@gitpod/gitpod-protocol 0.1.5-tar-telemetry-settings-data.3 → 0.1.5-tar-sh-active-users.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (344) hide show
  1. package/data/gitpod-schema.json +97 -5
  2. package/lib/accounting-protocol.d.ts +18 -10
  3. package/lib/accounting-protocol.d.ts.map +1 -1
  4. package/lib/accounting-protocol.js +34 -32
  5. package/lib/accounting-protocol.js.map +1 -1
  6. package/lib/admin-protocol.d.ts +9 -2
  7. package/lib/admin-protocol.d.ts.map +1 -1
  8. package/lib/admin-protocol.js.map +1 -1
  9. package/lib/analytics.d.ts +4 -5
  10. package/lib/analytics.d.ts.map +1 -1
  11. package/lib/analytics.js.map +1 -1
  12. package/lib/attribution.d.ts +20 -0
  13. package/lib/attribution.d.ts.map +1 -0
  14. package/lib/attribution.js +40 -0
  15. package/lib/attribution.js.map +1 -0
  16. package/lib/auth.d.ts.map +1 -1
  17. package/lib/billing-mode.d.ts +40 -0
  18. package/lib/billing-mode.d.ts.map +1 -0
  19. package/lib/billing-mode.js +36 -0
  20. package/lib/billing-mode.js.map +1 -0
  21. package/lib/blocked-repositories-protocol.d.ts +13 -0
  22. package/lib/blocked-repositories-protocol.d.ts.map +1 -0
  23. package/lib/blocked-repositories-protocol.js +8 -0
  24. package/lib/blocked-repositories-protocol.js.map +1 -0
  25. package/lib/context-url.d.ts.map +1 -1
  26. package/lib/context-url.js +4 -4
  27. package/lib/context-url.js.map +1 -1
  28. package/lib/context-url.spec.d.ts.map +1 -1
  29. package/lib/context-url.spec.js +20 -5
  30. package/lib/context-url.spec.js.map +1 -1
  31. package/lib/email-protocol.d.ts +1 -1
  32. package/lib/email-protocol.d.ts.map +1 -1
  33. package/lib/email-protocol.js.map +1 -1
  34. package/lib/encryption/container-module.d.ts.map +1 -1
  35. package/lib/encryption/container-module.js +1 -1
  36. package/lib/encryption/container-module.js.map +1 -1
  37. package/lib/encryption/encryption-engine.d.ts.map +1 -1
  38. package/lib/encryption/encryption-engine.js +7 -7
  39. package/lib/encryption/encryption-engine.js.map +1 -1
  40. package/lib/encryption/encryption-engine.spec.d.ts.map +1 -1
  41. package/lib/encryption/encryption-engine.spec.js +2 -3
  42. package/lib/encryption/encryption-engine.spec.js.map +1 -1
  43. package/lib/encryption/encryption-service.d.ts.map +1 -1
  44. package/lib/encryption/encryption-service.js +1 -1
  45. package/lib/encryption/encryption-service.js.map +1 -1
  46. package/lib/encryption/key-provider.d.ts.map +1 -1
  47. package/lib/encryption/key-provider.js +7 -9
  48. package/lib/encryption/key-provider.js.map +1 -1
  49. package/lib/env.d.ts +0 -5
  50. package/lib/env.d.ts.map +1 -1
  51. package/lib/env.js +1 -20
  52. package/lib/env.js.map +1 -1
  53. package/lib/experiments/always-default.d.ts +8 -0
  54. package/lib/experiments/always-default.d.ts.map +1 -0
  55. package/lib/experiments/always-default.js +20 -0
  56. package/lib/experiments/always-default.js.map +1 -0
  57. package/lib/experiments/configcat-server.d.ts +10 -0
  58. package/lib/experiments/configcat-server.d.ts.map +1 -0
  59. package/lib/experiments/configcat-server.js +36 -0
  60. package/lib/experiments/configcat-server.js.map +1 -0
  61. package/lib/experiments/configcat.d.ts +22 -0
  62. package/lib/experiments/configcat.d.ts.map +1 -0
  63. package/lib/experiments/configcat.js +53 -0
  64. package/lib/experiments/configcat.js.map +1 -0
  65. package/lib/experiments/types.d.ts +23 -0
  66. package/lib/experiments/types.d.ts.map +1 -0
  67. package/lib/experiments/types.js +10 -0
  68. package/lib/experiments/types.js.map +1 -0
  69. package/lib/gitpod-file-parser.d.ts.map +1 -1
  70. package/lib/gitpod-file-parser.js +6 -6
  71. package/lib/gitpod-file-parser.js.map +1 -1
  72. package/lib/gitpod-file-parser.spec.js +42 -39
  73. package/lib/gitpod-file-parser.spec.js.map +1 -1
  74. package/lib/gitpod-service.d.ts +56 -26
  75. package/lib/gitpod-service.d.ts.map +1 -1
  76. package/lib/gitpod-service.js +40 -33
  77. package/lib/gitpod-service.js.map +1 -1
  78. package/lib/headless-workspace-log.d.ts +1 -0
  79. package/lib/headless-workspace-log.d.ts.map +1 -1
  80. package/lib/headless-workspace-log.js +2 -1
  81. package/lib/headless-workspace-log.js.map +1 -1
  82. package/lib/ide-frontend-service.d.ts +1 -1
  83. package/lib/ide-protocol.d.ts +14 -6
  84. package/lib/ide-protocol.d.ts.map +1 -1
  85. package/lib/index.d.ts +17 -16
  86. package/lib/index.d.ts.map +1 -1
  87. package/lib/index.js +1 -0
  88. package/lib/index.js.map +1 -1
  89. package/lib/installation-admin-protocol.d.ts +4 -0
  90. package/lib/installation-admin-protocol.d.ts.map +1 -1
  91. package/lib/installation-admin-protocol.js +3 -2
  92. package/lib/installation-admin-protocol.js.map +1 -1
  93. package/lib/license-protocol.d.ts +7 -0
  94. package/lib/license-protocol.d.ts.map +1 -1
  95. package/lib/license-protocol.js.map +1 -1
  96. package/lib/messaging/browser/connection.d.ts +1 -1
  97. package/lib/messaging/browser/connection.d.ts.map +1 -1
  98. package/lib/messaging/browser/connection.js +19 -19
  99. package/lib/messaging/browser/connection.js.map +1 -1
  100. package/lib/messaging/browser/window-connection.d.ts +4 -4
  101. package/lib/messaging/browser/window-connection.d.ts.map +1 -1
  102. package/lib/messaging/browser/window-connection.js +9 -6
  103. package/lib/messaging/browser/window-connection.js.map +1 -1
  104. package/lib/messaging/client-call-metrics.d.ts +2 -18
  105. package/lib/messaging/client-call-metrics.d.ts.map +1 -1
  106. package/lib/messaging/client-call-metrics.js +21 -22
  107. package/lib/messaging/client-call-metrics.js.map +1 -1
  108. package/lib/messaging/error.d.ts +6 -1
  109. package/lib/messaging/error.d.ts.map +1 -1
  110. package/lib/messaging/error.js +13 -3
  111. package/lib/messaging/error.js.map +1 -1
  112. package/lib/messaging/handler.d.ts.map +1 -1
  113. package/lib/messaging/handler.js +1 -1
  114. package/lib/messaging/node/connection.js +8 -8
  115. package/lib/messaging/node/connection.js.map +1 -1
  116. package/lib/messaging/proxy-factory.d.ts +1 -1
  117. package/lib/messaging/proxy-factory.d.ts.map +1 -1
  118. package/lib/messaging/proxy-factory.js +7 -9
  119. package/lib/messaging/proxy-factory.js.map +1 -1
  120. package/lib/payment-protocol.d.ts.map +1 -1
  121. package/lib/payment-protocol.js +1 -1
  122. package/lib/payment-protocol.js.map +1 -1
  123. package/lib/permission.d.ts +2 -2
  124. package/lib/permission.d.ts.map +1 -1
  125. package/lib/permission.js +12 -23
  126. package/lib/permission.js.map +1 -1
  127. package/lib/plans.d.ts +4 -3
  128. package/lib/plans.d.ts.map +1 -1
  129. package/lib/plans.js +210 -171
  130. package/lib/plans.js.map +1 -1
  131. package/lib/protocol.d.ts +146 -39
  132. package/lib/protocol.d.ts.map +1 -1
  133. package/lib/protocol.js +267 -88
  134. package/lib/protocol.js.map +1 -1
  135. package/{src/theia-plugins.ts → lib/protocol.spec.d.ts} +2 -6
  136. package/lib/protocol.spec.d.ts.map +1 -0
  137. package/lib/protocol.spec.js +127 -0
  138. package/lib/protocol.spec.js.map +1 -0
  139. package/lib/snapshot-url.spec.js.map +1 -1
  140. package/lib/team-subscription-protocol.d.ts +22 -3
  141. package/lib/team-subscription-protocol.d.ts.map +1 -1
  142. package/lib/team-subscription-protocol.js +20 -5
  143. package/lib/team-subscription-protocol.js.map +1 -1
  144. package/lib/teams-projects-protocol.d.ts +21 -3
  145. package/lib/teams-projects-protocol.d.ts.map +1 -1
  146. package/lib/teams-projects-protocol.js +1 -1
  147. package/lib/teams-projects-protocol.js.map +1 -1
  148. package/lib/typings/globals.d.ts +2 -2
  149. package/lib/typings/globals.d.ts.map +1 -1
  150. package/lib/usage.d.ts +43 -0
  151. package/lib/usage.d.ts.map +1 -0
  152. package/lib/{theia-plugins.js → usage.js} +2 -2
  153. package/lib/usage.js.map +1 -0
  154. package/lib/util/analytics.d.ts.map +1 -1
  155. package/lib/util/analytics.js +12 -3
  156. package/lib/util/analytics.js.map +1 -1
  157. package/lib/util/async-iterator.d.ts.map +1 -1
  158. package/lib/util/async-iterator.js +3 -3
  159. package/lib/util/async-iterator.js.map +1 -1
  160. package/lib/util/cancelable.js.map +1 -1
  161. package/lib/util/date-time.js +6 -6
  162. package/lib/util/date-time.js.map +1 -1
  163. package/lib/util/debug-app.d.ts +25 -0
  164. package/lib/util/debug-app.d.ts.map +1 -0
  165. package/lib/util/debug-app.js +100 -0
  166. package/lib/util/debug-app.js.map +1 -0
  167. package/lib/util/deferred.js.map +1 -1
  168. package/lib/util/disposable.d.ts.map +1 -1
  169. package/lib/util/disposable.js +2 -2
  170. package/lib/util/disposable.js.map +1 -1
  171. package/lib/util/event.d.ts.map +1 -1
  172. package/lib/util/event.js +5 -3
  173. package/lib/util/event.js.map +1 -1
  174. package/lib/util/garbage-collected-cache.d.ts.map +1 -1
  175. package/lib/util/garbage-collected-cache.js +6 -1
  176. package/lib/util/garbage-collected-cache.js.map +1 -1
  177. package/lib/util/generate-workspace-id.d.ts +5 -0
  178. package/lib/util/generate-workspace-id.d.ts.map +1 -1
  179. package/lib/util/generate-workspace-id.js +446 -442
  180. package/lib/util/generate-workspace-id.js.map +1 -1
  181. package/lib/util/generate-workspace-id.spec.js +18 -7
  182. package/lib/util/generate-workspace-id.spec.js.map +1 -1
  183. package/lib/util/gitpod-cookie.d.ts +1 -1
  184. package/lib/util/gitpod-cookie.d.ts.map +1 -1
  185. package/lib/util/gitpod-cookie.js +0 -3
  186. package/lib/util/gitpod-cookie.js.map +1 -1
  187. package/lib/util/gitpod-host-url.d.ts +3 -0
  188. package/lib/util/gitpod-host-url.d.ts.map +1 -1
  189. package/lib/util/gitpod-host-url.js +49 -29
  190. package/lib/util/gitpod-host-url.js.map +1 -1
  191. package/lib/util/gitpod-host-url.spec.d.ts.map +1 -1
  192. package/lib/util/gitpod-host-url.spec.js +15 -5
  193. package/lib/util/gitpod-host-url.spec.js.map +1 -1
  194. package/lib/util/grpc.d.ts +19 -0
  195. package/lib/util/grpc.d.ts.map +1 -1
  196. package/lib/util/grpc.js +73 -1
  197. package/lib/util/grpc.js.map +1 -1
  198. package/lib/util/jaeger-client-types.d.ts.map +1 -1
  199. package/lib/util/logging.d.ts +1 -1
  200. package/lib/util/logging.d.ts.map +1 -1
  201. package/lib/util/logging.js +31 -25
  202. package/lib/util/logging.js.map +1 -1
  203. package/lib/util/logging.spec.d.ts +7 -0
  204. package/lib/util/logging.spec.d.ts.map +1 -0
  205. package/lib/util/logging.spec.js +52 -0
  206. package/lib/util/logging.spec.js.map +1 -0
  207. package/lib/util/make-link.js +5 -5
  208. package/lib/util/make-link.js.map +1 -1
  209. package/lib/util/parse-workspace-id.d.ts.map +1 -1
  210. package/lib/util/parse-workspace-id.js +1 -2
  211. package/lib/util/parse-workspace-id.js.map +1 -1
  212. package/lib/util/parse-workspace-id.spec.d.ts.map +1 -1
  213. package/lib/util/parse-workspace-id.spec.js.map +1 -1
  214. package/lib/util/queue.spec.js +9 -6
  215. package/lib/util/queue.spec.js.map +1 -1
  216. package/lib/util/semaphore.d.ts.map +1 -1
  217. package/lib/util/semaphore.js.map +1 -1
  218. package/lib/util/skip-if.d.ts.map +1 -1
  219. package/lib/util/skip-if.js.map +1 -1
  220. package/lib/util/timeutil.d.ts +2 -0
  221. package/lib/util/timeutil.d.ts.map +1 -1
  222. package/lib/util/timeutil.js +15 -3
  223. package/lib/util/timeutil.js.map +1 -1
  224. package/lib/util/timeutil.spec.d.ts +1 -0
  225. package/lib/util/timeutil.spec.d.ts.map +1 -1
  226. package/lib/util/timeutil.spec.js +10 -0
  227. package/lib/util/timeutil.spec.js.map +1 -1
  228. package/lib/util/tracing.d.ts +6 -6
  229. package/lib/util/tracing.d.ts.map +1 -1
  230. package/lib/util/tracing.js +14 -16
  231. package/lib/util/tracing.js.map +1 -1
  232. package/lib/util/tracing.spec.js +3 -3
  233. package/lib/util/tracing.spec.js.map +1 -1
  234. package/lib/util/workspace-port-authentication.d.ts +7 -7
  235. package/lib/util/workspace-port-authentication.d.ts.map +1 -1
  236. package/lib/util/workspace-port-authentication.js +8 -11
  237. package/lib/util/workspace-port-authentication.js.map +1 -1
  238. package/lib/webhook-event.d.ts +44 -0
  239. package/lib/webhook-event.d.ts.map +1 -0
  240. package/lib/webhook-event.js +8 -0
  241. package/lib/webhook-event.js.map +1 -0
  242. package/lib/workspace-class.d.ts +14 -0
  243. package/lib/workspace-class.d.ts.map +1 -0
  244. package/lib/workspace-class.js +8 -0
  245. package/lib/workspace-class.js.map +1 -0
  246. package/lib/workspace-cluster.d.ts +6 -8
  247. package/lib/workspace-cluster.d.ts.map +1 -1
  248. package/lib/workspace-cluster.js +2 -4
  249. package/lib/workspace-cluster.js.map +1 -1
  250. package/lib/workspace-instance.d.ts +20 -3
  251. package/lib/workspace-instance.d.ts.map +1 -1
  252. package/lib/wsready.d.ts +4 -4
  253. package/lib/wsready.d.ts.map +1 -1
  254. package/lib/wsready.js +1 -3
  255. package/lib/wsready.js.map +1 -1
  256. package/package.json +13 -7
  257. package/pkg-yarn.lock +9 -6
  258. package/provenance-bundle.jsonl +1 -1
  259. package/src/accounting-protocol.ts +66 -51
  260. package/src/admin-protocol.ts +33 -21
  261. package/src/analytics.ts +26 -28
  262. package/src/attribution.ts +48 -0
  263. package/src/auth.ts +2 -2
  264. package/src/billing-mode.ts +67 -0
  265. package/src/blocked-repositories-protocol.ts +13 -0
  266. package/src/context-url.spec.ts +25 -11
  267. package/src/context-url.ts +80 -78
  268. package/src/email-protocol.ts +5 -6
  269. package/src/encryption/container-module.ts +2 -3
  270. package/src/encryption/encryption-engine.spec.ts +9 -8
  271. package/src/encryption/encryption-engine.ts +14 -14
  272. package/src/encryption/encryption-service.ts +4 -5
  273. package/src/encryption/key-provider.ts +16 -19
  274. package/src/env.ts +0 -22
  275. package/src/experiments/always-default.ts +24 -0
  276. package/src/experiments/configcat-server.ts +41 -0
  277. package/src/experiments/configcat.ts +58 -0
  278. package/src/experiments/types.ts +35 -0
  279. package/src/gitpod-file-parser.spec.ts +55 -61
  280. package/src/gitpod-file-parser.ts +16 -17
  281. package/src/gitpod-service.ts +188 -111
  282. package/src/headless-workspace-log.ts +6 -4
  283. package/src/ide-frontend-service.ts +2 -2
  284. package/src/ide-protocol.ts +18 -8
  285. package/src/index.ts +17 -16
  286. package/src/installation-admin-protocol.ts +12 -8
  287. package/src/license-protocol.ts +12 -6
  288. package/src/messaging/browser/connection.ts +45 -47
  289. package/src/messaging/browser/window-connection.ts +39 -29
  290. package/src/messaging/client-call-metrics.ts +62 -82
  291. package/src/messaging/error.ts +20 -7
  292. package/src/messaging/handler.ts +6 -6
  293. package/src/messaging/node/connection.ts +8 -8
  294. package/src/messaging/proxy-factory.ts +23 -30
  295. package/src/oss-allowlist.ts +3 -3
  296. package/src/payment-protocol.ts +2 -2
  297. package/src/permission.ts +20 -31
  298. package/src/plans.ts +240 -189
  299. package/src/protocol.spec.ts +97 -0
  300. package/src/protocol.ts +509 -242
  301. package/src/snapshot-url.spec.ts +9 -7
  302. package/src/team-subscription-protocol.ts +59 -22
  303. package/src/teams-projects-protocol.ts +28 -8
  304. package/src/typings/globals.ts +4 -4
  305. package/src/usage.ts +63 -0
  306. package/src/util/analytics.ts +46 -24
  307. package/src/util/async-iterator.ts +4 -5
  308. package/src/util/cancelable.ts +3 -3
  309. package/src/util/date-time.ts +8 -8
  310. package/src/util/debug-app.ts +81 -0
  311. package/src/util/deferred.ts +6 -6
  312. package/src/util/disposable.ts +3 -6
  313. package/src/util/event.ts +9 -11
  314. package/src/util/garbage-collected-cache.ts +8 -6
  315. package/src/util/generate-workspace-id.spec.ts +26 -16
  316. package/src/util/generate-workspace-id.ts +460 -454
  317. package/src/util/gitpod-cookie.ts +8 -9
  318. package/src/util/gitpod-host-url.spec.ts +40 -13
  319. package/src/util/gitpod-host-url.ts +57 -33
  320. package/src/util/grpc.ts +90 -1
  321. package/src/util/jaeger-client-types.ts +2 -2
  322. package/src/util/logging.spec.ts +23 -0
  323. package/src/util/logging.ts +60 -42
  324. package/src/util/make-link.ts +6 -7
  325. package/src/util/parse-workspace-id.spec.ts +17 -8
  326. package/src/util/parse-workspace-id.ts +5 -6
  327. package/src/util/queue.spec.ts +27 -25
  328. package/src/util/repeat.ts +1 -1
  329. package/src/util/semaphore.ts +4 -6
  330. package/src/util/skip-if.ts +9 -6
  331. package/src/util/timeutil.spec.ts +19 -14
  332. package/src/util/timeutil.ts +27 -11
  333. package/src/util/tracing.spec.ts +28 -23
  334. package/src/util/tracing.ts +54 -51
  335. package/src/util/workspace-port-authentication.ts +10 -13
  336. package/src/webhook-event.ts +55 -0
  337. package/src/workspace-class.ts +14 -0
  338. package/src/workspace-cluster.ts +14 -13
  339. package/src/workspace-instance.ts +60 -24
  340. package/src/wsready.ts +6 -5
  341. package/data/builtin-theia-plugins.json +0 -372
  342. package/lib/theia-plugins.d.ts +0 -11
  343. package/lib/theia-plugins.d.ts.map +0 -1
  344. package/lib/theia-plugins.js.map +0 -1
package/src/protocol.ts CHANGED
@@ -7,26 +7,27 @@
7
7
  import { WorkspaceInstance, PortVisibility } from "./workspace-instance";
8
8
  import { RoleOrPermission } from "./permission";
9
9
  import { Project } from "./teams-projects-protocol";
10
+ import { createHash } from "crypto";
10
11
 
11
12
  export interface UserInfo {
12
- name?: string
13
+ name?: string;
13
14
  }
14
15
 
15
16
  export interface User {
16
17
  /** The user id */
17
- id: string
18
+ id: string;
18
19
 
19
20
  /** The timestamp when the user entry was created */
20
- creationDate: string
21
+ creationDate: string;
21
22
 
22
- avatarUrl?: string
23
+ avatarUrl?: string;
23
24
 
24
- name?: string
25
+ name?: string;
25
26
 
26
27
  /** Optional for backwards compatibility */
27
- fullName?: string
28
+ fullName?: string;
28
29
 
29
- identities: Identity[]
30
+ identities: Identity[];
30
31
 
31
32
  /**
32
33
  * Whether the user has been blocked to use our service, because of TOS violation for example.
@@ -44,38 +45,54 @@ export interface User {
44
45
  markedDeleted?: boolean;
45
46
 
46
47
  additionalData?: AdditionalUserData;
48
+
49
+ // Identifies an explicit team or user ID to which all the user's workspace usage should be attributed to (e.g. for billing purposes)
50
+ usageAttributionId?: string;
51
+
52
+ // The last time this user got verified somehow. The user is not verified if this is empty.
53
+ lastVerificationTime?: string;
54
+
55
+ // The phone number used for the last phone verification.
56
+ verificationPhoneNumber?: string;
47
57
  }
48
58
 
49
59
  export namespace User {
50
60
  export function is(data: any): data is User {
51
- return data
52
- && data.hasOwnProperty('id')
53
- && data.hasOwnProperty('identities')
61
+ return data && data.hasOwnProperty("id") && data.hasOwnProperty("identities");
54
62
  }
55
63
  export function getIdentity(user: User, authProviderId: string): Identity | undefined {
56
- return user.identities.find(id => id.authProviderId === authProviderId);
64
+ return user.identities.find((id) => id.authProviderId === authProviderId);
57
65
  }
58
66
  export function censor(user: User): User {
59
67
  const res = { ...user };
60
- delete (res.additionalData);
61
- res.identities = res.identities.map(i => {
62
- delete (i.tokens);
68
+ delete res.additionalData;
69
+ res.identities = res.identities.map((i) => {
70
+ delete i.tokens;
63
71
 
64
72
  // The user field is not in the Identity shape, but actually exists on DBIdentity.
65
73
  // Trying to push this object out via JSON RPC will fail because of the cyclic nature
66
74
  // of this field.
67
- delete ((i as any).user);
75
+ delete (i as any).user;
68
76
  return i;
69
77
  });
70
78
  return res;
71
79
  }
72
- export function getPrimaryEmail(user: User): string {
73
- const identities = user.identities.filter(i => !!i.primaryEmail);
80
+
81
+ /**
82
+ * Returns the stored email or if it doesn't exist returns the primaryEmail of the first identity this user signed up with.
83
+ * @param user
84
+ * @returns A primaryEmail, or undefined if there is none.
85
+ */
86
+ export function getPrimaryEmail(user: User): string | undefined {
87
+ if (user.additionalData?.profile?.emailAddress) {
88
+ return user.additionalData?.profile?.emailAddress;
89
+ }
90
+ const identities = user.identities.filter((i) => !!i.primaryEmail);
74
91
  if (identities.length <= 0) {
75
- throw new Error(`No identity with primary email for user: ${user.id}!`);
92
+ return undefined;
76
93
  }
77
94
 
78
- return identities[0].primaryEmail!;
95
+ return identities[0].primaryEmail || undefined;
79
96
  }
80
97
  export function getName(user: User): string | undefined {
81
98
  const name = user.fullName || user.name;
@@ -90,6 +107,91 @@ export namespace User {
90
107
  }
91
108
  return undefined;
92
109
  }
110
+
111
+ export function hasPreferredIde(user: User) {
112
+ return (
113
+ typeof user?.additionalData?.ideSettings?.defaultIde !== "undefined" ||
114
+ typeof user?.additionalData?.ideSettings?.useLatestVersion !== "undefined"
115
+ );
116
+ }
117
+
118
+ export function isOnboardingUser(user: User) {
119
+ return !hasPreferredIde(user);
120
+ }
121
+
122
+ export function migrationIDESettings(user: User) {
123
+ if (
124
+ !user?.additionalData?.ideSettings ||
125
+ Object.keys(user.additionalData.ideSettings).length === 0 ||
126
+ user.additionalData.ideSettings.settingVersion === "2.0"
127
+ ) {
128
+ return;
129
+ }
130
+ const newIDESettings: IDESettings = {
131
+ settingVersion: "2.0",
132
+ };
133
+ const ideSettings = user.additionalData.ideSettings;
134
+ if (ideSettings.useDesktopIde) {
135
+ if (ideSettings.defaultDesktopIde === "code-desktop") {
136
+ newIDESettings.defaultIde = "code-desktop";
137
+ } else if (ideSettings.defaultDesktopIde === "code-desktop-insiders") {
138
+ newIDESettings.defaultIde = "code-desktop";
139
+ newIDESettings.useLatestVersion = true;
140
+ } else {
141
+ newIDESettings.defaultIde = ideSettings.defaultDesktopIde;
142
+ newIDESettings.useLatestVersion = ideSettings.useLatestVersion;
143
+ }
144
+ } else {
145
+ const useLatest = ideSettings.defaultIde === "code-latest";
146
+ newIDESettings.defaultIde = "code";
147
+ newIDESettings.useLatestVersion = useLatest;
148
+ }
149
+ user.additionalData.ideSettings = newIDESettings;
150
+ }
151
+
152
+ export function getProfile(user: User): Profile {
153
+ return {
154
+ name: User.getName(user!) || "",
155
+ email: User.getPrimaryEmail(user!) || "",
156
+ company: user?.additionalData?.profile?.companyName,
157
+ avatarURL: user?.avatarUrl,
158
+ };
159
+ }
160
+
161
+ export function setProfile(user: User, profile: Profile): User {
162
+ user.fullName = profile.name;
163
+ user.avatarUrl = profile.avatarURL;
164
+
165
+ if (!user.additionalData) {
166
+ user.additionalData = {};
167
+ }
168
+ if (!user.additionalData.profile) {
169
+ user.additionalData.profile = {};
170
+ }
171
+ user.additionalData.profile.emailAddress = profile.email;
172
+ user.additionalData.profile.companyName = profile.company;
173
+ user.additionalData.profile.lastUpdatedDetailsNudge = new Date().toISOString();
174
+
175
+ return user;
176
+ }
177
+
178
+ // The actual Profile of a User
179
+ export interface Profile {
180
+ name: string;
181
+ email: string;
182
+ company?: string;
183
+ avatarURL?: string;
184
+ }
185
+ export namespace Profile {
186
+ export function hasChanges(before: Profile, after: Profile) {
187
+ return (
188
+ before.name !== after.name ||
189
+ before.email !== after.email ||
190
+ before.company !== after.company ||
191
+ before.avatarURL !== after.avatarURL
192
+ );
193
+ }
194
+ }
93
195
  }
94
196
 
95
197
  export interface AdditionalUserData {
@@ -98,15 +200,42 @@ export interface AdditionalUserData {
98
200
  featurePreview?: boolean;
99
201
  ideSettings?: IDESettings;
100
202
  // key is the name of the news, string the iso date when it was seen
101
- whatsNewSeen?: { [key: string]: string }
203
+ whatsNewSeen?: { [key: string]: string };
102
204
  // key is the name of the OAuth client i.e. local app, string the iso date when it was approved
103
205
  // TODO(rl): provide a management UX to allow rescinding of approval
104
- oauthClientsApproved?: { [key: string]: string }
206
+ oauthClientsApproved?: { [key: string]: string };
105
207
  // to remember GH Orgs the user installed/updated the GH App for
106
208
  knownGitHubOrgs?: string[];
107
-
108
209
  // Git clone URL pointing to the user's dotfile repo
109
210
  dotfileRepo?: string;
211
+ // preferred workspace classes
212
+ workspaceClasses?: WorkspaceClasses;
213
+ // additional user profile data
214
+ profile?: ProfileDetails;
215
+ }
216
+ export namespace AdditionalUserData {
217
+ export function set(user: User, partialData: Partial<AdditionalUserData>): User {
218
+ if (!user.additionalData) {
219
+ user.additionalData = {
220
+ ...partialData,
221
+ };
222
+ } else {
223
+ user.additionalData = {
224
+ ...user.additionalData,
225
+ ...partialData,
226
+ };
227
+ }
228
+ return user;
229
+ }
230
+ }
231
+ // The format in which we store User Profiles in
232
+ export interface ProfileDetails {
233
+ // when was the last time the user updated their profile information or has been nudged to do so.
234
+ lastUpdatedDetailsNudge?: string;
235
+ // the user's company name
236
+ companyName?: string;
237
+ // the user's email
238
+ emailAddress?: string;
110
239
  }
111
240
 
112
241
  export interface EmailNotificationSettings {
@@ -116,10 +245,18 @@ export interface EmailNotificationSettings {
116
245
  }
117
246
 
118
247
  export type IDESettings = {
119
- defaultIde?: string
120
- useDesktopIde?: boolean
121
- defaultDesktopIde?: string
122
- useLatestVersion?: boolean
248
+ settingVersion?: string;
249
+ defaultIde?: string;
250
+ // DEPRECATED: Use defaultIde after `settingVersion: 2.0`, no more specialify desktop or browser.
251
+ useDesktopIde?: boolean;
252
+ // DEPRECATED: Same with useDesktopIde.
253
+ defaultDesktopIde?: string;
254
+ useLatestVersion?: boolean;
255
+ };
256
+
257
+ export interface WorkspaceClasses {
258
+ regular: string;
259
+ prebuild: string;
123
260
  }
124
261
 
125
262
  export interface UserPlatform {
@@ -152,8 +289,13 @@ export interface UserFeatureSettings {
152
289
  * The values of this type MUST MATCH enum values in WorkspaceFeatureFlag from ws-manager/client/core_pb.d.ts
153
290
  * If they don't we'll break things during workspace startup.
154
291
  */
155
- export const WorkspaceFeatureFlags = { "full_workspace_backup": undefined, "fixed_resources": undefined };
156
- export type NamedWorkspaceFeatureFlag = keyof (typeof WorkspaceFeatureFlags);
292
+ export const WorkspaceFeatureFlags = {
293
+ full_workspace_backup: undefined,
294
+ persistent_volume_claim: undefined,
295
+ protected_secrets: undefined,
296
+ workspace_class_limiting: undefined,
297
+ };
298
+ export type NamedWorkspaceFeatureFlag = keyof typeof WorkspaceFeatureFlags;
157
299
 
158
300
  export interface EnvVarWithValue {
159
301
  name: string;
@@ -166,7 +308,7 @@ export interface ProjectEnvVarWithValue extends EnvVarWithValue {
166
308
  censored: boolean;
167
309
  }
168
310
 
169
- export type ProjectEnvVar = Omit<ProjectEnvVarWithValue, 'value'>;
311
+ export type ProjectEnvVar = Omit<ProjectEnvVarWithValue, "value">;
170
312
 
171
313
  export interface UserEnvVarValue extends EnvVarWithValue {
172
314
  id?: string;
@@ -179,6 +321,44 @@ export interface UserEnvVar extends UserEnvVarValue {
179
321
  }
180
322
 
181
323
  export namespace UserEnvVar {
324
+ /**
325
+ * @param variable
326
+ * @returns Either a string containing an error message or undefined.
327
+ */
328
+ export function validate(variable: UserEnvVarValue): string | undefined {
329
+ const name = variable.name;
330
+ const pattern = variable.repositoryPattern;
331
+ if (name.trim() === "") {
332
+ return "Name must not be empty.";
333
+ }
334
+ if (name.length > 255) {
335
+ return "Name too long. Maximum name length is 255 characters.";
336
+ }
337
+ if (!/^[a-zA-Z_]+[a-zA-Z0-9_]*$/.test(name)) {
338
+ return "Name must match /^[a-zA-Z_]+[a-zA-Z0-9_]*$/.";
339
+ }
340
+ if (variable.value.trim() === "") {
341
+ return "Value must not be empty.";
342
+ }
343
+ if (variable.value.length > 32767) {
344
+ return "Value too long. Maximum value length is 32767 characters.";
345
+ }
346
+ if (pattern.trim() === "") {
347
+ return "Scope must not be empty.";
348
+ }
349
+ const split = pattern.split("/");
350
+ if (split.length < 2) {
351
+ return "A scope must use the form 'organization/repo'.";
352
+ }
353
+ for (const name of split) {
354
+ if (name !== "*") {
355
+ if (!/^[a-zA-Z0-9_\-.\*]+$/.test(name)) {
356
+ return "Invalid scope segment. Only ASCII characters, numbers, -, _, . or * are allowed.";
357
+ }
358
+ }
359
+ }
360
+ return undefined;
361
+ }
182
362
 
183
363
  // DEPRECATED: Use ProjectEnvVar instead of repositoryPattern - https://github.com/gitpod-com/gitpod/issues/5322
184
364
  export function normalizeRepoPattern(pattern: string) {
@@ -199,7 +379,7 @@ export namespace UserEnvVar {
199
379
  if (repoPattern == "*") {
200
380
  score += 1;
201
381
  }
202
- if (ownerPattern == '*') {
382
+ if (ownerPattern == "*") {
203
383
  score += 2;
204
384
  }
205
385
  if (ownerPattern == "#" || repoPattern == "#") {
@@ -210,20 +390,20 @@ export namespace UserEnvVar {
210
390
 
211
391
  // DEPRECATED: Use ProjectEnvVar instead of repositoryPattern - https://github.com/gitpod-com/gitpod/issues/5322
212
392
  export function filter<T extends UserEnvVarValue>(vars: T[], owner: string, repo: string): T[] {
213
- let result = vars.filter(e => {
393
+ let result = vars.filter((e) => {
214
394
  const [ownerPattern, repoPattern] = splitRepositoryPattern(e.repositoryPattern);
215
- if (ownerPattern !== '*' && ownerPattern !== '#' && (!!owner && ownerPattern !== owner.toLocaleLowerCase())) {
395
+ if (ownerPattern !== "*" && ownerPattern !== "#" && !!owner && ownerPattern !== owner.toLocaleLowerCase()) {
216
396
  return false;
217
397
  }
218
- if (repoPattern !== '*' && repoPattern !== '#' && (!!repo && repoPattern !== repo.toLocaleLowerCase())) {
398
+ if (repoPattern !== "*" && repoPattern !== "#" && !!repo && repoPattern !== repo.toLocaleLowerCase()) {
219
399
  return false;
220
400
  }
221
401
  return true;
222
402
  });
223
403
 
224
404
  const resmap = new Map<string, T[]>();
225
- result.forEach(e => {
226
- const l = (resmap.get(e.name) || []);
405
+ result.forEach((e) => {
406
+ const l = resmap.get(e.name) || [];
227
407
  l.push(e);
228
408
  resmap.set(e.name, l);
229
409
  });
@@ -258,46 +438,107 @@ export namespace UserEnvVar {
258
438
 
259
439
  // DEPRECATED: Use ProjectEnvVar instead of repositoryPattern - https://github.com/gitpod-com/gitpod/issues/5322
260
440
  export function splitRepositoryPattern(repositoryPattern: string): string[] {
261
- const patterns = repositoryPattern.split('/');
262
- const repoPattern = patterns.slice(1).join('/')
441
+ const patterns = repositoryPattern.split("/");
442
+ const repoPattern = patterns.slice(1).join("/");
263
443
  const ownerPattern = patterns[0];
264
444
  return [ownerPattern, repoPattern];
265
445
  }
266
446
  }
267
447
 
268
- export interface GitpodToken {
448
+ export interface SSHPublicKeyValue {
449
+ name: string;
450
+ key: string;
451
+ }
452
+ export interface UserSSHPublicKey extends SSHPublicKeyValue {
453
+ id: string;
454
+ key: string;
455
+ userId: string;
456
+ fingerprint: string;
457
+ creationTime: string;
458
+ lastUsedTime?: string;
459
+ }
460
+
461
+ export type UserSSHPublicKeyValue = Omit<UserSSHPublicKey, "key" | "userId">;
462
+
463
+ export namespace SSHPublicKeyValue {
464
+ export function validate(value: SSHPublicKeyValue): string | undefined {
465
+ if (value.name.length === 0) {
466
+ return "Title must not be empty.";
467
+ }
468
+ if (value.name.length > 255) {
469
+ return "Title too long. Maximum value length is 255 characters.";
470
+ }
471
+ if (value.key.length === 0) {
472
+ return "Key must not be empty.";
473
+ }
474
+ try {
475
+ getData(value);
476
+ } catch (e) {
477
+ return "Key is invalid. You must supply a key in OpenSSH public key format.";
478
+ }
479
+ return;
480
+ }
269
481
 
482
+ export function getData(value: SSHPublicKeyValue) {
483
+ // Begins with 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521', 'ssh-ed25519', 'sk-ecdsa-sha2-nistp256@openssh.com', or 'sk-ssh-ed25519@openssh.com'.
484
+ const regex =
485
+ /^(?<type>ssh-rsa|ecdsa-sha2-nistp256|ecdsa-sha2-nistp384|ecdsa-sha2-nistp521|ssh-ed25519|sk-ecdsa-sha2-nistp256@openssh\.com|sk-ssh-ed25519@openssh\.com) (?<key>.*?)( (?<email>.*?))?$/;
486
+ const resultGroup = regex.exec(value.key.trim());
487
+ if (!resultGroup) {
488
+ throw new Error("Key is invalid.");
489
+ }
490
+ return {
491
+ type: resultGroup.groups?.["type"] as string,
492
+ key: resultGroup.groups?.["key"] as string,
493
+ email: resultGroup.groups?.["email"] || undefined,
494
+ };
495
+ }
496
+
497
+ export function getFingerprint(value: SSHPublicKeyValue) {
498
+ const data = getData(value);
499
+ let buf = Buffer.from(data.key, "base64");
500
+ // gitlab style
501
+ // const hash = createHash("md5").update(buf).digest("hex");
502
+ // github style
503
+ const hash = createHash("sha256").update(buf).digest("base64");
504
+ return hash;
505
+ }
506
+
507
+ export const MAXIMUM_KEY_LENGTH = 5;
508
+ }
509
+
510
+ export interface GitpodToken {
270
511
  /** Hash value (SHA256) of the token (primary key). */
271
- tokenHash: string
512
+ tokenHash: string;
272
513
 
273
514
  /** Human readable name of the token */
274
- name?: string
515
+ name?: string;
275
516
 
276
517
  /** Token kind */
277
- type: GitpodTokenType
518
+ type: GitpodTokenType;
278
519
 
279
520
  /** The user the token belongs to. */
280
- user: User
521
+ user: User;
281
522
 
282
523
  /** Scopes (e.g. limition to read-only) */
283
- scopes: string[]
524
+ scopes: string[];
284
525
 
285
526
  /** Created timestamp */
286
- created: string
527
+ created: string;
287
528
 
288
529
  // token is deleted on the database and about to be collected by db-sync
289
- deleted?: boolean
530
+ deleted?: boolean;
290
531
  }
291
532
 
292
533
  export enum GitpodTokenType {
293
534
  API_AUTH_TOKEN = 0,
294
- MACHINE_AUTH_TOKEN = 1
535
+ MACHINE_AUTH_TOKEN = 1,
295
536
  }
296
537
 
297
538
  export interface OneTimeSecret {
298
- id: string
539
+ id: string;
299
540
 
300
- value: string
541
+ value: string;
301
542
 
302
543
  expirationTime: string;
303
544
 
@@ -329,13 +570,12 @@ export type IdentityLookup = Pick<Identity, "authProviderId" | "authId">;
329
570
 
330
571
  export namespace Identity {
331
572
  export function is(data: any): data is Identity {
332
- return data.hasOwnProperty('authProviderId')
333
- && data.hasOwnProperty('authId')
334
- && data.hasOwnProperty('authName')
573
+ return (
574
+ data.hasOwnProperty("authProviderId") && data.hasOwnProperty("authId") && data.hasOwnProperty("authName")
575
+ );
335
576
  }
336
577
  export function equals(id1: IdentityLookup, id2: IdentityLookup) {
337
- return id1.authProviderId === id2.authProviderId
338
- && id1.authId === id2.authId
578
+ return id1.authProviderId === id2.authProviderId && id1.authId === id2.authId;
339
579
  }
340
580
  }
341
581
 
@@ -399,7 +639,14 @@ export interface Snapshot {
399
639
  message?: string;
400
640
  }
401
641
 
402
- export type SnapshotState = 'pending' | 'available' | 'error';
642
+ export interface VolumeSnapshot {
643
+ id: string;
644
+ workspaceId: string;
645
+ creationTime: string;
646
+ volumeHandle: string;
647
+ }
648
+
649
+ export type SnapshotState = "pending" | "available" | "error";
403
650
 
404
651
  export interface LayoutData {
405
652
  workspaceId: string;
@@ -428,13 +675,13 @@ export interface Workspace {
428
675
  * The resolved, fix name of the workspace image. We only use this
429
676
  * to access the logs during an image build.
430
677
  */
431
- imageNameResolved?: string
678
+ imageNameResolved?: string;
432
679
 
433
680
  /**
434
681
  * The resolved/built fixed named of the base image. This field is only set if the workspace
435
682
  * already has its base image built.
436
683
  */
437
- baseImageNameResolved?: string
684
+ baseImageNameResolved?: string;
438
685
 
439
686
  shareable?: boolean;
440
687
  pinned?: boolean;
@@ -468,20 +715,19 @@ export interface Workspace {
468
715
 
469
716
  export type WorkspaceSoftDeletion = "user" | "gc";
470
717
 
471
- export type WorkspaceType = "regular" | "prebuild" | "probe";
718
+ export type WorkspaceType = "regular" | "prebuild" | "probe"; // TODO(gpl) Removed prove here
472
719
 
473
720
  export namespace Workspace {
474
-
475
721
  export function getFullRepositoryName(ws: Workspace): string | undefined {
476
722
  if (CommitContext.is(ws.context)) {
477
- return ws.context.repository.owner + '/' + ws.context.repository.name
723
+ return ws.context.repository.owner + "/" + ws.context.repository.name;
478
724
  }
479
725
  return undefined;
480
726
  }
481
727
 
482
728
  export function getFullRepositoryUrl(ws: Workspace): string | undefined {
483
729
  if (CommitContext.is(ws.context)) {
484
- return `https://${ws.context.repository.host}/${getFullRepositoryName(ws)}`
730
+ return `https://${ws.context.repository.host}/${getFullRepositoryName(ws)}`;
485
731
  }
486
732
  return undefined;
487
733
  }
@@ -515,59 +761,50 @@ export namespace Workspace {
515
761
  }
516
762
  }
517
763
 
518
- export interface PreparePluginUploadParams {
519
- fullPluginName: string;
520
- }
521
-
522
- export interface ResolvePluginsParams {
523
- config?: WorkspaceConfig
524
- builtins?: ResolvedPlugins
525
- vsxRegistryUrl?: string
526
- }
527
-
528
- export interface InstallPluginsParams {
529
- pluginIds: string[]
530
- }
531
-
532
- export interface UninstallPluginParams {
533
- pluginId: string;
534
- }
535
-
536
764
  export interface GuessGitTokenScopesParams {
537
- host: string
538
- repoUrl: string
539
- gitCommand: string
540
- currentToken: GitToken
765
+ host: string;
766
+ repoUrl: string;
767
+ gitCommand: string;
768
+ currentToken: GitToken;
541
769
  }
542
770
 
543
771
  export interface GitToken {
544
- token: string
545
- user: string
546
- scopes: string[]
772
+ token: string;
773
+ user: string;
774
+ scopes: string[];
547
775
  }
548
776
 
549
777
  export interface GuessedGitTokenScopes {
550
- message?: string
551
- scopes?: string[]
778
+ message?: string;
779
+ scopes?: string[];
552
780
  }
553
781
 
554
- export type ResolvedPluginKind = 'user' | 'workspace' | 'builtin';
555
-
556
- export interface ResolvedPlugins {
557
- [pluginId: string]: ResolvedPlugin | undefined
782
+ export interface VSCodeConfig {
783
+ extensions?: string[];
558
784
  }
559
785
 
560
- export interface ResolvedPlugin {
561
- fullPluginName: string;
562
- url: string;
563
- kind: ResolvedPluginKind;
786
+ export interface JetBrainsConfig {
787
+ intellij?: JetBrainsProductConfig;
788
+ goland?: JetBrainsProductConfig;
789
+ pycharm?: JetBrainsProductConfig;
790
+ phpstorm?: JetBrainsProductConfig;
791
+ }
792
+ export interface JetBrainsProductConfig {
793
+ prebuilds?: JetBrainsPrebuilds;
794
+ vmoptions?: string;
795
+ }
796
+ export interface JetBrainsPrebuilds {
797
+ version?: "stable" | "latest" | "both";
564
798
  }
565
799
 
566
- export interface VSCodeConfig {
567
- extensions?: string[];
800
+ export interface RepositoryCloneInformation {
801
+ url: string;
802
+ checkoutLocation?: string;
568
803
  }
569
804
 
570
805
  export interface WorkspaceConfig {
806
+ mainConfiguration?: string;
807
+ additionalRepositories?: RepositoryCloneInformation[];
571
808
  image?: ImageConfig;
572
809
  ports?: PortConfig[];
573
810
  tasks?: TaskConfig[];
@@ -576,6 +813,7 @@ export interface WorkspaceConfig {
576
813
  gitConfig?: { [config: string]: string };
577
814
  github?: GithubAppConfig;
578
815
  vscode?: VSCodeConfig;
816
+ jetbrains?: JetBrainsConfig;
579
817
 
580
818
  /** deprecated. Enabled by default **/
581
819
  experimentalNetwork?: boolean;
@@ -590,7 +828,7 @@ export interface WorkspaceConfig {
590
828
  * additional-content - config comes from additional content, usually provided through the project's configuration
591
829
  * default - our static catch-all default config
592
830
  */
593
- _origin?: 'repo' | 'project-db' | 'definitely-gp' | 'derived' | 'additional-content' | 'default';
831
+ _origin?: "repo" | "project-db" | "definitely-gp" | "derived" | "additional-content" | "default";
594
832
 
595
833
  /**
596
834
  * Set of automatically infered feature flags. That's not something the user can set, but
@@ -600,34 +838,33 @@ export interface WorkspaceConfig {
600
838
  }
601
839
 
602
840
  export interface GithubAppConfig {
603
- prebuilds?: GithubAppPrebuildConfig
841
+ prebuilds?: GithubAppPrebuildConfig;
604
842
  }
605
843
  export interface GithubAppPrebuildConfig {
606
- master?: boolean
607
- branches?: boolean
608
- pullRequests?: boolean
609
- pullRequestsFromForks?: boolean
610
- addCheck?: boolean | 'prevent-merge-on-error'
611
- addBadge?: boolean
612
- addLabel?: boolean | string
613
- addComment?: boolean
844
+ master?: boolean;
845
+ branches?: boolean;
846
+ pullRequests?: boolean;
847
+ pullRequestsFromForks?: boolean;
848
+ addCheck?: boolean | "prevent-merge-on-error";
849
+ addBadge?: boolean;
850
+ addLabel?: boolean | string;
851
+ addComment?: boolean;
614
852
  }
615
853
  export namespace GithubAppPrebuildConfig {
616
854
  export function is(obj: boolean | GithubAppPrebuildConfig): obj is GithubAppPrebuildConfig {
617
- return !(typeof obj === 'boolean');
855
+ return !(typeof obj === "boolean");
618
856
  }
619
857
  }
620
858
 
621
859
  export type WorkspaceImageSource = WorkspaceImageSourceDocker | WorkspaceImageSourceReference;
622
860
  export interface WorkspaceImageSourceDocker {
623
- dockerFilePath: string
624
- dockerFileHash: string
625
- dockerFileSource?: Commit
861
+ dockerFilePath: string;
862
+ dockerFileHash: string;
863
+ dockerFileSource?: Commit;
626
864
  }
627
865
  export namespace WorkspaceImageSourceDocker {
628
866
  export function is(obj: object): obj is WorkspaceImageSourceDocker {
629
- return 'dockerFileHash' in obj
630
- && 'dockerFilePath' in obj;
867
+ return "dockerFileHash" in obj && "dockerFilePath" in obj;
631
868
  }
632
869
  }
633
870
  export interface WorkspaceImageSourceReference {
@@ -636,21 +873,23 @@ export interface WorkspaceImageSourceReference {
636
873
  }
637
874
  export namespace WorkspaceImageSourceReference {
638
875
  export function is(obj: object): obj is WorkspaceImageSourceReference {
639
- return 'baseImageResolved' in obj;
876
+ return "baseImageResolved" in obj;
640
877
  }
641
878
  }
642
879
 
643
- export type PrebuiltWorkspaceState
880
+ export type PrebuiltWorkspaceState =
644
881
  // the prebuild is queued and may start at anytime
645
- = "queued"
882
+ | "queued"
646
883
  // the workspace prebuild is currently running (i.e. there's a workspace pod deployed)
647
884
  | "building"
648
- // the prebuild failed due to some issue with the system (e.g. missed a message, could not start workspace)
885
+ // the prebuild was aborted
649
886
  | "aborted"
650
887
  // the prebuild timed out
651
888
  | "timeout"
652
- // the prebuild has finished and a snapshot is available
653
- | "available";
889
+ // the prebuild has finished (even if a headless task failed) and a snapshot is available
890
+ | "available"
891
+ // the prebuild (headless workspace) failed due to some system error
892
+ | "failed";
654
893
 
655
894
  export interface PrebuiltWorkspace {
656
895
  id: string;
@@ -661,13 +900,16 @@ export interface PrebuiltWorkspace {
661
900
  buildWorkspaceId: string;
662
901
  creationTime: string;
663
902
  state: PrebuiltWorkspaceState;
903
+ statusVersion: number;
664
904
  error?: string;
665
905
  snapshot?: string;
666
906
  }
667
907
 
668
908
  export namespace PrebuiltWorkspace {
669
909
  export function isDone(pws: PrebuiltWorkspace) {
670
- return pws.state === "available" || pws.state === "timeout" || pws.state === 'aborted';
910
+ return (
911
+ pws.state === "available" || pws.state === "timeout" || pws.state === "aborted" || pws.state === "failed"
912
+ );
671
913
  }
672
914
 
673
915
  export function isAvailable(pws: PrebuiltWorkspace) {
@@ -686,18 +928,22 @@ export interface PrebuiltWorkspaceUpdatable {
686
928
  repo: string;
687
929
  isResolved: boolean;
688
930
  installationId: string;
931
+ /**
932
+ * the commitSHA of the commit that triggered the prebuild
933
+ */
934
+ commitSHA?: string;
689
935
  issue?: string;
690
936
  contextUrl?: string;
691
937
  }
692
938
 
693
939
  export interface WhitelistedRepository {
694
- url: string
695
- name: string
696
- description?: string
697
- avatar?: string
940
+ url: string;
941
+ name: string;
942
+ description?: string;
943
+ avatar?: string;
698
944
  }
699
945
 
700
- export type PortOnOpen = 'open-browser' | 'open-preview' | 'notify' | 'ignore';
946
+ export type PortOnOpen = "open-browser" | "open-preview" | "notify" | "ignore";
701
947
 
702
948
  export interface PortConfig {
703
949
  port: number;
@@ -708,7 +954,7 @@ export interface PortConfig {
708
954
  }
709
955
  export namespace PortConfig {
710
956
  export function is(config: any): config is PortConfig {
711
- return config && ('port' in config) && (typeof config.port === 'number');
957
+ return config && "port" in config && typeof config.port === "number";
712
958
  }
713
959
  }
714
960
 
@@ -718,7 +964,7 @@ export interface PortRangeConfig {
718
964
  }
719
965
  export namespace PortRangeConfig {
720
966
  export function is(config: any): config is PortRangeConfig {
721
- return config && ('port' in config) && (typeof config.port === 'string' || config.port instanceof String);
967
+ return config && "port" in config && (typeof config.port === "string" || config.port instanceof String);
722
968
  }
723
969
  }
724
970
 
@@ -729,32 +975,31 @@ export interface TaskConfig {
729
975
  prebuild?: string;
730
976
  command?: string;
731
977
  env?: { [env: string]: any };
732
- openIn?: 'bottom' | 'main' | 'left' | 'right';
733
- openMode?: 'split-top' | 'split-left' | 'split-right' | 'split-bottom' | 'tab-before' | 'tab-after';
978
+ openIn?: "bottom" | "main" | "left" | "right";
979
+ openMode?: "split-top" | "split-left" | "split-right" | "split-bottom" | "tab-before" | "tab-after";
734
980
  }
735
981
 
736
982
  export namespace TaskConfig {
737
983
  export function is(config: any): config is TaskConfig {
738
- return config
739
- && ('command' in config || 'init' in config || 'before' in config);
984
+ return config && ("command" in config || "init" in config || "before" in config);
740
985
  }
741
986
  }
742
987
 
743
988
  export namespace WorkspaceImageBuild {
744
- export type Phase = 'BaseImage' | 'GitpodLayer' | 'Error' | 'Done';
989
+ export type Phase = "BaseImage" | "GitpodLayer" | "Error" | "Done";
745
990
  export interface StateInfo {
746
- phase: Phase
747
- currentStep?: number
748
- maxSteps?: number
991
+ phase: Phase;
992
+ currentStep?: number;
993
+ maxSteps?: number;
749
994
  }
750
995
  export interface LogContent {
751
- text: string
752
- upToLine?: number
753
- isDiff?: boolean
996
+ text: string;
997
+ upToLine?: number;
998
+ isDiff?: boolean;
754
999
  }
755
1000
  export type LogCallback = (info: StateInfo, content: LogContent | undefined) => void;
756
1001
  export namespace LogLine {
757
- export const DELIMITER = '\r\n';
1002
+ export const DELIMITER = "\r\n";
758
1003
  export const DELIMITER_REGEX = /\r?\n/;
759
1004
  }
760
1005
  }
@@ -763,20 +1008,18 @@ export type ImageConfig = ImageConfigString | ImageConfigFile;
763
1008
  export type ImageConfigString = string;
764
1009
  export namespace ImageConfigString {
765
1010
  export function is(config: ImageConfig | undefined): config is ImageConfigString {
766
- return typeof config === 'string';
1011
+ return typeof config === "string";
767
1012
  }
768
-
769
1013
  }
770
1014
  export interface ImageConfigFile {
771
1015
  // Path to the Dockerfile relative to repository root
772
- file: string,
1016
+ file: string;
773
1017
  // Path to the docker build context relative to repository root
774
- context?: string
1018
+ context?: string;
775
1019
  }
776
1020
  export namespace ImageConfigFile {
777
1021
  export function is(config: ImageConfig | undefined): config is ImageConfigFile {
778
- return typeof config === 'object'
779
- && 'file' in config;
1022
+ return typeof config === "object" && "file" in config;
780
1023
  }
781
1024
  }
782
1025
  export interface ExternalImageConfigFile extends ImageConfigFile {
@@ -784,14 +1027,13 @@ export interface ExternalImageConfigFile extends ImageConfigFile {
784
1027
  }
785
1028
  export namespace ExternalImageConfigFile {
786
1029
  export function is(config: any | undefined): config is ExternalImageConfigFile {
787
- return typeof config === 'object'
788
- && 'file' in config
789
- && 'externalSource' in config;
1030
+ return typeof config === "object" && "file" in config && "externalSource" in config;
790
1031
  }
791
1032
  }
792
1033
 
793
1034
  export interface WorkspaceContext {
794
1035
  title: string;
1036
+ ref?: string;
795
1037
  /** This contains the URL portion of the contextURL (which might contain other modifiers as well). It's optional because it's not set for older workspaces. */
796
1038
  normalizedContextURL?: string;
797
1039
  forceCreateNewWorkspace?: boolean;
@@ -800,8 +1042,7 @@ export interface WorkspaceContext {
800
1042
 
801
1043
  export namespace WorkspaceContext {
802
1044
  export function is(context: any): context is WorkspaceContext {
803
- return context
804
- && 'title' in context;
1045
+ return context && "title" in context;
805
1046
  }
806
1047
  }
807
1048
 
@@ -810,22 +1051,17 @@ export interface WithSnapshot {
810
1051
  }
811
1052
  export namespace WithSnapshot {
812
1053
  export function is(context: any): context is WithSnapshot {
813
- return context
814
- && 'snapshotBucketId' in context;
1054
+ return context && "snapshotBucketId" in context;
815
1055
  }
816
1056
  }
817
1057
 
818
- export interface WithPrebuild {
819
- snapshotBucketId: string;
1058
+ export interface WithPrebuild extends WithSnapshot {
820
1059
  prebuildWorkspaceId: string;
821
1060
  wasPrebuilt: true;
822
1061
  }
823
1062
  export namespace WithPrebuild {
824
1063
  export function is(context: any): context is WithPrebuild {
825
- return context
826
- && 'snapshotBucketId' in context
827
- && 'prebuildWorkspaceId' in context
828
- && 'wasPrebuilt' in context;
1064
+ return context && WithSnapshot.is(context) && "prebuildWorkspaceId" in context && "wasPrebuilt" in context;
829
1065
  }
830
1066
  }
831
1067
 
@@ -839,16 +1075,14 @@ export interface WithDefaultConfig {
839
1075
 
840
1076
  export namespace WithDefaultConfig {
841
1077
  export function is(context: any): context is WithDefaultConfig {
842
- return context
843
- && 'withDefaultConfig' in context
844
- && context.withDefaultConfig;
1078
+ return context && "withDefaultConfig" in context && context.withDefaultConfig;
845
1079
  }
846
1080
 
847
1081
  export function mark(ctx: WorkspaceContext): WorkspaceContext & WithDefaultConfig {
848
1082
  return {
849
1083
  ...ctx,
850
- withDefaultConfig: true
851
- }
1084
+ withDefaultConfig: true,
1085
+ };
852
1086
  }
853
1087
  }
854
1088
 
@@ -858,23 +1092,24 @@ export interface SnapshotContext extends WorkspaceContext, WithSnapshot {
858
1092
 
859
1093
  export namespace SnapshotContext {
860
1094
  export function is(context: any): context is SnapshotContext {
861
- return context
862
- && WithSnapshot.is(context)
863
- && 'snapshotId' in context;
1095
+ return context && WithSnapshot.is(context) && "snapshotId" in context;
864
1096
  }
865
1097
  }
866
1098
 
867
1099
  export interface StartPrebuildContext extends WorkspaceContext {
868
1100
  actual: WorkspaceContext;
869
1101
  commitHistory?: string[];
1102
+ additionalRepositoryCommitHistories?: {
1103
+ cloneUrl: string;
1104
+ commitHistory: string[];
1105
+ }[];
870
1106
  project?: Project;
871
1107
  branch?: string;
872
1108
  }
873
1109
 
874
1110
  export namespace StartPrebuildContext {
875
1111
  export function is(context: any): context is StartPrebuildContext {
876
- return context
877
- && 'actual' in context;
1112
+ return context && "actual" in context;
878
1113
  }
879
1114
  }
880
1115
 
@@ -886,21 +1121,18 @@ export interface PrebuiltWorkspaceContext extends WorkspaceContext {
886
1121
 
887
1122
  export namespace PrebuiltWorkspaceContext {
888
1123
  export function is(context: any): context is PrebuiltWorkspaceContext {
889
- return context
890
- && 'originalContext' in context
891
- && 'prebuiltWorkspace' in context;
1124
+ return context && "originalContext" in context && "prebuiltWorkspace" in context;
892
1125
  }
893
1126
  }
894
1127
 
895
1128
  export interface WithReferrerContext extends WorkspaceContext {
896
- referrer: string
897
- referrerIde?: string
1129
+ referrer: string;
1130
+ referrerIde?: string;
898
1131
  }
899
1132
 
900
1133
  export namespace WithReferrerContext {
901
1134
  export function is(context: any): context is WithReferrerContext {
902
- return context
903
- && 'referrer' in context;
1135
+ return context && "referrer" in context;
904
1136
  }
905
1137
  }
906
1138
 
@@ -910,21 +1142,18 @@ export interface WithEnvvarsContext extends WorkspaceContext {
910
1142
 
911
1143
  export namespace WithEnvvarsContext {
912
1144
  export function is(context: any): context is WithEnvvarsContext {
913
- return context
914
- && 'envvars' in context
1145
+ return context && "envvars" in context;
915
1146
  }
916
1147
  }
917
1148
 
918
1149
  export interface WorkspaceProbeContext extends WorkspaceContext {
919
- responseURL: string
920
- responseToken: string
1150
+ responseURL: string;
1151
+ responseToken: string;
921
1152
  }
922
1153
 
923
1154
  export namespace WorkspaceProbeContext {
924
1155
  export function is(context: any): context is WorkspaceProbeContext {
925
- return context
926
- && 'responseURL' in context
927
- && 'responseToken' in context;
1156
+ return context && "responseURL" in context && "responseToken" in context;
928
1157
  }
929
1158
  }
930
1159
 
@@ -936,32 +1165,30 @@ export namespace RefType {
936
1165
  }
937
1166
  // This fallback is meant to handle the cases where (for historic reasons) ref is present but refType is missing
938
1167
  return commit.refType || "branch";
939
- }
1168
+ };
940
1169
  }
941
1170
 
942
1171
  export interface Commit {
943
- repository: Repository
944
- revision: string
1172
+ repository: Repository;
1173
+ revision: string;
945
1174
 
946
1175
  // Might contain either a branch or a tag (determined by refType)
947
- ref?: string
1176
+ ref?: string;
948
1177
 
949
1178
  // refType is only set if ref is present (and not for old workspaces, before this feature was added)
950
- refType?: RefType
1179
+ refType?: RefType;
951
1180
  }
952
1181
 
953
1182
  export interface AdditionalContentContext extends WorkspaceContext {
954
-
955
1183
  /**
956
1184
  * utf-8 encoded contents that will be copied on top of the workspace's filesystem
957
1185
  */
958
- additionalFiles: {[filePath: string]: string};
959
-
1186
+ additionalFiles: { [filePath: string]: string };
960
1187
  }
961
1188
 
962
1189
  export namespace AdditionalContentContext {
963
1190
  export function is(ctx: any): ctx is AdditionalContentContext {
964
- return 'additionalFiles' in ctx;
1191
+ return "additionalFiles" in ctx;
965
1192
  }
966
1193
 
967
1194
  export function hasDockerConfig(ctx: any, config: WorkspaceConfig): boolean {
@@ -969,16 +1196,49 @@ export namespace AdditionalContentContext {
969
1196
  }
970
1197
  }
971
1198
 
972
- export interface CommitContext extends WorkspaceContext, Commit {
1199
+ export interface CommitContext extends WorkspaceContext, GitCheckoutInfo {
973
1200
  /** @deprecated Moved to .repository.cloneUrl, left here for backwards-compatibility for old workspace contextes in the DB */
974
- cloneUrl?: string
1201
+ cloneUrl?: string;
1202
+
1203
+ /**
1204
+ * The clone and checkout information for additional repositories in case of multi-repo projects.
1205
+ */
1206
+ additionalRepositoryCheckoutInfo?: GitCheckoutInfo[];
1207
+ }
1208
+
1209
+ export namespace CommitContext {
1210
+ /**
1211
+ * Creates a hash for all the commits of the CommitContext and all sub-repo commit infos.
1212
+ * The hash is max 255 chars long.
1213
+ * @param commitContext
1214
+ * @returns hash for commitcontext
1215
+ */
1216
+ export function computeHash(commitContext: CommitContext): string {
1217
+ // for single commits we use the revision to be backward compatible.
1218
+ if (
1219
+ !commitContext.additionalRepositoryCheckoutInfo ||
1220
+ commitContext.additionalRepositoryCheckoutInfo.length === 0
1221
+ ) {
1222
+ return commitContext.revision;
1223
+ }
1224
+ const hasher = createHash("sha256");
1225
+ hasher.update(commitContext.revision);
1226
+ for (const info of commitContext.additionalRepositoryCheckoutInfo) {
1227
+ hasher.update(info.revision);
1228
+ }
1229
+ return hasher.digest("hex");
1230
+ }
1231
+ }
1232
+
1233
+ export interface GitCheckoutInfo extends Commit {
1234
+ checkoutLocation?: string;
1235
+ upstreamRemoteURI?: string;
1236
+ localBranch?: string;
975
1237
  }
976
1238
 
977
1239
  export namespace CommitContext {
978
1240
  export function is(commit: any): commit is CommitContext {
979
- return WorkspaceContext.is(commit)
980
- && 'repository' in commit
981
- && 'revision' in commit
1241
+ return WorkspaceContext.is(commit) && "repository" in commit && "revision" in commit;
982
1242
  }
983
1243
  }
984
1244
 
@@ -986,17 +1246,14 @@ export interface PullRequestContext extends CommitContext {
986
1246
  nr: number;
987
1247
  ref: string;
988
1248
  base: {
989
- repository: Repository
990
- ref: string
991
- }
1249
+ repository: Repository;
1250
+ ref: string;
1251
+ };
992
1252
  }
993
1253
 
994
1254
  export namespace PullRequestContext {
995
1255
  export function is(ctx: any): ctx is PullRequestContext {
996
- return CommitContext.is(ctx)
997
- && 'nr' in ctx
998
- && 'ref' in ctx
999
- && 'base' in ctx
1256
+ return CommitContext.is(ctx) && "nr" in ctx && "ref" in ctx && "base" in ctx;
1000
1257
  }
1001
1258
  }
1002
1259
 
@@ -1008,10 +1265,7 @@ export interface IssueContext extends CommitContext {
1008
1265
 
1009
1266
  export namespace IssueContext {
1010
1267
  export function is(ctx: any): ctx is IssueContext {
1011
- return CommitContext.is(ctx)
1012
- && 'nr' in ctx
1013
- && 'ref' in ctx
1014
- && 'localBranch' in ctx
1268
+ return CommitContext.is(ctx) && "nr" in ctx && "ref" in ctx && "localBranch" in ctx;
1015
1269
  }
1016
1270
  }
1017
1271
 
@@ -1022,9 +1276,7 @@ export interface NavigatorContext extends CommitContext {
1022
1276
 
1023
1277
  export namespace NavigatorContext {
1024
1278
  export function is(ctx: any): ctx is NavigatorContext {
1025
- return CommitContext.is(ctx)
1026
- && 'path' in ctx
1027
- && 'isFile' in ctx
1279
+ return CommitContext.is(ctx) && "path" in ctx && "isFile" in ctx;
1028
1280
  }
1029
1281
  }
1030
1282
 
@@ -1033,6 +1285,8 @@ export interface Repository {
1033
1285
  owner: string;
1034
1286
  name: string;
1035
1287
  cloneUrl: string;
1288
+ /* Optional kind to differentiate between repositories of orgs/groups/projects and personal repos. */
1289
+ repoKind?: string;
1036
1290
  description?: string;
1037
1291
  avatarUrl?: string;
1038
1292
  webUrl?: string;
@@ -1041,8 +1295,8 @@ export interface Repository {
1041
1295
  private?: boolean;
1042
1296
  fork?: {
1043
1297
  // The direct parent of this fork
1044
- parent: Repository
1045
- }
1298
+ parent: Repository;
1299
+ };
1046
1300
  }
1047
1301
  export interface Branch {
1048
1302
  name: string;
@@ -1067,21 +1321,19 @@ export namespace Repository {
1067
1321
  export interface WorkspaceInstancePortsChangedEvent {
1068
1322
  type: "PortsChanged";
1069
1323
  instanceID: string;
1070
- portsOpened: number[]
1071
- portsClosed: number[]
1324
+ portsOpened: number[];
1325
+ portsClosed: number[];
1072
1326
  }
1073
1327
 
1074
1328
  export namespace WorkspaceInstancePortsChangedEvent {
1075
-
1076
1329
  export function is(data: any): data is WorkspaceInstancePortsChangedEvent {
1077
1330
  return data && data.type == "PortsChanged";
1078
1331
  }
1079
-
1080
1332
  }
1081
1333
 
1082
1334
  export interface WorkspaceInfo {
1083
- workspace: Workspace
1084
- latestInstance?: WorkspaceInstance
1335
+ workspace: Workspace;
1336
+ latestInstance?: WorkspaceInstance;
1085
1337
  }
1086
1338
 
1087
1339
  export namespace WorkspaceInfo {
@@ -1097,35 +1349,36 @@ export interface WorkspaceCreationResult {
1097
1349
  workspaceURL?: string;
1098
1350
  existingWorkspaces?: WorkspaceInfo[];
1099
1351
  runningWorkspacePrebuild?: {
1100
- prebuildID: string
1101
- workspaceID: string
1102
- instanceID: string
1103
- starting: RunningWorkspacePrebuildStarting
1104
- sameCluster: boolean
1105
- }
1352
+ prebuildID: string;
1353
+ workspaceID: string;
1354
+ instanceID: string;
1355
+ starting: RunningWorkspacePrebuildStarting;
1356
+ sameCluster: boolean;
1357
+ };
1106
1358
  runningPrebuildWorkspaceID?: string;
1107
1359
  }
1108
- export type RunningWorkspacePrebuildStarting = 'queued' | 'starting' | 'running';
1360
+ export type RunningWorkspacePrebuildStarting = "queued" | "starting" | "running";
1109
1361
 
1110
1362
  export enum CreateWorkspaceMode {
1111
1363
  // Default returns a running prebuild if there is any, otherwise creates a new workspace (using a prebuild if one is available)
1112
- Default = 'default',
1364
+ Default = "default",
1113
1365
  // ForceNew creates a new workspace irrespective of any running prebuilds. This mode is guaranteed to actually create a workspace - but may degrade user experience as currently runnig prebuilds are ignored.
1114
- ForceNew = 'force-new',
1366
+ ForceNew = "force-new",
1115
1367
  // UsePrebuild polls the database waiting for a currently running prebuild to become available. This mode exists to handle the db-sync delay.
1116
- UsePrebuild = 'use-prebuild',
1368
+ UsePrebuild = "use-prebuild",
1117
1369
  // SelectIfRunning returns a list of currently running workspaces for the context URL if there are any, otherwise falls back to Default mode
1118
- SelectIfRunning = 'select-if-running',
1370
+ SelectIfRunning = "select-if-running",
1119
1371
  }
1120
1372
 
1121
1373
  export namespace WorkspaceCreationResult {
1122
1374
  export function is(data: any): data is WorkspaceCreationResult {
1123
- return data && (
1124
- 'createdWorkspaceId' in data
1125
- || 'existingWorkspaces' in data
1126
- || 'runningWorkspacePrebuild' in data
1127
- || 'runningPrebuildWorkspaceID' in data
1128
- )
1375
+ return (
1376
+ data &&
1377
+ ("createdWorkspaceId" in data ||
1378
+ "existingWorkspaces" in data ||
1379
+ "runningWorkspacePrebuild" in data ||
1380
+ "runningPrebuildWorkspaceID" in data)
1381
+ );
1129
1382
  }
1130
1383
  }
1131
1384
 
@@ -1159,7 +1412,7 @@ export interface AuthProviderInfo {
1159
1412
  readonly default: string[];
1160
1413
  readonly publicRepo: string[];
1161
1414
  readonly privateRepo: string[];
1162
- }
1415
+ };
1163
1416
  }
1164
1417
 
1165
1418
  export interface AuthProviderEntry {
@@ -1171,6 +1424,8 @@ export interface AuthProviderEntry {
1171
1424
  readonly status: AuthProviderEntry.Status;
1172
1425
 
1173
1426
  readonly oauth: OAuth2Config;
1427
+ /** A random string that is to change whenever oauth changes (enforced on DB level) */
1428
+ readonly oauthRevision?: string;
1174
1429
  }
1175
1430
 
1176
1431
  export interface OAuth2Config {
@@ -1183,23 +1438,27 @@ export interface OAuth2Config {
1183
1438
  readonly scopeSeparator?: string;
1184
1439
 
1185
1440
  readonly settingsUrl?: string;
1186
- readonly authorizationParams?: { [key: string]: string }
1441
+ readonly authorizationParams?: { [key: string]: string };
1187
1442
  readonly configURL?: string;
1188
1443
  }
1189
1444
 
1190
1445
  export namespace AuthProviderEntry {
1191
1446
  export type Type = "GitHub" | "GitLab" | string;
1192
1447
  export type Status = "pending" | "verified";
1193
- export type NewEntry = Pick<AuthProviderEntry, "ownerId" | "host" | "type"> & { clientId?: string, clientSecret?: string };
1194
- export type UpdateEntry = Pick<AuthProviderEntry, "id" | "ownerId"> & Pick<OAuth2Config, "clientId" | "clientSecret">;
1448
+ export type NewEntry = Pick<AuthProviderEntry, "ownerId" | "host" | "type"> & {
1449
+ clientId?: string;
1450
+ clientSecret?: string;
1451
+ };
1452
+ export type UpdateEntry = Pick<AuthProviderEntry, "id" | "ownerId"> &
1453
+ Pick<OAuth2Config, "clientId" | "clientSecret">;
1195
1454
  export function redact(entry: AuthProviderEntry): AuthProviderEntry {
1196
1455
  return {
1197
1456
  ...entry,
1198
1457
  oauth: {
1199
1458
  ...entry.oauth,
1200
- clientSecret: "redacted"
1201
- }
1202
- }
1459
+ clientSecret: "redacted",
1460
+ },
1461
+ };
1203
1462
  }
1204
1463
  }
1205
1464
 
@@ -1243,3 +1502,11 @@ export interface Terms {
1243
1502
  readonly content: string;
1244
1503
  readonly formElements?: object;
1245
1504
  }
1505
+
1506
+ export interface CostCenter {
1507
+ readonly id: string;
1508
+ /**
1509
+ * Unit: credits
1510
+ */
1511
+ spendingLimit: number;
1512
+ }