@datalayer/core 0.0.12 → 0.0.14

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.
Files changed (249) hide show
  1. package/README.md +2 -2
  2. package/lib/api/DatalayerApi.d.ts +38 -26
  3. package/lib/api/DatalayerApi.js +52 -13
  4. package/lib/api/iam/authentication.d.ts +9 -8
  5. package/lib/api/iam/authentication.js +14 -15
  6. package/lib/api/iam/healthz.d.ts +3 -2
  7. package/lib/api/iam/healthz.js +5 -3
  8. package/lib/api/iam/index.d.ts +9 -4
  9. package/lib/api/iam/index.js +9 -4
  10. package/lib/api/iam/oauth2.d.ts +115 -0
  11. package/lib/api/iam/oauth2.js +309 -0
  12. package/lib/api/iam/profile.d.ts +8 -1
  13. package/lib/api/iam/profile.js +17 -2
  14. package/lib/api/iam/usage.d.ts +18 -0
  15. package/lib/api/iam/usage.js +39 -0
  16. package/lib/api/index.d.ts +6 -6
  17. package/lib/api/index.js +6 -7
  18. package/lib/api/runtimes/environments.d.ts +2 -2
  19. package/lib/api/runtimes/environments.js +3 -2
  20. package/lib/api/runtimes/healthz.d.ts +3 -13
  21. package/lib/api/runtimes/healthz.js +4 -3
  22. package/lib/api/runtimes/index.d.ts +3 -2
  23. package/lib/api/runtimes/index.js +3 -2
  24. package/lib/api/runtimes/runtimes.d.ts +4 -4
  25. package/lib/api/runtimes/runtimes.js +17 -6
  26. package/lib/api/runtimes/snapshots.d.ts +4 -4
  27. package/lib/api/runtimes/snapshots.js +3 -2
  28. package/lib/api/spacer/documents.d.ts +12 -0
  29. package/lib/api/spacer/documents.js +43 -0
  30. package/lib/api/spacer/healthz.d.ts +3 -13
  31. package/lib/api/spacer/healthz.js +4 -3
  32. package/lib/api/spacer/index.d.ts +4 -2
  33. package/lib/api/spacer/index.js +4 -2
  34. package/lib/api/spacer/items.d.ts +9 -1
  35. package/lib/api/spacer/items.js +17 -2
  36. package/lib/api/spacer/lexicals.d.ts +1 -1
  37. package/lib/api/spacer/lexicals.js +3 -2
  38. package/lib/api/spacer/notebooks.d.ts +1 -1
  39. package/lib/api/spacer/notebooks.js +3 -2
  40. package/lib/api/spacer/spaces.d.ts +1 -1
  41. package/lib/api/spacer/spaces.js +3 -2
  42. package/lib/api/spacer/users.d.ts +1 -1
  43. package/lib/api/spacer/users.js +3 -2
  44. package/lib/api/utils/validation.d.ts +24 -1
  45. package/lib/api/utils/validation.js +62 -1
  46. package/lib/client/base.d.ts +75 -0
  47. package/lib/client/base.js +199 -0
  48. package/lib/client/constants.d.ts +22 -0
  49. package/lib/client/constants.js +22 -0
  50. package/lib/client/index.d.ts +108 -0
  51. package/lib/client/index.js +79 -0
  52. package/lib/client/mixins/IAMMixin.d.ts +54 -0
  53. package/lib/client/mixins/IAMMixin.js +181 -0
  54. package/lib/client/mixins/RuntimesMixin.d.ts +93 -0
  55. package/lib/client/mixins/RuntimesMixin.js +229 -0
  56. package/lib/client/mixins/SpacerMixin.d.ts +111 -0
  57. package/lib/client/mixins/SpacerMixin.js +340 -0
  58. package/lib/client/utils/mixins.d.ts +12 -0
  59. package/lib/{sdk/client → client}/utils/mixins.js +0 -28
  60. package/lib/client/utils/spacerUtils.d.ts +18 -0
  61. package/lib/client/utils/spacerUtils.js +32 -0
  62. package/lib/collaboration/DatalayerCollaboration.d.ts +6 -1
  63. package/lib/collaboration/DatalayerCollaboration.js +2 -2
  64. package/lib/collaboration/DatalayerCollaborationProvider.d.ts +5 -0
  65. package/lib/collaboration/DatalayerCollaborationProvider.js +10 -9
  66. package/lib/components/progress/CreditsIndicator.d.ts +1 -1
  67. package/lib/components/runtimes/RuntimeCellVariablesDialog.js +1 -1
  68. package/lib/components/runtimes/RuntimeLauncherDialog.d.ts +1 -1
  69. package/lib/components/runtimes/RuntimeLauncherDialog.js +2 -2
  70. package/lib/components/runtimes/RuntimePickerBase.d.ts +1 -1
  71. package/lib/components/runtimes/RuntimePickerBase.js +1 -1
  72. package/lib/components/runtimes/RuntimePickerCell.js +3 -3
  73. package/lib/components/runtimes/RuntimePickerNotebook.d.ts +1 -1
  74. package/lib/components/runtimes/RuntimePickerNotebook.js +2 -2
  75. package/lib/components/runtimes/RuntimeTransfer.d.ts +2 -2
  76. package/lib/components/runtimes/RuntimeUtils.d.ts +1 -1
  77. package/lib/components/snapshots/RuntimeSnapshotMenu.d.ts +1 -1
  78. package/lib/components/snapshots/RuntimeSnapshotMenu.js +27 -20
  79. package/lib/config/Configuration.d.ts +8 -0
  80. package/lib/hooks/useDatalayer.js +1 -1
  81. package/lib/hooks/useRuntimes.js +1 -1
  82. package/lib/hooks/useToast.js +1 -1
  83. package/lib/index.d.ts +2 -3
  84. package/lib/index.js +4 -3
  85. package/lib/models/Common.d.ts +64 -0
  86. package/lib/models/CreditsDTO.d.ts +124 -0
  87. package/lib/models/CreditsDTO.js +135 -0
  88. package/lib/models/Environment.d.ts +1 -1
  89. package/lib/models/EnvironmentDTO.d.ts +125 -0
  90. package/lib/models/EnvironmentDTO.js +88 -0
  91. package/lib/models/HealthCheck.d.ts +72 -0
  92. package/lib/models/HealthCheck.js +107 -0
  93. package/lib/{api/types/iam.d.ts → models/IAM.d.ts} +15 -78
  94. package/lib/models/ItemDTO.d.ts +74 -0
  95. package/lib/models/ItemDTO.js +186 -0
  96. package/lib/models/LexicalDTO.d.ts +155 -0
  97. package/lib/models/LexicalDTO.js +157 -0
  98. package/lib/models/NotebookDTO.d.ts +96 -0
  99. package/lib/models/NotebookDTO.js +153 -0
  100. package/lib/models/Profile.d.ts +65 -0
  101. package/lib/models/RuntimeDTO.d.ts +191 -0
  102. package/lib/models/RuntimeDTO.js +204 -0
  103. package/lib/models/RuntimeSnapshotDTO.d.ts +173 -0
  104. package/lib/models/RuntimeSnapshotDTO.js +139 -0
  105. package/lib/models/SpaceDTO.d.ts +280 -0
  106. package/lib/models/SpaceDTO.js +239 -0
  107. package/lib/models/UserDTO.d.ts +86 -0
  108. package/lib/models/UserDTO.js +84 -0
  109. package/lib/models/index.d.ts +45 -4
  110. package/lib/models/index.js +45 -4
  111. package/lib/sdk/index.d.ts +5 -4
  112. package/lib/sdk/index.js +6 -5
  113. package/lib/services/DatalayerServiceManager.js +1 -1
  114. package/lib/state/substates/CoreState.js +2 -0
  115. package/lib/state/substates/RuntimesState.d.ts +1 -1
  116. package/lib/state/substates/RuntimesState.js +1 -1
  117. package/lib/{sdk/stateful → stateful}/index.d.ts +1 -1
  118. package/lib/{sdk/stateful → stateful}/index.js +1 -1
  119. package/lib/{sdk/stateful → stateful}/jupyter/exec/Snippets.d.ts +1 -41
  120. package/lib/{sdk/stateful → stateful}/jupyter/exec/Snippets.js +1 -20
  121. package/lib/{sdk/stateful → stateful}/runtimes/actions.d.ts +3 -3
  122. package/lib/{sdk/stateful → stateful}/runtimes/actions.js +8 -8
  123. package/lib/{sdk/stateful → stateful}/runtimes/apis.d.ts +8 -8
  124. package/package.json +13 -10
  125. package/lib/__tests__/hooks.test.d.ts +0 -1
  126. package/lib/__tests__/hooks.test.js +0 -19
  127. package/lib/__tests__/index.test.d.ts +0 -1
  128. package/lib/__tests__/index.test.js +0 -27
  129. package/lib/__tests__/integration.test.d.ts +0 -1
  130. package/lib/__tests__/integration.test.js +0 -57
  131. package/lib/__tests__/shared/cleanup-shared.d.ts +0 -4
  132. package/lib/__tests__/shared/cleanup-shared.js +0 -228
  133. package/lib/__tests__/shared/test-config.d.ts +0 -51
  134. package/lib/__tests__/shared/test-config.js +0 -110
  135. package/lib/__tests__/shared/test-constants.d.ts +0 -66
  136. package/lib/__tests__/shared/test-constants.js +0 -79
  137. package/lib/__tests__/utils.test.d.ts +0 -1
  138. package/lib/__tests__/utils.test.js +0 -59
  139. package/lib/api/__tests__/iam.authentication.integration.test.d.ts +0 -1
  140. package/lib/api/__tests__/iam.authentication.integration.test.js +0 -247
  141. package/lib/api/__tests__/iam.healthz.integration.test.d.ts +0 -1
  142. package/lib/api/__tests__/iam.healthz.integration.test.js +0 -63
  143. package/lib/api/__tests__/iam.profile.integration.test.d.ts +0 -1
  144. package/lib/api/__tests__/iam.profile.integration.test.js +0 -252
  145. package/lib/api/__tests__/runtimes.environments.integration.test.d.ts +0 -1
  146. package/lib/api/__tests__/runtimes.environments.integration.test.js +0 -122
  147. package/lib/api/__tests__/runtimes.healthz.integration.test.d.ts +0 -1
  148. package/lib/api/__tests__/runtimes.healthz.integration.test.js +0 -50
  149. package/lib/api/__tests__/runtimes.integration.test.d.ts +0 -1
  150. package/lib/api/__tests__/runtimes.integration.test.js +0 -369
  151. package/lib/api/__tests__/spacer.healthz.integration.test.d.ts +0 -1
  152. package/lib/api/__tests__/spacer.healthz.integration.test.js +0 -50
  153. package/lib/api/__tests__/spacer.integration.test.d.ts +0 -1
  154. package/lib/api/__tests__/spacer.integration.test.js +0 -519
  155. package/lib/api/iam/__tests__/authentication.unit.test.d.ts +0 -1
  156. package/lib/api/iam/__tests__/authentication.unit.test.js +0 -63
  157. package/lib/api/iam/__tests__/healthz.unit.test.d.ts +0 -1
  158. package/lib/api/iam/__tests__/healthz.unit.test.js +0 -60
  159. package/lib/api/iam/__tests__/profile.unit.test.d.ts +0 -1
  160. package/lib/api/iam/__tests__/profile.unit.test.js +0 -57
  161. package/lib/api/runtimes/__tests__/environments.unit.test.d.ts +0 -1
  162. package/lib/api/runtimes/__tests__/environments.unit.test.js +0 -77
  163. package/lib/api/runtimes/__tests__/healthz.unit.test.d.ts +0 -1
  164. package/lib/api/runtimes/__tests__/healthz.unit.test.js +0 -57
  165. package/lib/api/runtimes/__tests__/runtimes.unit.test.d.ts +0 -1
  166. package/lib/api/runtimes/__tests__/runtimes.unit.test.js +0 -139
  167. package/lib/api/runtimes/__tests__/snapshots.unit.test.d.ts +0 -1
  168. package/lib/api/runtimes/__tests__/snapshots.unit.test.js +0 -96
  169. package/lib/api/spacer/__tests__/healthz.unit.test.d.ts +0 -1
  170. package/lib/api/spacer/__tests__/healthz.unit.test.js +0 -57
  171. package/lib/api/spacer/__tests__/items.unit.test.d.ts +0 -1
  172. package/lib/api/spacer/__tests__/items.unit.test.js +0 -165
  173. package/lib/api/spacer/__tests__/lexicals.unit.test.d.ts +0 -1
  174. package/lib/api/spacer/__tests__/lexicals.unit.test.js +0 -323
  175. package/lib/api/spacer/__tests__/notebooks.unit.test.d.ts +0 -1
  176. package/lib/api/spacer/__tests__/notebooks.unit.test.js +0 -224
  177. package/lib/api/spacer/__tests__/users.unit.test.d.ts +0 -1
  178. package/lib/api/spacer/__tests__/users.unit.test.js +0 -132
  179. package/lib/api/types/index.d.ts +0 -32
  180. package/lib/api/types/index.js +0 -36
  181. package/lib/api/types/runtimes.d.ts +0 -235
  182. package/lib/api/types/spacer.d.ts +0 -271
  183. package/lib/api/types/spacer.js +0 -5
  184. package/lib/api/utils/__tests__/validation.test.d.ts +0 -1
  185. package/lib/api/utils/__tests__/validation.test.js +0 -109
  186. package/lib/sdk/client/__tests__/sdk.health.integration.test.d.ts +0 -1
  187. package/lib/sdk/client/__tests__/sdk.health.integration.test.js +0 -110
  188. package/lib/sdk/client/__tests__/sdk.iam.integration.test.d.ts +0 -1
  189. package/lib/sdk/client/__tests__/sdk.iam.integration.test.js +0 -179
  190. package/lib/sdk/client/__tests__/sdk.models.integration.test.d.ts +0 -1
  191. package/lib/sdk/client/__tests__/sdk.models.integration.test.js +0 -376
  192. package/lib/sdk/client/__tests__/sdk.runtimes.integration.test.d.ts +0 -1
  193. package/lib/sdk/client/__tests__/sdk.runtimes.integration.test.js +0 -276
  194. package/lib/sdk/client/__tests__/sdk.spacer.integration.test.d.ts +0 -1
  195. package/lib/sdk/client/__tests__/sdk.spacer.integration.test.js +0 -361
  196. package/lib/sdk/client/base.d.ts +0 -88
  197. package/lib/sdk/client/base.js +0 -112
  198. package/lib/sdk/client/index.d.ts +0 -192
  199. package/lib/sdk/client/index.js +0 -128
  200. package/lib/sdk/client/mixins/HealthMixin.d.ts +0 -100
  201. package/lib/sdk/client/mixins/HealthMixin.js +0 -133
  202. package/lib/sdk/client/mixins/IAMMixin.d.ts +0 -59
  203. package/lib/sdk/client/mixins/IAMMixin.js +0 -83
  204. package/lib/sdk/client/mixins/RuntimesMixin.d.ts +0 -134
  205. package/lib/sdk/client/mixins/RuntimesMixin.js +0 -221
  206. package/lib/sdk/client/mixins/SpacerMixin.d.ts +0 -184
  207. package/lib/sdk/client/mixins/SpacerMixin.js +0 -278
  208. package/lib/sdk/client/models/Lexical.d.ts +0 -156
  209. package/lib/sdk/client/models/Lexical.js +0 -275
  210. package/lib/sdk/client/models/Notebook.d.ts +0 -174
  211. package/lib/sdk/client/models/Notebook.js +0 -311
  212. package/lib/sdk/client/models/Runtime.d.ts +0 -221
  213. package/lib/sdk/client/models/Runtime.js +0 -341
  214. package/lib/sdk/client/models/Snapshot.d.ts +0 -156
  215. package/lib/sdk/client/models/Snapshot.js +0 -244
  216. package/lib/sdk/client/models/Space.d.ts +0 -182
  217. package/lib/sdk/client/models/Space.js +0 -276
  218. package/lib/sdk/client/models/__tests__/Lexical.test.d.ts +0 -1
  219. package/lib/sdk/client/models/__tests__/Lexical.test.js +0 -288
  220. package/lib/sdk/client/models/__tests__/Notebook.test.d.ts +0 -1
  221. package/lib/sdk/client/models/__tests__/Notebook.test.js +0 -206
  222. package/lib/sdk/client/models/__tests__/Runtime.test.d.ts +0 -1
  223. package/lib/sdk/client/models/__tests__/Runtime.test.js +0 -133
  224. package/lib/sdk/client/models/__tests__/Snapshot.test.d.ts +0 -1
  225. package/lib/sdk/client/models/__tests__/Snapshot.test.js +0 -244
  226. package/lib/sdk/client/models/__tests__/Space.test.d.ts +0 -1
  227. package/lib/sdk/client/models/__tests__/Space.test.js +0 -334
  228. package/lib/sdk/client/models/index.d.ts +0 -30
  229. package/lib/sdk/client/models/index.js +0 -30
  230. package/lib/sdk/client/utils/mixins.d.ts +0 -42
  231. /package/lib/{api/types/iam.js → models/Common.js} +0 -0
  232. /package/lib/{api/types/runtimes.js → models/IAM.js} +0 -0
  233. /package/lib/{sdk/stateful → stateful}/jupyter/exec/Python.d.ts +0 -0
  234. /package/lib/{sdk/stateful → stateful}/jupyter/exec/Python.js +0 -0
  235. /package/lib/{sdk/stateful → stateful}/jupyter/exec/index.d.ts +0 -0
  236. /package/lib/{sdk/stateful → stateful}/jupyter/exec/index.js +0 -0
  237. /package/lib/{sdk/stateful → stateful}/jupyter/index.d.ts +0 -0
  238. /package/lib/{sdk/stateful → stateful}/jupyter/index.js +0 -0
  239. /package/lib/{sdk/stateful → stateful}/jupyter/kernelsHandler.d.ts +0 -0
  240. /package/lib/{sdk/stateful → stateful}/jupyter/kernelsHandler.js +0 -0
  241. /package/lib/{sdk/stateful → stateful}/runtimes/apis.js +0 -0
  242. /package/lib/{sdk/stateful → stateful}/runtimes/index.d.ts +0 -0
  243. /package/lib/{sdk/stateful → stateful}/runtimes/index.js +0 -0
  244. /package/lib/{sdk/stateful → stateful}/runtimes/settings.d.ts +0 -0
  245. /package/lib/{sdk/stateful → stateful}/runtimes/settings.js +0 -0
  246. /package/lib/{sdk/stateful → stateful}/runtimes/snapshots.d.ts +0 -0
  247. /package/lib/{sdk/stateful → stateful}/runtimes/snapshots.js +0 -0
  248. /package/lib/{sdk/stateful → stateful}/runtimes/utils.d.ts +0 -0
  249. /package/lib/{sdk/stateful → stateful}/runtimes/utils.js +0 -0
@@ -0,0 +1,340 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * Spacer mixin for managing workspaces, notebooks, and content.
7
+ * @module client/mixins/SpacerMixin
8
+ */
9
+ import * as spaces from '../../api/spacer/spaces';
10
+ import * as notebooks from '../../api/spacer/notebooks';
11
+ import * as users from '../../api/spacer/users';
12
+ import * as lexicals from '../../api/spacer/lexicals';
13
+ import * as documents from '../../api/spacer/documents';
14
+ import * as items from '../../api/spacer/items';
15
+ import { NotebookDTO } from '../../models/NotebookDTO';
16
+ import { LexicalDTO } from '../../models/LexicalDTO';
17
+ import { SpaceDTO } from '../../models/SpaceDTO';
18
+ import { HealthCheck } from '../../models/HealthCheck';
19
+ import { convertSpaceItemsToModels } from '../utils/spacerUtils';
20
+ /** Spacer mixin providing workspace and content management. */
21
+ export function SpacerMixin(Base) {
22
+ return class extends Base {
23
+ // ========================================================================
24
+ // User
25
+ // ========================================================================
26
+ /**
27
+ * Get all workspaces for the authenticated user.
28
+ * @returns Array of Space instances
29
+ */
30
+ async getMySpaces() {
31
+ const token = this.getToken();
32
+ const spacerRunUrl = this.getSpacerRunUrl();
33
+ const response = await users.getMySpaces(token, spacerRunUrl);
34
+ return response.spaces.map(s => new SpaceDTO(s, this));
35
+ }
36
+ // ========================================================================
37
+ // Spaces
38
+ // ========================================================================
39
+ /**
40
+ * Create a new workspace.
41
+ * @param name - Space name
42
+ * @param description - Space description
43
+ * @param variant - Space variant type
44
+ * @param spaceHandle - Unique handle for the space
45
+ * @param organizationId - Organization ID
46
+ * @param seedSpaceId - Seed space ID for initialization
47
+ * @param isPublic - Whether the space is public
48
+ * @returns Created Space instance
49
+ */
50
+ async createSpace(name, description, variant, spaceHandle, organizationId, seedSpaceId, isPublic) {
51
+ const token = this.getToken();
52
+ const spacerRunUrl = this.getSpacerRunUrl();
53
+ const data = {
54
+ name,
55
+ description,
56
+ variant,
57
+ spaceHandle,
58
+ organizationId,
59
+ seedSpaceId,
60
+ public: isPublic,
61
+ };
62
+ const response = await spaces.createSpace(token, data, spacerRunUrl);
63
+ if (!response.space) {
64
+ throw new Error('Failed to create space: no space returned');
65
+ }
66
+ return new SpaceDTO(response.space, this);
67
+ }
68
+ // ========================================================================
69
+ // Notebooks
70
+ // ========================================================================
71
+ /**
72
+ * Create a new notebook.
73
+ * @param spaceId - ID of the space to create the notebook in
74
+ * @param name - Name of the notebook
75
+ * @param description - Description of the notebook
76
+ * @param file - Optional file for notebook content
77
+ * @returns Created Notebook instance
78
+ */
79
+ async createNotebook(spaceId, name, description, file) {
80
+ // Get the Space model instance
81
+ const spaces = await this.getMySpaces();
82
+ const spaceModel = spaces.find((s) => s.uid === spaceId);
83
+ if (!spaceModel) {
84
+ throw new Error(`Space with ID '${spaceId}' not found`);
85
+ }
86
+ // Use the Space model's createNotebook method
87
+ return await spaceModel.createNotebook({
88
+ name,
89
+ description,
90
+ file,
91
+ });
92
+ }
93
+ /**
94
+ * Get a notebook by ID.
95
+ * @param id - Notebook ID
96
+ * @returns Notebook instance
97
+ */
98
+ async getNotebook(id) {
99
+ const spacerRunUrl = this.getSpacerRunUrl();
100
+ const token = this.getToken();
101
+ const response = await notebooks.getNotebook(token, id, spacerRunUrl);
102
+ if (!response.notebook) {
103
+ throw new Error(`Notebook with ID '${id}' not found`);
104
+ }
105
+ return new NotebookDTO(response.notebook, this);
106
+ }
107
+ /**
108
+ * Update a notebook.
109
+ * @param id - Notebook ID
110
+ * @param name - Optional new name for the notebook
111
+ * @param description - Optional new description for the notebook
112
+ * @returns Updated Notebook instance
113
+ */
114
+ async updateNotebook(id, name, description) {
115
+ const spacerRunUrl = this.getSpacerRunUrl();
116
+ const token = this.getToken();
117
+ const data = {};
118
+ if (name !== undefined)
119
+ data.name = name;
120
+ if (description !== undefined)
121
+ data.description = description;
122
+ const response = await notebooks.updateNotebook(token, id, data, spacerRunUrl);
123
+ if (!response.notebook) {
124
+ throw new Error('Failed to update notebook: no notebook returned');
125
+ }
126
+ return new NotebookDTO(response.notebook, this);
127
+ }
128
+ // ========================================================================
129
+ // Lexicals
130
+ // ========================================================================
131
+ /**
132
+ * Create a new lexical document.
133
+ * @param spaceId - ID of the space to create the lexical document in
134
+ * @param name - Name of the lexical document
135
+ * @param description - Description of the lexical document
136
+ * @param file - Optional file for document content
137
+ * @returns Created Lexical instance
138
+ */
139
+ async createLexical(spaceId, name, description, file) {
140
+ // Get the Space model instance
141
+ const spaces = await this.getMySpaces();
142
+ const spaceModel = spaces.find((s) => s.uid === spaceId);
143
+ if (!spaceModel) {
144
+ throw new Error(`Space with ID '${spaceId}' not found`);
145
+ }
146
+ // Use the Space model's createLexical method
147
+ return await spaceModel.createLexical({
148
+ name,
149
+ description,
150
+ file,
151
+ });
152
+ }
153
+ /**
154
+ * Get a lexical document by ID.
155
+ * @param id - Document ID
156
+ * @returns Lexical instance
157
+ */
158
+ async getLexical(id) {
159
+ const spacerRunUrl = this.getSpacerRunUrl();
160
+ const token = this.getToken();
161
+ const response = await lexicals.getLexical(token, id, spacerRunUrl);
162
+ if (!response.document) {
163
+ throw new Error(`Lexical document with ID '${id}' not found`);
164
+ }
165
+ return new LexicalDTO(response.document, this);
166
+ }
167
+ /**
168
+ * Update a lexical document.
169
+ * @param id - Document ID
170
+ * @param name - Optional new name for the lexical document
171
+ * @param description - Optional new description for the lexical document
172
+ * @returns Updated Lexical instance
173
+ */
174
+ async updateLexical(id, name, description) {
175
+ const spacerRunUrl = this.getSpacerRunUrl();
176
+ const token = this.getToken();
177
+ const data = {};
178
+ if (name !== undefined)
179
+ data.name = name;
180
+ if (description !== undefined)
181
+ data.description = description;
182
+ const response = await lexicals.updateLexical(token, id, data, spacerRunUrl);
183
+ return new LexicalDTO(response.document, this);
184
+ }
185
+ // ========================================================================
186
+ // Items
187
+ // ========================================================================
188
+ /**
189
+ * Get the items of a space as model instances.
190
+ * @param spaceId - Space ID
191
+ * @returns Array of Notebook and Lexical model instances
192
+ */
193
+ async getSpaceItems(spaceId) {
194
+ const spacerRunUrl = this.getSpacerRunUrl();
195
+ const token = this.getToken();
196
+ const response = await items.getSpaceItems(token, spaceId, spacerRunUrl);
197
+ // Use shared utility function to convert items to model instances
198
+ return convertSpaceItemsToModels(response.items, this);
199
+ }
200
+ /**
201
+ * Get a single item from a space.
202
+ * @param itemId - Item ID to retrieve
203
+ * @returns Notebook or Lexical model instance
204
+ * @throws Error if item not found
205
+ */
206
+ async getSpaceItem(itemId) {
207
+ const spacerRunUrl = this.getSpacerRunUrl();
208
+ const token = this.getToken();
209
+ const response = await items.getItem(token, itemId, spacerRunUrl);
210
+ if (!response.success || !response.item) {
211
+ throw new Error(`Space item '${itemId}' not found`);
212
+ }
213
+ // Determine item type and create appropriate model
214
+ const item = response.item;
215
+ if (item.type_s === 'notebook' || item.notebook_name_s !== undefined) {
216
+ return new NotebookDTO(item, this);
217
+ }
218
+ else if (item.type_s === 'lexical' ||
219
+ item.document_name_s !== undefined) {
220
+ return new LexicalDTO(item, this);
221
+ }
222
+ else {
223
+ throw new Error(`Unknown item type for item '${itemId}'`);
224
+ }
225
+ }
226
+ /**
227
+ * Delete an item from a space.
228
+ * @param itemId - Item ID to delete
229
+ * @throws Error if deletion fails
230
+ */
231
+ async deleteSpaceItem(itemId) {
232
+ const spacerRunUrl = this.getSpacerRunUrl();
233
+ const token = this.getToken();
234
+ // First, check if the item exists
235
+ try {
236
+ const getResponse = await items.getItem(token, itemId, spacerRunUrl);
237
+ if (!getResponse.success || !getResponse.item) {
238
+ throw new Error(`Space item '${itemId}' not found`);
239
+ }
240
+ }
241
+ catch (error) {
242
+ // If getItem throws (e.g., 404), wrap in descriptive error
243
+ if (error.message?.includes('404') ||
244
+ error.message?.includes('not found')) {
245
+ throw new Error(`Failed to delete space item '${itemId}': Item not found`);
246
+ }
247
+ throw new Error(`Failed to delete space item '${itemId}': ${error.message}`);
248
+ }
249
+ // Item exists, proceed with deletion
250
+ const response = await items.deleteItem(token, itemId, spacerRunUrl);
251
+ if (!response.success) {
252
+ throw new Error(`Failed to delete space item '${itemId}': ${response.message}`);
253
+ }
254
+ // Success - return void
255
+ }
256
+ // ========================================================================
257
+ // Content Loading with CDN Support
258
+ // ========================================================================
259
+ async getContent(itemId) {
260
+ const spacerRunUrl = this.getSpacerRunUrl();
261
+ const token = this.getToken();
262
+ // First, get the item to check for CDN URL
263
+ const response = await items.getItem(token, itemId, spacerRunUrl);
264
+ if (!response.success || !response.item) {
265
+ throw new Error(`Space item '${itemId}' not found`);
266
+ }
267
+ const item = response.item;
268
+ const cdnUrl = item.cdn_url_s;
269
+ if (cdnUrl) {
270
+ // Load content from CDN
271
+ const cdnResponse = await fetch(cdnUrl);
272
+ if (!cdnResponse.ok) {
273
+ throw new Error(`Failed to load content from CDN: ${cdnResponse.statusText}`);
274
+ }
275
+ return await cdnResponse.json();
276
+ }
277
+ // No CDN URL, return content from item
278
+ return item.content;
279
+ }
280
+ // ========================================================================
281
+ // Service Health Checks
282
+ // ========================================================================
283
+ /**
284
+ * Check the health status of the Spacer service.
285
+ * Performs a lightweight check to verify service accessibility.
286
+ *
287
+ * @returns Health check result with status and response time
288
+ */
289
+ async checkSpacerHealth() {
290
+ const startTime = Date.now();
291
+ const errors = [];
292
+ let status = 'unknown';
293
+ let healthy = false;
294
+ try {
295
+ // Test basic connectivity by getting user spaces (lightweight operation)
296
+ const spaces = await this.getMySpaces();
297
+ const responseTime = Date.now() - startTime;
298
+ if (Array.isArray(spaces)) {
299
+ healthy = true;
300
+ status = 'operational';
301
+ }
302
+ else {
303
+ status = 'degraded';
304
+ errors.push('Unexpected response format from spaces endpoint');
305
+ }
306
+ return new HealthCheck({
307
+ healthy,
308
+ status,
309
+ responseTime,
310
+ errors,
311
+ timestamp: new Date(),
312
+ }, this);
313
+ }
314
+ catch (error) {
315
+ const responseTime = Date.now() - startTime;
316
+ status = 'down';
317
+ errors.push(`Service unreachable: ${error}`);
318
+ return new HealthCheck({
319
+ healthy: false,
320
+ status,
321
+ responseTime,
322
+ errors,
323
+ timestamp: new Date(),
324
+ }, this);
325
+ }
326
+ }
327
+ /**
328
+ * Get collaboration session ID for a document
329
+ */
330
+ async getCollaborationSessionId(documentId) {
331
+ const token = this.getToken();
332
+ const spacerRunUrl = this.getSpacerRunUrl();
333
+ const response = await documents.getCollaborationSessionId(token, documentId, spacerRunUrl);
334
+ if (!response.success || !response.sessionId) {
335
+ throw new Error(`Failed to get collaboration session ID for document '${documentId}': ${response.error || 'Unknown error'}`);
336
+ }
337
+ return response.sessionId;
338
+ }
339
+ };
340
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * TypeScript mixin utilities for composing the DatalayerClient class.
3
+ * @module client/utils/mixins
4
+ */
5
+ /** Type for a constructor function that can be used in mixins. */
6
+ export type Constructor<T = {}> = new (...args: any[]) => T;
7
+ /**
8
+ * Apply mixins to a base class.
9
+ * @param derivedCtor - The base class to extend
10
+ * @param constructors - Array of mixin classes to apply
11
+ */
12
+ export declare function applyMixins(derivedCtor: any, constructors: any[]): void;
@@ -4,36 +4,8 @@
4
4
  */
5
5
  /**
6
6
  * Apply mixins to a base class.
7
- *
8
- * This utility function enables multiple inheritance-like behavior in TypeScript
9
- * by copying properties and methods from mixin classes to the target class.
10
- *
11
7
  * @param derivedCtor - The base class to extend
12
8
  * @param constructors - Array of mixin classes to apply
13
- *
14
- * @example
15
- * ```typescript
16
- * class Base {
17
- * baseMethod() { return 'base'; }
18
- * }
19
- *
20
- * class MixinA {
21
- * mixinAMethod() { return 'A'; }
22
- * }
23
- *
24
- * class MixinB {
25
- * mixinBMethod() { return 'B'; }
26
- * }
27
- *
28
- * interface Combined extends Base, MixinA, MixinB {}
29
- * class Combined extends Base {}
30
- * applyMixins(Combined, [MixinA, MixinB]);
31
- *
32
- * const instance = new Combined();
33
- * instance.baseMethod(); // 'base'
34
- * instance.mixinAMethod(); // 'A'
35
- * instance.mixinBMethod(); // 'B'
36
- * ```
37
9
  */
38
10
  export function applyMixins(derivedCtor, constructors) {
39
11
  constructors.forEach(baseCtor => {
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Utility functions for Spacer-related operations to avoid code duplication.
3
+ * @module client/utils/spacerUtils
4
+ */
5
+ import type { GetSpaceItemsResponse } from '../../models/SpaceDTO';
6
+ import type { DatalayerClient } from '../index';
7
+ import { NotebookDTO } from '../../models/NotebookDTO';
8
+ import { LexicalDTO } from '../../models/LexicalDTO';
9
+ /**
10
+ * Convert raw space items from API response to model instances.
11
+ * This utility function is shared between Space.getItems() and SpacerMixin.getSpaceItems()
12
+ * to avoid code duplication.
13
+ *
14
+ * @param response - Raw API response containing space items
15
+ * @param sdk - SDK instance to pass to model constructors
16
+ * @returns Array of Notebook and Lexical model instances
17
+ */
18
+ export declare function convertSpaceItemsToModels(items: GetSpaceItemsResponse['items'], sdk: DatalayerClient): (NotebookDTO | LexicalDTO)[];
@@ -0,0 +1,32 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ import { NotebookDTO } from '../../models/NotebookDTO';
6
+ import { LexicalDTO } from '../../models/LexicalDTO';
7
+ import { ItemTypes } from '../constants';
8
+ /**
9
+ * Convert raw space items from API response to model instances.
10
+ * This utility function is shared between Space.getItems() and SpacerMixin.getSpaceItems()
11
+ * to avoid code duplication.
12
+ *
13
+ * @param response - Raw API response containing space items
14
+ * @param sdk - SDK instance to pass to model constructors
15
+ * @returns Array of Notebook and Lexical model instances
16
+ */
17
+ export function convertSpaceItemsToModels(items, sdk) {
18
+ const modelItems = [];
19
+ for (const item of items) {
20
+ // Check various possible type fields
21
+ const itemType = item.type_s;
22
+ // Only include notebooks and lexicals
23
+ if (itemType === ItemTypes.NOTEBOOK) {
24
+ modelItems.push(new NotebookDTO(item, sdk));
25
+ }
26
+ else if (itemType === ItemTypes.LEXICAL) {
27
+ modelItems.push(new LexicalDTO(item, sdk));
28
+ }
29
+ // Skip everything else (exercises, cells, etc.)
30
+ }
31
+ return modelItems;
32
+ }
@@ -1,9 +1,14 @@
1
1
  type IFetchSessionId = {
2
2
  url: string;
3
3
  token?: string;
4
+ /**
5
+ * Custom fetch function to use instead of global fetch.
6
+ * Useful for proxying requests in environments with CORS restrictions (e.g., VS Code webviews).
7
+ */
8
+ fetchFn?: typeof fetch;
4
9
  };
5
10
  /**
6
11
  * Fetch the session ID of a collaborative documents from Datalayer.
7
12
  */
8
- export declare function requestDatalayerCollaborationSessionId({ url, token, }: IFetchSessionId): Promise<string>;
13
+ export declare function requestDatalayerCollaborationSessionId({ url, token, fetchFn, }: IFetchSessionId): Promise<string>;
9
14
  export {};
@@ -5,14 +5,14 @@
5
5
  /**
6
6
  * Fetch the session ID of a collaborative documents from Datalayer.
7
7
  */
8
- export async function requestDatalayerCollaborationSessionId({ url, token, }) {
8
+ export async function requestDatalayerCollaborationSessionId({ url, token, fetchFn = fetch, }) {
9
9
  const headers = {
10
10
  Accept: 'application/json',
11
11
  };
12
12
  if (token) {
13
13
  headers['Authorization'] = `Bearer ${token}`;
14
14
  }
15
- const response = await fetch(url, {
15
+ const response = await fetchFn(url, {
16
16
  method: 'GET',
17
17
  headers,
18
18
  credentials: token ? 'include' : 'omit',
@@ -19,6 +19,11 @@ export interface IDatalayerCollaborationConfig {
19
19
  * Authentication token (optional, uses config from store if not provided)
20
20
  */
21
21
  token?: string;
22
+ /**
23
+ * Custom fetch function to use for HTTP requests.
24
+ * Useful for proxying requests in environments with CORS restrictions (e.g., VS Code webviews).
25
+ */
26
+ fetchFn?: typeof fetch;
22
27
  }
23
28
  /**
24
29
  * Datalayer collaboration provider
@@ -14,7 +14,6 @@ var CollaborationStatus;
14
14
  CollaborationStatus["Error"] = "error";
15
15
  })(CollaborationStatus || (CollaborationStatus = {}));
16
16
  import { requestDatalayerCollaborationSessionId } from './DatalayerCollaboration';
17
- import { coreStore } from '../state/substates/CoreState';
18
17
  /**
19
18
  * Datalayer collaboration provider
20
19
  *
@@ -64,24 +63,26 @@ export class DatalayerCollaborationProvider {
64
63
  }
65
64
  this.setStatus(CollaborationStatus.Connecting);
66
65
  try {
67
- // Get configuration from store or use provided config
68
- const { configuration } = coreStore.getState();
69
- const runUrl = this._config.runUrl ?? configuration?.runUrl;
70
- const token = this._config.token ?? configuration?.token;
66
+ // Use ONLY explicitly provided configuration
67
+ // NO fallback to coreStore - if config is wrong, we want to fail fast
68
+ // This is critical for VS Code extension where config must come from settings
69
+ const runUrl = this._config.runUrl;
70
+ const token = this._config.token;
71
71
  if (!runUrl) {
72
- throw new Error('Datalayer runUrl is not configured');
72
+ throw new Error('Datalayer runUrl is not configured - must be explicitly provided in DatalayerCollaborationProvider config');
73
73
  }
74
74
  if (!token) {
75
- throw new Error('Datalayer token is not configured');
75
+ throw new Error('Datalayer token is not configured - must be explicitly provided in DatalayerCollaborationProvider config');
76
76
  }
77
77
  const { ydoc, awareness } = sharedModel;
78
- // Build WebSocket URL
78
+ // Build URLs.
79
79
  const documentURL = URLExt.join(runUrl, '/api/spacer/v1/documents');
80
- const wsUrl = documentURL.replace(/^http/, 'ws');
80
+ const wsUrl = URLExt.join(runUrl, '/api/spacer/v1/documents/ws').replace(/^http/, 'ws');
81
81
  // Request collaboration session from Datalayer
82
82
  const sessionId = await requestDatalayerCollaborationSessionId({
83
83
  url: URLExt.join(documentURL, documentId),
84
84
  token,
85
+ fetchFn: this._config.fetchFn,
85
86
  });
86
87
  // Create WebSocket provider
87
88
  this._provider = new WebsocketProvider(wsUrl, documentId, ydoc, {
@@ -1,4 +1,4 @@
1
- import type { IRemoteServicesManager } from '../../sdk/stateful/runtimes';
1
+ import type { IRemoteServicesManager } from '../../stateful/runtimes';
2
2
  type ICreditsIndicatorProps = {
3
3
  /**
4
4
  * Kernel service manager
@@ -8,7 +8,7 @@ import { Dialog } from '@primer/react/experimental';
8
8
  import { nullTranslator } from '@jupyterlab/translation';
9
9
  import { JSONExt } from '@lumino/coreutils';
10
10
  import { KernelExecutor } from '@datalayer/jupyter-react';
11
- import { RuntimeSnippetsFacade } from '../../sdk/stateful/jupyter';
11
+ import { RuntimeSnippetsFacade } from '../../stateful/jupyter';
12
12
  import { RuntimeCellVariables } from './RuntimeCellVariables';
13
13
  /**
14
14
  * Dialog to define the runtime cell variables to transfer
@@ -1,5 +1,5 @@
1
1
  import type { IMarkdownParser, IRenderMime } from '@jupyterlab/rendermime';
2
- import type { IRemoteServicesManager } from '../../sdk/stateful/runtimes';
2
+ import type { IRemoteServicesManager } from '../../stateful/runtimes';
3
3
  import type { IRuntimeSnapshot, IRuntimeDesc } from '../../models';
4
4
  /**
5
5
  * {@link RuntimeLauncherDialog} properties.
@@ -50,7 +50,7 @@ export function RuntimeLauncherDialog(props) {
50
50
  const jupyterLabAdapter = jupyterReactStore.jupyterLabAdapter;
51
51
  const [selection, setSelection] = useState((kernelSnapshot?.environment || environments[0]?.name) ?? '');
52
52
  const [timeLimit, setTimeLimit] = useState(Math.min(credits?.available ?? 0, 10));
53
- const [runtimeName, setRuntimeName] = useState(environments[0]?.kernel?.givenNameTemplate || environments[0]?.title || '');
53
+ const [runtimeName, setRuntimeName] = useState(environments[0]?.runtime?.givenNameTemplate || environments[0]?.title || '');
54
54
  // Whether the runtim name has been changed by the user or not
55
55
  const [hasCustomRuntimeName, setHasCustomRuntimeName] = useState(false);
56
56
  const [userStorage, setUserStorage] = useState(false);
@@ -75,7 +75,7 @@ export function RuntimeLauncherDialog(props) {
75
75
  setSelection(selection);
76
76
  if (!hasCustomRuntimeName) {
77
77
  const spec = environments.find(env => env.name === selection);
78
- setRuntimeName(spec?.kernel?.givenNameTemplate || spec?.title || '');
78
+ setRuntimeName(spec?.runtime?.givenNameTemplate || spec?.title || '');
79
79
  }
80
80
  }, [setSelection, hasCustomRuntimeName]);
81
81
  const handleSubmitRuntime = useCallback(async () => {
@@ -2,7 +2,7 @@ import { ReactElement, ReactNode } from 'react';
2
2
  import { ISessionContext } from '@jupyterlab/apputils';
3
3
  import { ITranslator } from '@jupyterlab/translation';
4
4
  import { IRuntimeDesc } from '../../models';
5
- import { IMultiServiceManager } from '../../sdk/stateful/runtimes';
5
+ import { IMultiServiceManager } from '../../stateful/runtimes';
6
6
  type IDisplayMode = 'menu' | 'radio';
7
7
  /**
8
8
  * {@link RuntimePickerBase} properties
@@ -12,7 +12,7 @@ import { Box } from '@datalayer/primer-addons';
12
12
  import { CpuIcon } from '@primer/octicons-react';
13
13
  import { BrowserIcon, LaptopSimpleIcon } from '@datalayer/icons-react';
14
14
  import { CreditsIndicator } from '../../components/progress';
15
- import { isRuntimeRemote, } from '../../sdk/stateful/runtimes';
15
+ import { isRuntimeRemote } from '../../stateful/runtimes';
16
16
  import { getGroupedRuntimeDescs } from './RuntimeUtils';
17
17
  /**
18
18
  * Maximal runtime display name length after which it is trimmed.
@@ -8,8 +8,8 @@ import { nullTranslator } from '@jupyterlab/translation';
8
8
  import { ActionList } from '@primer/react';
9
9
  import { CloudUploadIcon } from '@datalayer/icons-react';
10
10
  import { useCoreStore, useIAMStore } from '../../state';
11
- import { isRuntimeRemote } from '../../sdk/stateful/runtimes';
12
- import { RuntimeSnippetsFacade } from '../../sdk/stateful/jupyter';
11
+ import { isRuntimeRemote } from '../../stateful/runtimes';
12
+ import { RuntimeSnippetsFacade } from '../../stateful/jupyter';
13
13
  import { ExternalTokenSilentLogin } from '../../components/iam';
14
14
  import { SnippetDialog } from './../snippets/SnippetDialog';
15
15
  import { RuntimeLauncherDialog } from './RuntimeLauncherDialog';
@@ -61,7 +61,7 @@ export function RuntimePickerCell(props) {
61
61
  }, [preference]);
62
62
  const setSelectedRuntimeDesc = useCallback((kernel) => {
63
63
  const datalayerMeta = model.getMetadata('datalayer') ?? {
64
- kernel: undefined,
64
+ runtime: undefined,
65
65
  };
66
66
  if (!kernel) {
67
67
  delete datalayerMeta.kernel;
@@ -1,6 +1,6 @@
1
1
  import { ITranslator } from '@jupyterlab/translation';
2
2
  import { CommandRegistry } from '@lumino/commands';
3
- import type { IMultiServiceManager, IDatalayerSessionContext } from '../../sdk/stateful/runtimes';
3
+ import type { IMultiServiceManager, IDatalayerSessionContext } from '../../stateful/runtimes';
4
4
  import { RuntimeTransfer } from './RuntimeTransfer';
5
5
  /**
6
6
  * {@link RuntimePickerNotebook} properties
@@ -9,7 +9,7 @@ import { Box } from '@datalayer/primer-addons';
9
9
  import { AlertIcon } from '@primer/octicons-react';
10
10
  import { JSONExt } from '@lumino/coreutils';
11
11
  import { KernelExecutor } from '@datalayer/jupyter-react';
12
- import { RuntimeSnippetsFacade } from '../../sdk/stateful/jupyter';
12
+ import { RuntimeSnippetsFacade } from '../../stateful/jupyter';
13
13
  import { ExternalTokenSilentLogin } from '../../components/iam';
14
14
  import { useCoreStore, useIAMStore } from '../../state';
15
15
  import { RuntimeReservationControl, MAXIMAL_RUNTIME_TIME_RESERVATION_MINUTES, } from './RuntimeReservationControl';
@@ -120,7 +120,7 @@ export function RuntimePickerNotebook(props) {
120
120
  : undefined;
121
121
  setValue(creditsLimit !== 0
122
122
  ? {
123
- kernel: selectedRuntimeDesc
123
+ runtime: selectedRuntimeDesc
124
124
  ? {
125
125
  environmentName: ['browser', 'remote'].includes(selectedRuntimeDesc.location)
126
126
  ? `${selectedRuntimeDesc.location}-${selectedRuntimeDesc.name}`
@@ -1,9 +1,9 @@
1
- import { type IRuntimeOptions } from '../../sdk/stateful/runtimes';
1
+ import { type IRuntimeOptions } from '../../stateful/runtimes';
2
2
  export interface RuntimeTransfer {
3
3
  /**
4
4
  * Selected Kernel.
5
5
  */
6
- kernel: Partial<Omit<IRuntimeOptions, 'kernelType'> & {
6
+ runtime: Partial<Omit<IRuntimeOptions, 'kernelType'> & {
7
7
  id: string;
8
8
  }> | null;
9
9
  /**