@gitpod/gitpod-protocol 0.1.5-vn-fix-undefined-context-ref-on-jb-gateway.1 → 0.1.5-vn-jetbrains-backend-plugin-223.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/data/gitpod-schema.json +63 -113
- package/lib/accounting-protocol.d.ts +1 -0
- package/lib/accounting-protocol.d.ts.map +1 -1
- package/lib/accounting-protocol.js +4 -0
- package/lib/accounting-protocol.js.map +1 -1
- package/lib/admin-protocol.d.ts +7 -0
- package/lib/admin-protocol.d.ts.map +1 -1
- package/lib/admin-protocol.js.map +1 -1
- package/lib/attribution.d.ts +20 -0
- package/lib/attribution.d.ts.map +1 -0
- package/lib/attribution.js +40 -0
- package/lib/attribution.js.map +1 -0
- package/lib/billing-mode.d.ts +41 -0
- package/lib/billing-mode.d.ts.map +1 -0
- package/lib/billing-mode.js +44 -0
- package/lib/billing-mode.js.map +1 -0
- package/lib/blocked-repositories-protocol.d.ts +13 -0
- package/lib/blocked-repositories-protocol.d.ts.map +1 -0
- package/lib/blocked-repositories-protocol.js +8 -0
- package/lib/blocked-repositories-protocol.js.map +1 -0
- package/lib/context-url.js +1 -1
- package/lib/context-url.js.map +1 -1
- package/lib/encryption/encryption-engine.d.ts.map +1 -1
- package/lib/encryption/encryption-engine.js +3 -3
- package/lib/encryption/encryption-engine.js.map +1 -1
- package/lib/encryption/encryption-engine.spec.js +1 -1
- package/lib/encryption/encryption-engine.spec.js.map +1 -1
- package/lib/encryption/key-provider.js +1 -1
- package/lib/encryption/key-provider.js.map +1 -1
- package/lib/experiments/always-default.d.ts +8 -0
- package/lib/experiments/always-default.d.ts.map +1 -0
- package/lib/experiments/always-default.js +20 -0
- package/lib/experiments/always-default.js.map +1 -0
- package/lib/experiments/configcat-server.d.ts +10 -0
- package/lib/experiments/configcat-server.d.ts.map +1 -0
- package/lib/experiments/configcat-server.js +36 -0
- package/lib/experiments/configcat-server.js.map +1 -0
- package/lib/experiments/configcat.d.ts +23 -0
- package/lib/experiments/configcat.d.ts.map +1 -0
- package/lib/experiments/configcat.js +57 -0
- package/lib/experiments/configcat.js.map +1 -0
- package/lib/experiments/types.d.ts +24 -0
- package/lib/experiments/types.d.ts.map +1 -0
- package/lib/experiments/types.js +10 -0
- package/lib/experiments/types.js.map +1 -0
- package/lib/gitpod-service.d.ts +35 -11
- package/lib/gitpod-service.d.ts.map +1 -1
- package/lib/gitpod-service.js +13 -1
- package/lib/gitpod-service.js.map +1 -1
- package/lib/ide-protocol.d.ts +8 -0
- package/lib/ide-protocol.d.ts.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/installation-admin-protocol.d.ts +3 -0
- package/lib/installation-admin-protocol.d.ts.map +1 -1
- package/lib/installation-admin-protocol.js +1 -0
- package/lib/installation-admin-protocol.js.map +1 -1
- package/lib/messaging/client-call-metrics.d.ts +1 -17
- package/lib/messaging/client-call-metrics.d.ts.map +1 -1
- package/lib/messaging/client-call-metrics.js +1 -2
- package/lib/messaging/client-call-metrics.js.map +1 -1
- package/lib/messaging/error.d.ts +6 -1
- package/lib/messaging/error.d.ts.map +1 -1
- package/lib/messaging/error.js +13 -3
- package/lib/messaging/error.js.map +1 -1
- package/lib/plans.d.ts +1 -0
- package/lib/plans.d.ts.map +1 -1
- package/lib/plans.js +4 -0
- package/lib/plans.js.map +1 -1
- package/lib/protocol.d.ts +88 -12
- package/lib/protocol.d.ts.map +1 -1
- package/lib/protocol.js +117 -11
- package/lib/protocol.js.map +1 -1
- package/lib/protocol.spec.d.ts +7 -0
- package/lib/protocol.spec.d.ts.map +1 -0
- package/lib/protocol.spec.js +127 -0
- package/lib/protocol.spec.js.map +1 -0
- package/lib/team-subscription-protocol.d.ts +2 -0
- package/lib/team-subscription-protocol.d.ts.map +1 -1
- package/lib/team-subscription-protocol.js +4 -0
- package/lib/team-subscription-protocol.js.map +1 -1
- package/lib/teams-projects-protocol.d.ts +14 -1
- package/lib/teams-projects-protocol.d.ts.map +1 -1
- package/lib/teams-projects-protocol.js.map +1 -1
- package/lib/usage.d.ts +61 -0
- package/lib/usage.d.ts.map +1 -0
- package/lib/usage.js +14 -0
- package/lib/usage.js.map +1 -0
- package/lib/util/debug-app.d.ts +25 -0
- package/lib/util/debug-app.d.ts.map +1 -0
- package/lib/util/debug-app.js +100 -0
- package/lib/util/debug-app.js.map +1 -0
- package/lib/util/garbage-collected-cache.d.ts.map +1 -1
- package/lib/util/garbage-collected-cache.js +5 -0
- package/lib/util/garbage-collected-cache.js.map +1 -1
- package/lib/util/gitpod-host-url.d.ts +3 -0
- package/lib/util/gitpod-host-url.d.ts.map +1 -1
- package/lib/util/gitpod-host-url.js +18 -0
- package/lib/util/gitpod-host-url.js.map +1 -1
- package/lib/util/grpc.d.ts +19 -0
- package/lib/util/grpc.d.ts.map +1 -1
- package/lib/util/grpc.js +73 -1
- package/lib/util/grpc.js.map +1 -1
- package/lib/util/logging.d.ts.map +1 -1
- package/lib/util/logging.js +8 -1
- package/lib/util/logging.js.map +1 -1
- package/lib/util/logging.spec.d.ts +7 -0
- package/lib/util/logging.spec.d.ts.map +1 -0
- package/lib/util/logging.spec.js +52 -0
- package/lib/util/logging.spec.js.map +1 -0
- package/lib/util/timeutil.d.ts +2 -0
- package/lib/util/timeutil.d.ts.map +1 -1
- package/lib/util/timeutil.js +13 -1
- package/lib/util/timeutil.js.map +1 -1
- package/lib/util/timeutil.spec.d.ts +2 -0
- package/lib/util/timeutil.spec.d.ts.map +1 -1
- package/lib/util/timeutil.spec.js +34 -0
- package/lib/util/timeutil.spec.js.map +1 -1
- package/lib/webhook-event.d.ts +44 -0
- package/lib/webhook-event.d.ts.map +1 -0
- package/lib/webhook-event.js +8 -0
- package/lib/webhook-event.js.map +1 -0
- package/lib/workspace-class.d.ts +14 -0
- package/lib/workspace-class.d.ts.map +1 -0
- package/lib/workspace-class.js +8 -0
- package/lib/workspace-class.js.map +1 -0
- package/lib/workspace-cluster.d.ts +5 -7
- package/lib/workspace-cluster.d.ts.map +1 -1
- package/lib/workspace-cluster.js.map +1 -1
- package/lib/workspace-instance.d.ts +12 -0
- package/lib/workspace-instance.d.ts.map +1 -1
- package/lib/wsready.d.ts +3 -3
- package/lib/wsready.d.ts.map +1 -1
- package/lib/wsready.js +0 -2
- package/lib/wsready.js.map +1 -1
- package/package.json +12 -6
- package/pkg-yarn.lock +8 -5
- package/provenance-bundle.jsonl +1 -1
- package/src/accounting-protocol.ts +3 -0
- package/src/admin-protocol.ts +10 -0
- package/src/attribution.ts +48 -0
- package/src/billing-mode.ts +77 -0
- package/src/blocked-repositories-protocol.ts +13 -0
- package/src/context-url.ts +1 -1
- package/src/encryption/encryption-engine.spec.ts +1 -1
- package/src/encryption/encryption-engine.ts +7 -3
- package/src/encryption/key-provider.ts +1 -1
- package/src/experiments/always-default.ts +24 -0
- package/src/experiments/configcat-server.ts +41 -0
- package/src/experiments/configcat.ts +62 -0
- package/src/experiments/types.ts +38 -0
- package/src/gitpod-service.ts +58 -10
- package/src/ide-protocol.ts +10 -0
- package/src/index.ts +1 -1
- package/src/installation-admin-protocol.ts +3 -0
- package/src/messaging/client-call-metrics.ts +1 -20
- package/src/messaging/error.ts +19 -4
- package/src/plans.ts +4 -0
- package/src/protocol.spec.ts +97 -0
- package/src/protocol.ts +196 -18
- package/src/team-subscription-protocol.ts +4 -0
- package/src/teams-projects-protocol.ts +15 -1
- package/src/usage.ts +71 -0
- package/src/util/debug-app.ts +81 -0
- package/src/util/garbage-collected-cache.ts +5 -0
- package/src/util/gitpod-host-url.ts +21 -0
- package/src/util/grpc.ts +89 -0
- package/src/util/logging.spec.ts +23 -0
- package/src/util/logging.ts +11 -2
- package/src/util/timeutil.spec.ts +28 -1
- package/src/util/timeutil.ts +12 -0
- package/src/webhook-event.ts +55 -0
- package/src/workspace-class.ts +14 -0
- package/src/workspace-cluster.ts +2 -4
- package/src/workspace-instance.ts +20 -0
- package/src/wsready.ts +5 -4
- package/lib/email-protocol.d.ts +0 -49
- package/lib/email-protocol.d.ts.map +0 -1
- package/lib/email-protocol.js +0 -28
- package/lib/email-protocol.js.map +0 -1
- package/src/email-protocol.ts +0 -65
package/src/protocol.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { WorkspaceInstance, PortVisibility } from "./workspace-instance";
|
|
|
8
8
|
import { RoleOrPermission } from "./permission";
|
|
9
9
|
import { Project } from "./teams-projects-protocol";
|
|
10
10
|
import { createHash } from "crypto";
|
|
11
|
+
import { AttributionId } from "./attribution";
|
|
11
12
|
|
|
12
13
|
export interface UserInfo {
|
|
13
14
|
name?: string;
|
|
@@ -45,6 +46,15 @@ export interface User {
|
|
|
45
46
|
markedDeleted?: boolean;
|
|
46
47
|
|
|
47
48
|
additionalData?: AdditionalUserData;
|
|
49
|
+
|
|
50
|
+
// Identifies an explicit team or user ID to which all the user's workspace usage should be attributed to (e.g. for billing purposes)
|
|
51
|
+
usageAttributionId?: string;
|
|
52
|
+
|
|
53
|
+
// The last time this user got verified somehow. The user is not verified if this is empty.
|
|
54
|
+
lastVerificationTime?: string;
|
|
55
|
+
|
|
56
|
+
// The phone number used for the last phone verification.
|
|
57
|
+
verificationPhoneNumber?: string;
|
|
48
58
|
}
|
|
49
59
|
|
|
50
60
|
export namespace User {
|
|
@@ -70,11 +80,14 @@ export namespace User {
|
|
|
70
80
|
}
|
|
71
81
|
|
|
72
82
|
/**
|
|
73
|
-
*
|
|
83
|
+
* Returns the stored email or if it doesn't exist returns the primaryEmail of the first identity this user signed up with.
|
|
74
84
|
* @param user
|
|
75
85
|
* @returns A primaryEmail, or undefined if there is none.
|
|
76
86
|
*/
|
|
77
87
|
export function getPrimaryEmail(user: User): string | undefined {
|
|
88
|
+
if (user.additionalData?.profile?.emailAddress) {
|
|
89
|
+
return user.additionalData?.profile?.emailAddress;
|
|
90
|
+
}
|
|
78
91
|
const identities = user.identities.filter((i) => !!i.primaryEmail);
|
|
79
92
|
if (identities.length <= 0) {
|
|
80
93
|
return undefined;
|
|
@@ -136,6 +149,50 @@ export namespace User {
|
|
|
136
149
|
}
|
|
137
150
|
user.additionalData.ideSettings = newIDESettings;
|
|
138
151
|
}
|
|
152
|
+
|
|
153
|
+
export function getProfile(user: User): Profile {
|
|
154
|
+
return {
|
|
155
|
+
name: User.getName(user!) || "",
|
|
156
|
+
email: User.getPrimaryEmail(user!) || "",
|
|
157
|
+
company: user?.additionalData?.profile?.companyName,
|
|
158
|
+
avatarURL: user?.avatarUrl,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function setProfile(user: User, profile: Profile): User {
|
|
163
|
+
user.fullName = profile.name;
|
|
164
|
+
user.avatarUrl = profile.avatarURL;
|
|
165
|
+
|
|
166
|
+
if (!user.additionalData) {
|
|
167
|
+
user.additionalData = {};
|
|
168
|
+
}
|
|
169
|
+
if (!user.additionalData.profile) {
|
|
170
|
+
user.additionalData.profile = {};
|
|
171
|
+
}
|
|
172
|
+
user.additionalData.profile.emailAddress = profile.email;
|
|
173
|
+
user.additionalData.profile.companyName = profile.company;
|
|
174
|
+
user.additionalData.profile.lastUpdatedDetailsNudge = new Date().toISOString();
|
|
175
|
+
|
|
176
|
+
return user;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// The actual Profile of a User
|
|
180
|
+
export interface Profile {
|
|
181
|
+
name: string;
|
|
182
|
+
email: string;
|
|
183
|
+
company?: string;
|
|
184
|
+
avatarURL?: string;
|
|
185
|
+
}
|
|
186
|
+
export namespace Profile {
|
|
187
|
+
export function hasChanges(before: Profile, after: Profile) {
|
|
188
|
+
return (
|
|
189
|
+
before.name !== after.name ||
|
|
190
|
+
before.email !== after.email ||
|
|
191
|
+
before.company !== after.company ||
|
|
192
|
+
before.avatarURL !== after.avatarURL
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
139
196
|
}
|
|
140
197
|
|
|
141
198
|
export interface AdditionalUserData {
|
|
@@ -150,9 +207,36 @@ export interface AdditionalUserData {
|
|
|
150
207
|
oauthClientsApproved?: { [key: string]: string };
|
|
151
208
|
// to remember GH Orgs the user installed/updated the GH App for
|
|
152
209
|
knownGitHubOrgs?: string[];
|
|
153
|
-
|
|
154
210
|
// Git clone URL pointing to the user's dotfile repo
|
|
155
211
|
dotfileRepo?: string;
|
|
212
|
+
// preferred workspace classes
|
|
213
|
+
workspaceClasses?: WorkspaceClasses;
|
|
214
|
+
// additional user profile data
|
|
215
|
+
profile?: ProfileDetails;
|
|
216
|
+
}
|
|
217
|
+
export namespace AdditionalUserData {
|
|
218
|
+
export function set(user: User, partialData: Partial<AdditionalUserData>): User {
|
|
219
|
+
if (!user.additionalData) {
|
|
220
|
+
user.additionalData = {
|
|
221
|
+
...partialData,
|
|
222
|
+
};
|
|
223
|
+
} else {
|
|
224
|
+
user.additionalData = {
|
|
225
|
+
...user.additionalData,
|
|
226
|
+
...partialData,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
return user;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// The format in which we store User Profiles in
|
|
233
|
+
export interface ProfileDetails {
|
|
234
|
+
// when was the last time the user updated their profile information or has been nudged to do so.
|
|
235
|
+
lastUpdatedDetailsNudge?: string;
|
|
236
|
+
// the user's company name
|
|
237
|
+
companyName?: string;
|
|
238
|
+
// the user's email
|
|
239
|
+
emailAddress?: string;
|
|
156
240
|
}
|
|
157
241
|
|
|
158
242
|
export interface EmailNotificationSettings {
|
|
@@ -171,6 +255,11 @@ export type IDESettings = {
|
|
|
171
255
|
useLatestVersion?: boolean;
|
|
172
256
|
};
|
|
173
257
|
|
|
258
|
+
export interface WorkspaceClasses {
|
|
259
|
+
regular: string;
|
|
260
|
+
prebuild: string;
|
|
261
|
+
}
|
|
262
|
+
|
|
174
263
|
export interface UserPlatform {
|
|
175
264
|
uid: string;
|
|
176
265
|
userAgent: string;
|
|
@@ -197,16 +286,29 @@ export interface UserFeatureSettings {
|
|
|
197
286
|
permanentWSFeatureFlags?: NamedWorkspaceFeatureFlag[];
|
|
198
287
|
}
|
|
199
288
|
|
|
289
|
+
export type BillingTier = "paid" | "free";
|
|
290
|
+
|
|
200
291
|
/**
|
|
201
292
|
* The values of this type MUST MATCH enum values in WorkspaceFeatureFlag from ws-manager/client/core_pb.d.ts
|
|
202
293
|
* If they don't we'll break things during workspace startup.
|
|
203
294
|
*/
|
|
204
295
|
export const WorkspaceFeatureFlags = {
|
|
205
296
|
full_workspace_backup: undefined,
|
|
206
|
-
fixed_resources: undefined,
|
|
207
297
|
persistent_volume_claim: undefined,
|
|
298
|
+
protected_secrets: undefined,
|
|
299
|
+
workspace_class_limiting: undefined,
|
|
300
|
+
workspace_connection_limiting: undefined,
|
|
208
301
|
};
|
|
209
302
|
export type NamedWorkspaceFeatureFlag = keyof typeof WorkspaceFeatureFlags;
|
|
303
|
+
export namespace NamedWorkspaceFeatureFlag {
|
|
304
|
+
export const WORKSPACE_PERSISTED_FEATTURE_FLAGS: NamedWorkspaceFeatureFlag[] = [
|
|
305
|
+
"full_workspace_backup",
|
|
306
|
+
"persistent_volume_claim",
|
|
307
|
+
];
|
|
308
|
+
export function isWorkspacePersisted(ff: NamedWorkspaceFeatureFlag): boolean {
|
|
309
|
+
return WORKSPACE_PERSISTED_FEATTURE_FLAGS.includes(ff);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
210
312
|
|
|
211
313
|
export interface EnvVarWithValue {
|
|
212
314
|
name: string;
|
|
@@ -356,6 +458,68 @@ export namespace UserEnvVar {
|
|
|
356
458
|
}
|
|
357
459
|
}
|
|
358
460
|
|
|
461
|
+
export interface SSHPublicKeyValue {
|
|
462
|
+
name: string;
|
|
463
|
+
key: string;
|
|
464
|
+
}
|
|
465
|
+
export interface UserSSHPublicKey extends SSHPublicKeyValue {
|
|
466
|
+
id: string;
|
|
467
|
+
key: string;
|
|
468
|
+
userId: string;
|
|
469
|
+
fingerprint: string;
|
|
470
|
+
creationTime: string;
|
|
471
|
+
lastUsedTime?: string;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export type UserSSHPublicKeyValue = Omit<UserSSHPublicKey, "key" | "userId">;
|
|
475
|
+
|
|
476
|
+
export namespace SSHPublicKeyValue {
|
|
477
|
+
export function validate(value: SSHPublicKeyValue): string | undefined {
|
|
478
|
+
if (value.name.length === 0) {
|
|
479
|
+
return "Title must not be empty.";
|
|
480
|
+
}
|
|
481
|
+
if (value.name.length > 255) {
|
|
482
|
+
return "Title too long. Maximum value length is 255 characters.";
|
|
483
|
+
}
|
|
484
|
+
if (value.key.length === 0) {
|
|
485
|
+
return "Key must not be empty.";
|
|
486
|
+
}
|
|
487
|
+
try {
|
|
488
|
+
getData(value);
|
|
489
|
+
} catch (e) {
|
|
490
|
+
return "Key is invalid. You must supply a key in OpenSSH public key format.";
|
|
491
|
+
}
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
export function getData(value: SSHPublicKeyValue) {
|
|
496
|
+
// 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'.
|
|
497
|
+
const regex =
|
|
498
|
+
/^(?<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>.*?))?$/;
|
|
499
|
+
const resultGroup = regex.exec(value.key.trim());
|
|
500
|
+
if (!resultGroup) {
|
|
501
|
+
throw new Error("Key is invalid.");
|
|
502
|
+
}
|
|
503
|
+
return {
|
|
504
|
+
type: resultGroup.groups?.["type"] as string,
|
|
505
|
+
key: resultGroup.groups?.["key"] as string,
|
|
506
|
+
email: resultGroup.groups?.["email"] || undefined,
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
export function getFingerprint(value: SSHPublicKeyValue) {
|
|
511
|
+
const data = getData(value);
|
|
512
|
+
let buf = Buffer.from(data.key, "base64");
|
|
513
|
+
// gitlab style
|
|
514
|
+
// const hash = createHash("md5").update(buf).digest("hex");
|
|
515
|
+
// github style
|
|
516
|
+
const hash = createHash("sha256").update(buf).digest("base64");
|
|
517
|
+
return hash;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
export const MAXIMUM_KEY_LENGTH = 5;
|
|
521
|
+
}
|
|
522
|
+
|
|
359
523
|
export interface GitpodToken {
|
|
360
524
|
/** Hash value (SHA256) of the token (primary key). */
|
|
361
525
|
tokenHash: string;
|
|
@@ -490,6 +654,7 @@ export interface Snapshot {
|
|
|
490
654
|
|
|
491
655
|
export interface VolumeSnapshot {
|
|
492
656
|
id: string;
|
|
657
|
+
workspaceId: string;
|
|
493
658
|
creationTime: string;
|
|
494
659
|
volumeHandle: string;
|
|
495
660
|
}
|
|
@@ -563,7 +728,7 @@ export interface Workspace {
|
|
|
563
728
|
|
|
564
729
|
export type WorkspaceSoftDeletion = "user" | "gc";
|
|
565
730
|
|
|
566
|
-
export type WorkspaceType = "regular" | "prebuild"
|
|
731
|
+
export type WorkspaceType = "regular" | "prebuild";
|
|
567
732
|
|
|
568
733
|
export namespace Workspace {
|
|
569
734
|
export function getFullRepositoryName(ws: Workspace): string | undefined {
|
|
@@ -639,6 +804,7 @@ export interface JetBrainsConfig {
|
|
|
639
804
|
}
|
|
640
805
|
export interface JetBrainsProductConfig {
|
|
641
806
|
prebuilds?: JetBrainsPrebuilds;
|
|
807
|
+
vmoptions?: string;
|
|
642
808
|
}
|
|
643
809
|
export interface JetBrainsPrebuilds {
|
|
644
810
|
version?: "stable" | "latest" | "both";
|
|
@@ -649,6 +815,12 @@ export interface RepositoryCloneInformation {
|
|
|
649
815
|
checkoutLocation?: string;
|
|
650
816
|
}
|
|
651
817
|
|
|
818
|
+
export interface CoreDumpConfig {
|
|
819
|
+
enabled?: boolean;
|
|
820
|
+
softLimit?: number;
|
|
821
|
+
hardLimit?: number;
|
|
822
|
+
}
|
|
823
|
+
|
|
652
824
|
export interface WorkspaceConfig {
|
|
653
825
|
mainConfiguration?: string;
|
|
654
826
|
additionalRepositories?: RepositoryCloneInformation[];
|
|
@@ -661,6 +833,7 @@ export interface WorkspaceConfig {
|
|
|
661
833
|
github?: GithubAppConfig;
|
|
662
834
|
vscode?: VSCodeConfig;
|
|
663
835
|
jetbrains?: JetBrainsConfig;
|
|
836
|
+
coreDump?: CoreDumpConfig;
|
|
664
837
|
|
|
665
838
|
/** deprecated. Enabled by default **/
|
|
666
839
|
experimentalNetwork?: boolean;
|
|
@@ -669,13 +842,12 @@ export interface WorkspaceConfig {
|
|
|
669
842
|
* Where the config object originates from.
|
|
670
843
|
*
|
|
671
844
|
* repo - from the repository
|
|
672
|
-
* project-db - from the "Project" stored in the database
|
|
673
845
|
* definitly-gp - from github.com/gitpod-io/definitely-gp
|
|
674
846
|
* derived - computed based on analyzing the repository
|
|
675
847
|
* additional-content - config comes from additional content, usually provided through the project's configuration
|
|
676
848
|
* default - our static catch-all default config
|
|
677
849
|
*/
|
|
678
|
-
_origin?: "repo" | "
|
|
850
|
+
_origin?: "repo" | "definitely-gp" | "derived" | "additional-content" | "default";
|
|
679
851
|
|
|
680
852
|
/**
|
|
681
853
|
* Set of automatically infered feature flags. That's not something the user can set, but
|
|
@@ -754,7 +926,9 @@ export interface PrebuiltWorkspace {
|
|
|
754
926
|
|
|
755
927
|
export namespace PrebuiltWorkspace {
|
|
756
928
|
export function isDone(pws: PrebuiltWorkspace) {
|
|
757
|
-
return
|
|
929
|
+
return (
|
|
930
|
+
pws.state === "available" || pws.state === "timeout" || pws.state === "aborted" || pws.state === "failed"
|
|
931
|
+
);
|
|
758
932
|
}
|
|
759
933
|
|
|
760
934
|
export function isAvailable(pws: PrebuiltWorkspace) {
|
|
@@ -991,17 +1165,6 @@ export namespace WithEnvvarsContext {
|
|
|
991
1165
|
}
|
|
992
1166
|
}
|
|
993
1167
|
|
|
994
|
-
export interface WorkspaceProbeContext extends WorkspaceContext {
|
|
995
|
-
responseURL: string;
|
|
996
|
-
responseToken: string;
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
export namespace WorkspaceProbeContext {
|
|
1000
|
-
export function is(context: any): context is WorkspaceProbeContext {
|
|
1001
|
-
return context && "responseURL" in context && "responseToken" in context;
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
1168
|
export type RefType = "branch" | "tag" | "revision";
|
|
1006
1169
|
export namespace RefType {
|
|
1007
1170
|
export const getRefType = (commit: Commit): RefType => {
|
|
@@ -1347,3 +1510,18 @@ export interface Terms {
|
|
|
1347
1510
|
readonly content: string;
|
|
1348
1511
|
readonly formElements?: object;
|
|
1349
1512
|
}
|
|
1513
|
+
|
|
1514
|
+
export interface StripeConfig {
|
|
1515
|
+
individualUsagePriceIds: { [currency: string]: string };
|
|
1516
|
+
teamUsagePriceIds: { [currency: string]: string };
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
export type BillingStrategy = "other" | "stripe";
|
|
1520
|
+
export interface CostCenter {
|
|
1521
|
+
readonly id: AttributionId;
|
|
1522
|
+
/**
|
|
1523
|
+
* Unit: credits
|
|
1524
|
+
*/
|
|
1525
|
+
spendingLimit: number;
|
|
1526
|
+
billingStrategy: BillingStrategy;
|
|
1527
|
+
}
|
|
@@ -43,6 +43,7 @@ export interface TeamSubscription2 {
|
|
|
43
43
|
/** The Chargebee subscription id */
|
|
44
44
|
paymentReference: string;
|
|
45
45
|
cancellationDate?: string;
|
|
46
|
+
excludeFromMoreResources: boolean;
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
export namespace TeamSubscription2 {
|
|
@@ -54,6 +55,9 @@ export namespace TeamSubscription2 {
|
|
|
54
55
|
export const isActive = (ts2: TeamSubscription2, date: string): boolean => {
|
|
55
56
|
return ts2.startDate <= date && (ts2.endDate === undefined || date < ts2.endDate);
|
|
56
57
|
};
|
|
58
|
+
export function isCancelled(s: TeamSubscription2, date: string): boolean {
|
|
59
|
+
return (!!s.cancellationDate && s.cancellationDate < date) || (!!s.endDate && s.endDate < date); // This edge case is meant to handle bad data: If for whatever reason cancellationDate has not been set: treat endDate as such
|
|
60
|
+
}
|
|
57
61
|
}
|
|
58
62
|
|
|
59
63
|
/**
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { PrebuiltWorkspaceState } from "./protocol";
|
|
8
8
|
import { v4 as uuidv4 } from "uuid";
|
|
9
9
|
import { DeepPartial } from "./util/deep-partial";
|
|
10
|
+
import { WebhookEvent } from "./webhook-event";
|
|
10
11
|
|
|
11
12
|
export interface ProjectConfig {
|
|
12
13
|
".gitpod.yml": string;
|
|
@@ -14,6 +15,8 @@ export interface ProjectConfig {
|
|
|
14
15
|
|
|
15
16
|
export interface ProjectSettings {
|
|
16
17
|
useIncrementalPrebuilds?: boolean;
|
|
18
|
+
usePersistentVolumeClaim?: boolean;
|
|
19
|
+
keepOutdatedPrebuildsRunning?: boolean;
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
export interface Project {
|
|
@@ -24,7 +27,6 @@ export interface Project {
|
|
|
24
27
|
teamId?: string;
|
|
25
28
|
userId?: string;
|
|
26
29
|
appInstallationId: string;
|
|
27
|
-
config?: ProjectConfig;
|
|
28
30
|
settings?: ProjectSettings;
|
|
29
31
|
creationTime: string;
|
|
30
32
|
/** This is a flag that triggers the HARD DELETION of this entity */
|
|
@@ -150,3 +152,15 @@ export interface TeamMembershipInvite {
|
|
|
150
152
|
/** This is a flag that triggers the HARD DELETION of this entity */
|
|
151
153
|
deleted?: boolean;
|
|
152
154
|
}
|
|
155
|
+
|
|
156
|
+
export interface PrebuildEvent {
|
|
157
|
+
id: string;
|
|
158
|
+
creationTime: string;
|
|
159
|
+
status: WebhookEvent.Status | WebhookEvent.PrebuildStatus;
|
|
160
|
+
message?: string;
|
|
161
|
+
prebuildId?: string;
|
|
162
|
+
projectId?: string;
|
|
163
|
+
cloneUrl?: string;
|
|
164
|
+
branch?: string;
|
|
165
|
+
commit?: string;
|
|
166
|
+
}
|
package/src/usage.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2022 Gitpod GmbH. All rights reserved.
|
|
3
|
+
* Licensed under the GNU Affero General Public License (AGPL).
|
|
4
|
+
* See License-AGPL.txt in the project root for license information.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { WorkspaceType } from "./protocol";
|
|
8
|
+
|
|
9
|
+
// types below are copied over from components/usage-api/typescript/src/usage/v1/usage_pb.d.ts
|
|
10
|
+
export interface ListUsageRequest {
|
|
11
|
+
attributionId: string;
|
|
12
|
+
from?: number;
|
|
13
|
+
to?: number;
|
|
14
|
+
order: Ordering;
|
|
15
|
+
pagination?: PaginationRequest;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export enum Ordering {
|
|
19
|
+
ORDERING_DESCENDING = 0,
|
|
20
|
+
ORDERING_ASCENDING = 1,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface PaginationRequest {
|
|
24
|
+
perPage: number;
|
|
25
|
+
page: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ListUsageResponse {
|
|
29
|
+
usageEntriesList: Usage[];
|
|
30
|
+
pagination?: PaginationResponse;
|
|
31
|
+
creditsUsed: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface PaginationResponse {
|
|
35
|
+
perPage: number;
|
|
36
|
+
totalPages: number;
|
|
37
|
+
total: number;
|
|
38
|
+
page: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type UsageKind = "workspaceinstance" | "invoice";
|
|
42
|
+
export interface Usage {
|
|
43
|
+
id: string;
|
|
44
|
+
attributionId: string;
|
|
45
|
+
description: string;
|
|
46
|
+
credits: number;
|
|
47
|
+
effectiveTime?: number;
|
|
48
|
+
kind: UsageKind;
|
|
49
|
+
workspaceInstanceId: string;
|
|
50
|
+
draft: boolean;
|
|
51
|
+
metadata: WorkspaceInstanceUsageData | InvoiceUsageData;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// the equivalent golang shape is maintained in `/workspace/gitpod/`components/usage/pkg/db/usage.go`
|
|
55
|
+
export interface WorkspaceInstanceUsageData {
|
|
56
|
+
workspaceId: string;
|
|
57
|
+
workspaceType: WorkspaceType;
|
|
58
|
+
workspaceClass: string;
|
|
59
|
+
contextURL: string;
|
|
60
|
+
startTime: string;
|
|
61
|
+
endTime?: string;
|
|
62
|
+
userId: string;
|
|
63
|
+
userName: string;
|
|
64
|
+
userAvatarURL: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface InvoiceUsageData {
|
|
68
|
+
invoiceId: string;
|
|
69
|
+
startDate: string;
|
|
70
|
+
endDate: string;
|
|
71
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2021 Gitpod GmbH. All rights reserved.
|
|
3
|
+
* Licensed under the GNU Affero General Public License (AGPL).
|
|
4
|
+
* See License-AGPL.txt in the project root for license information.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as http from "http";
|
|
8
|
+
import * as express from "express";
|
|
9
|
+
import { injectable, postConstruct } from "inversify";
|
|
10
|
+
import { log, LogrusLogLevel } from "./logging";
|
|
11
|
+
|
|
12
|
+
export interface SetLogLevelRequest {
|
|
13
|
+
level: LogrusLogLevel;
|
|
14
|
+
}
|
|
15
|
+
export namespace SetLogLevelRequest {
|
|
16
|
+
export function is(o: any): o is SetLogLevelRequest {
|
|
17
|
+
return typeof o === "object" && "level" in o;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@injectable()
|
|
22
|
+
export class DebugApp {
|
|
23
|
+
protected _app: express.Application;
|
|
24
|
+
protected httpServer: http.Server | undefined = undefined;
|
|
25
|
+
|
|
26
|
+
@postConstruct()
|
|
27
|
+
public ctor() {
|
|
28
|
+
this._app = this.create();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
create(): express.Application {
|
|
32
|
+
const app = express();
|
|
33
|
+
|
|
34
|
+
app.use(express.json());
|
|
35
|
+
app.use(express.urlencoded({ extended: true }));
|
|
36
|
+
|
|
37
|
+
app.post("/debug/logging", (req, res) => {
|
|
38
|
+
try {
|
|
39
|
+
const levelRequest = req.body;
|
|
40
|
+
if (!SetLogLevelRequest.is(levelRequest)) {
|
|
41
|
+
res.status(400).end("not a SetLogLevelRequest");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const newLogLevel = levelRequest.level;
|
|
46
|
+
log.setLogLevel(newLogLevel);
|
|
47
|
+
log.info("set log level", { newLogLevel });
|
|
48
|
+
res.status(200).end(JSON.stringify(levelRequest));
|
|
49
|
+
} catch (err) {
|
|
50
|
+
res.status(500).end(err);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return app;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public start(port: number = 6060) {
|
|
57
|
+
this.httpServer = this._app.listen(port, "localhost", () => {
|
|
58
|
+
log.info(`debug server listening on port: ${port}`);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public async stop() {
|
|
63
|
+
const server = this.httpServer;
|
|
64
|
+
if (!server) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
return new Promise<void>((resolve) =>
|
|
68
|
+
server.close((err: any) => {
|
|
69
|
+
if (err) {
|
|
70
|
+
log.warn(`error while closing http server`, { err });
|
|
71
|
+
}
|
|
72
|
+
this.httpServer = undefined;
|
|
73
|
+
resolve();
|
|
74
|
+
}),
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public get app(): express.Application {
|
|
79
|
+
return this._app;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -85,6 +85,10 @@ export class GitpodHostUrl {
|
|
|
85
85
|
return this.with((url) => ({ protocol: url.protocol === "https:" ? "wss:" : "ws:" }));
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
asWorkspacePage(): GitpodHostUrl {
|
|
89
|
+
return this.with((url) => ({ pathname: "/workspaces" }));
|
|
90
|
+
}
|
|
91
|
+
|
|
88
92
|
asDashboard(): GitpodHostUrl {
|
|
89
93
|
return this.with((url) => ({ pathname: "/" }));
|
|
90
94
|
}
|
|
@@ -171,4 +175,21 @@ export class GitpodHostUrl {
|
|
|
171
175
|
asApiLogout(): GitpodHostUrl {
|
|
172
176
|
return this.withApi((url) => ({ pathname: "/logout/" }));
|
|
173
177
|
}
|
|
178
|
+
|
|
179
|
+
asIDEProxy(): GitpodHostUrl {
|
|
180
|
+
const hostSegments = this.url.host.split(".");
|
|
181
|
+
if (hostSegments[0] === "ide") {
|
|
182
|
+
return this;
|
|
183
|
+
}
|
|
184
|
+
return this.with((url) => ({ host: "ide." + url.host }));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
asIDEMetrics(): GitpodHostUrl {
|
|
188
|
+
let newUrl: GitpodHostUrl = this;
|
|
189
|
+
const hostSegments = this.url.host.split(".");
|
|
190
|
+
if (hostSegments[0] !== "ide") {
|
|
191
|
+
newUrl = newUrl.asIDEProxy();
|
|
192
|
+
}
|
|
193
|
+
return newUrl.with((url) => ({ pathname: "/metrics-api" }));
|
|
194
|
+
}
|
|
174
195
|
}
|
package/src/util/grpc.ts
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
* See License-AGPL.txt in the project root for license information.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import * as grpc from "@grpc/grpc-js";
|
|
8
|
+
import { Status } from "@grpc/grpc-js/build/src/constants";
|
|
9
|
+
|
|
7
10
|
export const defaultGRPCOptions = {
|
|
8
11
|
"grpc.keepalive_timeout_ms": 10000,
|
|
9
12
|
"grpc.keepalive_time_ms": 60000,
|
|
@@ -13,3 +16,89 @@ export const defaultGRPCOptions = {
|
|
|
13
16
|
"grpc.max_reconnect_backoff_ms": 5000,
|
|
14
17
|
"grpc.max_receive_message_length": 1024 * 1024 * 16,
|
|
15
18
|
};
|
|
19
|
+
|
|
20
|
+
export type GrpcMethodType = "unary" | "client_stream" | "server_stream" | "bidi_stream";
|
|
21
|
+
|
|
22
|
+
export interface IGrpcCallMetricsLabels {
|
|
23
|
+
service: string;
|
|
24
|
+
method: string;
|
|
25
|
+
type: GrpcMethodType;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface IGrpcCallMetricsLabelsWithCode extends IGrpcCallMetricsLabels {
|
|
29
|
+
code: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const IClientCallMetrics = Symbol("IClientCallMetrics");
|
|
33
|
+
|
|
34
|
+
export interface IClientCallMetrics {
|
|
35
|
+
started(labels: IGrpcCallMetricsLabels): void;
|
|
36
|
+
sent(labels: IGrpcCallMetricsLabels): void;
|
|
37
|
+
received(labels: IGrpcCallMetricsLabels): void;
|
|
38
|
+
handled(labels: IGrpcCallMetricsLabelsWithCode): void;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getGrpcMethodType(requestStream: boolean, responseStream: boolean): GrpcMethodType {
|
|
42
|
+
if (requestStream) {
|
|
43
|
+
if (responseStream) {
|
|
44
|
+
return "bidi_stream";
|
|
45
|
+
} else {
|
|
46
|
+
return "client_stream";
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
if (responseStream) {
|
|
50
|
+
return "server_stream";
|
|
51
|
+
} else {
|
|
52
|
+
return "unary";
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function createClientCallMetricsInterceptor(metrics: IClientCallMetrics): grpc.Interceptor {
|
|
58
|
+
return (options, nextCall): grpc.InterceptingCall => {
|
|
59
|
+
const methodDef = options.method_definition;
|
|
60
|
+
const method = methodDef.path.substring(methodDef.path.lastIndexOf("/") + 1);
|
|
61
|
+
const service = methodDef.path.substring(1, methodDef.path.length - method.length - 1);
|
|
62
|
+
const labels = {
|
|
63
|
+
service,
|
|
64
|
+
method,
|
|
65
|
+
type: getGrpcMethodType(options.method_definition.requestStream, options.method_definition.responseStream),
|
|
66
|
+
};
|
|
67
|
+
const requester = new grpc.RequesterBuilder()
|
|
68
|
+
.withStart((metadata, listener, next) => {
|
|
69
|
+
const newListener = new grpc.ListenerBuilder()
|
|
70
|
+
.withOnReceiveStatus((status, next) => {
|
|
71
|
+
try {
|
|
72
|
+
metrics.handled({
|
|
73
|
+
...labels,
|
|
74
|
+
code: Status[status.code],
|
|
75
|
+
});
|
|
76
|
+
} finally {
|
|
77
|
+
next(status);
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
.withOnReceiveMessage((message, next) => {
|
|
81
|
+
try {
|
|
82
|
+
metrics.received(labels);
|
|
83
|
+
} finally {
|
|
84
|
+
next(message);
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
.build();
|
|
88
|
+
try {
|
|
89
|
+
metrics.started(labels);
|
|
90
|
+
} finally {
|
|
91
|
+
next(metadata, newListener);
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
.withSendMessage((message, next) => {
|
|
95
|
+
try {
|
|
96
|
+
metrics.sent(labels);
|
|
97
|
+
} finally {
|
|
98
|
+
next(message);
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
.build();
|
|
102
|
+
return new grpc.InterceptingCall(nextCall(options), requester);
|
|
103
|
+
};
|
|
104
|
+
}
|