@valbuild/server 0.68.2 → 0.69.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.
@@ -1536,10 +1536,13 @@ class ValOps {
1536
1536
  }
1537
1537
 
1538
1538
  // #region analyzePatches
1539
- analyzePatches(sortedPatches) {
1539
+ analyzePatches(sortedPatches, commits, currentCommitSha) {
1540
1540
  const patchesByModule = {};
1541
1541
  const fileLastUpdatedByPatchId = {};
1542
1542
  for (const patch of sortedPatches) {
1543
+ if (patch.appliedAt) {
1544
+ continue;
1545
+ }
1543
1546
  for (const op of patch.patch) {
1544
1547
  if (op.op === "file") {
1545
1548
  const filePath = op.filePath;
@@ -1578,7 +1581,7 @@ class ValOps {
1578
1581
  const errors = {};
1579
1582
  for (const patchData of analysis.patches) {
1580
1583
  const path = patchData.path;
1581
- if (!sources[path]) {
1584
+ if (sources[path] === undefined) {
1582
1585
  if (!errors[path]) {
1583
1586
  errors[path] = [];
1584
1587
  }
@@ -1855,6 +1858,8 @@ class ValOps {
1855
1858
  patchesByModule,
1856
1859
  fileLastUpdatedByPatchId
1857
1860
  } = patchAnalysis;
1861
+ const patchedSourceFiles = {};
1862
+ const previousSourceFiles = {};
1858
1863
  const applySourceFilePatches = async (path, patches) => {
1859
1864
  const sourceFileRes = await this.getSourceFile(path);
1860
1865
  const errors = [];
@@ -1870,6 +1875,7 @@ class ValOps {
1870
1875
  };
1871
1876
  }
1872
1877
  const sourceFile = sourceFileRes.data;
1878
+ previousSourceFiles[path] = sourceFile;
1873
1879
  let tsSourceFile = ts.createSourceFile("<val>", sourceFile, ts.ScriptTarget.ES2015);
1874
1880
  const appliedPatches = [];
1875
1881
  const triedPatches = [];
@@ -1947,7 +1953,6 @@ class ValOps {
1947
1953
  const appliedPatches = {};
1948
1954
  const triedPatches = {};
1949
1955
  const skippedPatches = {};
1950
- const patchedSourceFiles = {};
1951
1956
 
1952
1957
  //
1953
1958
  const globalAppliedPatches = [];
@@ -1988,6 +1993,7 @@ class ValOps {
1988
1993
  sourceFilePatchErrors,
1989
1994
  binaryFilePatchErrors,
1990
1995
  patchedSourceFiles,
1996
+ previousSourceFiles,
1991
1997
  patchedBinaryFilesDescriptors,
1992
1998
  appliedPatches,
1993
1999
  skippedPatches,
@@ -2005,7 +2011,7 @@ class ValOps {
2005
2011
  if (parentRef.type !== "head") {
2006
2012
  // There's room for some optimizations here: we could do this once, then re-use every time we create a patch, then again we only create one patch at a time
2007
2013
  const patchOps = await this.fetchPatches({
2008
- omitPatch: false
2014
+ excludePatchOps: false
2009
2015
  });
2010
2016
  const patchAnalysis = this.analyzePatches(patchOps.patches);
2011
2017
  const tree = await this.getSources({
@@ -2029,7 +2035,7 @@ class ValOps {
2029
2035
  }
2030
2036
  });
2031
2037
  }
2032
- if (!source) {
2038
+ if (source === undefined) {
2033
2039
  console.error(`Cannot patch. Module source at path: '${path}' does not exist`);
2034
2040
  return result.err({
2035
2041
  errorType: "other",
@@ -2341,6 +2347,13 @@ class ValOpsFS extends ValOps {
2341
2347
  async onInit() {
2342
2348
  // do nothing
2343
2349
  }
2350
+ async getCommitSummary() {
2351
+ return {
2352
+ error: {
2353
+ message: "Val is in development / local mode. Cannot generate summary"
2354
+ }
2355
+ };
2356
+ }
2344
2357
  async getStat(params) {
2345
2358
  // In ValOpsFS, we don't have a websocket server to listen to file changes so we use long-polling.
2346
2359
  // If a file that Val depends on changes, we break the connection and tell the client to request again to get the latest values.
@@ -2522,7 +2535,7 @@ class ValOpsFS extends ValOps {
2522
2535
  }
2523
2536
  patches[parsedPatch.data.patchId] = {
2524
2537
  ...parsedPatch.data,
2525
- appliedAt: parsedBase ? parsedBase.data : null
2538
+ appliedAt: null
2526
2539
  };
2527
2540
  }
2528
2541
  });
@@ -2542,17 +2555,9 @@ class ValOpsFS extends ValOps {
2542
2555
  return parentRef.type === "head" ? "head" : parentRef.patchId;
2543
2556
  }
2544
2557
  async fetchPatches(filters) {
2545
- const fetchPatchesRes = await this.fetchPatchesFromFS(!!filters.omitPatch);
2546
- const sortedPatches = this.createPatchChain(fetchPatchesRes.patches).filter(patchData => {
2547
- if (filters.authors && !(patchData.authorId === null || filters.authors.includes(patchData.authorId))) {
2548
- return false;
2549
- }
2550
- if (filters.moduleFilePaths && !filters.moduleFilePaths.includes(patchData.path)) {
2551
- return false;
2552
- }
2553
- return true;
2554
- }).map(patchData => {
2555
- if (filters.omitPatch) {
2558
+ const fetchPatchesRes = await this.fetchPatchesFromFS(!!filters.excludePatchOps);
2559
+ const sortedPatches = this.createPatchChain(fetchPatchesRes.patches).map(patchData => {
2560
+ if (filters.excludePatchOps) {
2556
2561
  return {
2557
2562
  ...patchData,
2558
2563
  patch: undefined
@@ -2565,7 +2570,7 @@ class ValOpsFS extends ValOps {
2565
2570
  errors: fetchPatchesRes.errors
2566
2571
  };
2567
2572
  }
2568
- async fetchPatchesFromFS(omitPath) {
2573
+ async fetchPatchesFromFS(excludePatchOps) {
2569
2574
  const patches = {};
2570
2575
  const {
2571
2576
  errors,
@@ -2574,7 +2579,7 @@ class ValOpsFS extends ValOps {
2574
2579
  for (const [patchIdS, patch] of Object.entries(allPatches)) {
2575
2580
  const patchId = patchIdS;
2576
2581
  patches[patchId] = {
2577
- patch: omitPath ? undefined : patch.patch,
2582
+ patch: excludePatchOps ? undefined : patch.patch,
2578
2583
  parentRef: patch.parentRef,
2579
2584
  path: patch.path,
2580
2585
  baseSha: patch.baseSha,
@@ -3168,7 +3173,7 @@ const textEncoder = new TextEncoder();
3168
3173
  const PatchId = z.string().refine(s => !!s); // TODO: validate
3169
3174
  const CommitSha = z.string().refine(s => !!s); // TODO: validate
3170
3175
  z.string().refine(s => !!s); // TODO: validate
3171
- const AuthorId = z.string().refine(s => !!s); // TODO: validate
3176
+ z.string().refine(s => !!s); // TODO: validate
3172
3177
  const ModuleFilePath = z.string().refine(s => !!s); // TODO: validate
3173
3178
  const Metadata = z.union([z.object({
3174
3179
  mimeType: z.string(),
@@ -3182,20 +3187,28 @@ const MetadataRes = z.object({
3182
3187
  metadata: Metadata,
3183
3188
  type: z.union([z.literal("file"), z.literal("image")]).nullable()
3184
3189
  });
3185
- const BasePatchResponse = z.object({
3186
- path: ModuleFilePath,
3187
- patchId: PatchId,
3188
- authorId: AuthorId.nullable(),
3189
- createdAt: z.string().datetime(),
3190
- baseSha: z.string()
3190
+ const SummaryResponse = z.object({
3191
+ commitSummary: z.string().nullable()
3191
3192
  });
3192
- const GetPatches = z.object({
3193
- patches: z.array(z.intersection(z.object({
3194
- patch: Patch.optional()
3195
- }), BasePatchResponse)),
3196
- errors: z.array(z.object({
3197
- patchId: PatchId.optional(),
3198
- message: z.string()
3193
+ const GetApplicablePatches = z.object({
3194
+ patches: z.array(z.object({
3195
+ path: z.string(),
3196
+ patch: Patch.nullable(),
3197
+ patchId: z.string(),
3198
+ authorId: z.string().nullable(),
3199
+ baseSha: z.string(),
3200
+ createdAt: z.string(),
3201
+ applied: z.object({
3202
+ commitSha: z.string()
3203
+ }).nullable()
3204
+ })),
3205
+ commits: z.array(z.object({
3206
+ commitSha: z.string(),
3207
+ clientCommitSha: z.string(),
3208
+ parentCommitSha: z.string(),
3209
+ branch: z.string(),
3210
+ creator: z.string(),
3211
+ createdAt: z.string()
3199
3212
  })).optional()
3200
3213
  });
3201
3214
  const FilesResponse = z.object({
@@ -3232,7 +3245,7 @@ const DeletePatchesResponse = z.object({
3232
3245
  patchId: PatchId
3233
3246
  })).optional()
3234
3247
  });
3235
- z.object({
3248
+ const SavePatchFileResponse = z.object({
3236
3249
  patchId: PatchId,
3237
3250
  filePath: ModuleFilePath
3238
3251
  });
@@ -3251,11 +3264,11 @@ const ProfilesResponse = z.object({
3251
3264
  }))
3252
3265
  });
3253
3266
  class ValOpsHttp extends ValOps {
3254
- constructor(hostUrl, project, commitSha,
3267
+ constructor(contentUrl, project, commitSha,
3255
3268
  // TODO: CommitSha
3256
3269
  branch, apiKey, valModules, options) {
3257
3270
  super(valModules, options);
3258
- this.hostUrl = hostUrl;
3271
+ this.contentUrl = contentUrl;
3259
3272
  this.project = project;
3260
3273
  this.commitSha = commitSha;
3261
3274
  this.branch = branch;
@@ -3267,6 +3280,70 @@ class ValOpsHttp extends ValOps {
3267
3280
  async onInit() {
3268
3281
  // TODO: unused for now. Implement or remove
3269
3282
  }
3283
+ async getCommitSummary(preparedCommit) {
3284
+ try {
3285
+ var _res$headers$get;
3286
+ const res = await fetch(`${this.contentUrl}/v1/${this.project}/commit-summary`, {
3287
+ method: "POST",
3288
+ headers: {
3289
+ ...this.authHeaders,
3290
+ "Content-Type": "application/json"
3291
+ },
3292
+ body: JSON.stringify({
3293
+ patchedSourceFiles: preparedCommit.patchedSourceFiles,
3294
+ previousSourceFiles: preparedCommit.previousSourceFiles
3295
+ })
3296
+ });
3297
+ if (res.ok) {
3298
+ const json = await res.json();
3299
+ const parsed = SummaryResponse.safeParse(json);
3300
+ if (parsed.success) {
3301
+ return {
3302
+ commitSummary: parsed.data.commitSummary
3303
+ };
3304
+ }
3305
+ console.error(`Could not parse summary response. Error: ${fromError(parsed.error).toString()}`);
3306
+ return {
3307
+ error: {
3308
+ message: `Cannot get the summary of your changes. An error has been logged. Possible cause: the current version of Val might be too old. Please try again later or contact the developers on your team.`
3309
+ }
3310
+ };
3311
+ }
3312
+ if (res.status === 401) {
3313
+ console.error("Unauthorized to get summary");
3314
+ return {
3315
+ error: {
3316
+ message: "Could not get summary. Although your user is authorized, the application has authorization issues. Contact the developers on your team and ask them to verify the api keys."
3317
+ }
3318
+ };
3319
+ }
3320
+ const unknownErrorMessage = `Could not get summary. HTTP error: ${res.status} ${res.statusText}`;
3321
+ if ((_res$headers$get = res.headers.get("Content-Type")) !== null && _res$headers$get !== void 0 && _res$headers$get.includes("application/json")) {
3322
+ const json = await res.json();
3323
+ if (json.message) {
3324
+ console.error("Summary error:", json.message);
3325
+ return {
3326
+ error: {
3327
+ message: json.message
3328
+ }
3329
+ };
3330
+ }
3331
+ }
3332
+ console.error(unknownErrorMessage);
3333
+ return {
3334
+ error: {
3335
+ message: unknownErrorMessage
3336
+ }
3337
+ };
3338
+ } catch (e) {
3339
+ console.error("Could not get summary (connection error?):", e);
3340
+ return {
3341
+ error: {
3342
+ message: `Could not get summary. Error: ${e instanceof Error ? e.message : JSON.stringify(e)}`
3343
+ }
3344
+ };
3345
+ }
3346
+ }
3270
3347
  async getStat(params) {
3271
3348
  if (!(params !== null && params !== void 0 && params.profileId)) {
3272
3349
  return {
@@ -3279,11 +3356,23 @@ class ValOpsHttp extends ValOps {
3279
3356
  const currentBaseSha = await this.getBaseSha();
3280
3357
  const currentSchemaSha = await this.getSchemaSha();
3281
3358
  const allPatchData = await this.fetchPatches({
3282
- omitPatch: true,
3283
- authors: undefined,
3284
- patchIds: undefined,
3285
- moduleFilePaths: undefined
3359
+ excludePatchOps: true,
3360
+ patchIds: undefined
3286
3361
  });
3362
+ if ("error" in allPatchData && allPatchData.error && allPatchData.unauthorized) {
3363
+ return {
3364
+ type: "error",
3365
+ error: allPatchData.error,
3366
+ unauthorized: true
3367
+ };
3368
+ }
3369
+ if ("error" in allPatchData && allPatchData.error && allPatchData.networkError) {
3370
+ return {
3371
+ type: "error",
3372
+ error: allPatchData.error,
3373
+ networkError: true
3374
+ };
3375
+ }
3287
3376
  // We think these errors will be picked up else where (?), so we only return an error here if there are no patches
3288
3377
  if (allPatchData.patches.length === 0) {
3289
3378
  let message;
@@ -3330,7 +3419,7 @@ class ValOpsHttp extends ValOps {
3330
3419
  };
3331
3420
  }
3332
3421
  async getWebSocketNonce(profileId) {
3333
- return fetch(`${this.hostUrl}/v1/${this.project}/websocket/nonces`, {
3422
+ return fetch(`${this.contentUrl}/v1/${this.project}/websocket/nonces`, {
3334
3423
  method: "POST",
3335
3424
  body: JSON.stringify({
3336
3425
  branch: this.branch,
@@ -3407,16 +3496,12 @@ class ValOpsHttp extends ValOps {
3407
3496
  if (patchIds === undefined || patchIds.length === 0) {
3408
3497
  return this.fetchPatchesInternal({
3409
3498
  patchIds: patchIds,
3410
- authors: filters.authors,
3411
- moduleFilePaths: filters.moduleFilePaths,
3412
- omitPatch: filters.omitPatch
3499
+ excludePatchOps: filters.excludePatchOps
3413
3500
  });
3414
3501
  }
3415
3502
  for (const res of await Promise.all(patchIdChunks.map(patchIdChunk => this.fetchPatchesInternal({
3416
3503
  patchIds: patchIdChunk,
3417
- authors: filters.authors,
3418
- moduleFilePaths: filters.moduleFilePaths,
3419
- omitPatch: filters.omitPatch
3504
+ excludePatchOps: filters.excludePatchOps
3420
3505
  })))) {
3421
3506
  if ("error" in res) {
3422
3507
  return res;
@@ -3434,72 +3519,97 @@ class ValOpsHttp extends ValOps {
3434
3519
  async fetchPatchesInternal(filters) {
3435
3520
  const params = [];
3436
3521
  params.push(["branch", this.branch]);
3522
+ params.push(["commit", this.commitSha]);
3437
3523
  if (filters.patchIds) {
3438
3524
  for (const patchId of filters.patchIds) {
3439
3525
  params.push(["patch_id", patchId]);
3440
3526
  }
3441
3527
  }
3442
- if (filters.authors) {
3443
- for (const author of filters.authors) {
3444
- params.push(["author_id", author]);
3445
- }
3446
- }
3447
- if (filters.omitPatch) {
3448
- params.push(["omit_patch", "true"]);
3449
- }
3450
- if (filters.moduleFilePaths) {
3451
- for (const moduleFilePath of filters.moduleFilePaths) {
3452
- params.push(["module_file_path", moduleFilePath]);
3453
- }
3528
+ if (filters.excludePatchOps) {
3529
+ params.push(["exclude_patch_ops", "true"]);
3454
3530
  }
3455
3531
  const searchParams = new URLSearchParams(params);
3456
- return fetch(`${this.hostUrl}/v1/${this.project}/patches${searchParams.size > 0 ? `?${searchParams.toString()}` : ""}`, {
3457
- headers: {
3458
- ...this.authHeaders,
3459
- "Content-Type": "application/json"
3460
- }
3461
- }).then(async res => {
3532
+ try {
3533
+ const patchesRes = await fetch(`${this.contentUrl}/v1/${this.project}/applicable/patches${searchParams.size > 0 ? `?${searchParams.toString()}` : ""}`, {
3534
+ headers: this.authHeaders
3535
+ });
3462
3536
  const patches = [];
3463
- if (res.ok) {
3464
- const json = await res.json();
3465
- const parsed = GetPatches.safeParse(json);
3537
+ if (patchesRes.ok) {
3538
+ const json = await patchesRes.json();
3539
+ const parsed = GetApplicablePatches.safeParse(json);
3466
3540
  if (parsed.success) {
3467
3541
  const errors = [];
3468
3542
  const data = parsed.data;
3469
3543
  for (const patchesRes of data.patches) {
3544
+ var _patchesRes$applied;
3470
3545
  patches.push({
3471
3546
  authorId: patchesRes.authorId,
3472
3547
  createdAt: patchesRes.createdAt,
3473
- appliedAt: null,
3474
3548
  patchId: patchesRes.patchId,
3475
3549
  path: patchesRes.path,
3476
3550
  baseSha: patchesRes.baseSha,
3477
- patch: filters.omitPatch ? undefined : patchesRes.patch
3551
+ patch: patchesRes.patch,
3552
+ appliedAt: (_patchesRes$applied = patchesRes.applied) !== null && _patchesRes$applied !== void 0 && _patchesRes$applied.commitSha ? {
3553
+ commitSha: patchesRes.applied.commitSha
3554
+ } : null
3478
3555
  });
3479
3556
  }
3557
+ const commits = [];
3558
+ if (data.commits) {
3559
+ for (const commit of data.commits) {
3560
+ commits.push({
3561
+ commitSha: commit.commitSha,
3562
+ clientCommitSha: commit.clientCommitSha,
3563
+ parentCommitSha: commit.parentCommitSha,
3564
+ branch: commit.branch,
3565
+ creator: commit.creator,
3566
+ createdAt: commit.createdAt
3567
+ });
3568
+ }
3569
+ }
3480
3570
  return {
3571
+ commits,
3481
3572
  patches,
3482
3573
  errors
3483
3574
  };
3484
3575
  }
3576
+ console.error("Could not parse patches response. Error: " + fromError(parsed.error));
3577
+ return {
3578
+ patches,
3579
+ error: {
3580
+ message: `The response that Val got from the server was not in the expected format. This might be a transient error or a configuration issue. Please try again later.`
3581
+ }
3582
+ };
3583
+ }
3584
+ console.error("Could not get patches. HTTP error: " + patchesRes.status + " " + patchesRes.statusText);
3585
+ if (patchesRes.status === 401) {
3485
3586
  return {
3486
3587
  patches,
3487
3588
  error: {
3488
- message: `Could not parse get patches response. Error: ${fromError(parsed.error)}`
3589
+ message: "Although your user is authorized, the application has authorization issues. Contact the developers on your team and ask them to verify the api keys."
3489
3590
  }
3490
3591
  };
3491
3592
  }
3492
3593
  return {
3493
3594
  patches,
3494
3595
  error: {
3495
- message: "Could not get patches. HTTP error: " + res.status + " " + res.statusText
3596
+ message: "Could not your changes. It is most likely due to a network issue. Check your network connection and please try again."
3496
3597
  }
3497
3598
  };
3498
- });
3599
+ } catch (err) {
3600
+ console.error("Could not get patches (connection error):", err instanceof Error ? err.message : JSON.stringify(err));
3601
+ return {
3602
+ patches: [],
3603
+ networkError: true,
3604
+ error: {
3605
+ message: `Error: ${err instanceof Error ? err.message : JSON.stringify(err)}`
3606
+ }
3607
+ };
3608
+ }
3499
3609
  }
3500
3610
  async saveSourceFilePatch(path, patch, parentRef, authorId) {
3501
3611
  const baseSha = await this.getBaseSha();
3502
- return fetch(`${this.hostUrl}/v1/${this.project}/patches`, {
3612
+ return fetch(`${this.contentUrl}/v1/${this.project}/patches`, {
3503
3613
  method: "POST",
3504
3614
  headers: {
3505
3615
  ...this.authHeaders,
@@ -3516,7 +3626,7 @@ class ValOpsHttp extends ValOps {
3516
3626
  coreVersion: Internal.VERSION.core
3517
3627
  })
3518
3628
  }).then(async res => {
3519
- var _res$headers$get;
3629
+ var _res$headers$get2;
3520
3630
  if (res.ok) {
3521
3631
  const parsed = SavePatchResponse.safeParse(await res.json());
3522
3632
  if (parsed.success) {
@@ -3535,7 +3645,7 @@ class ValOpsHttp extends ValOps {
3535
3645
  message: "Conflict: " + (await res.text())
3536
3646
  });
3537
3647
  }
3538
- if ((_res$headers$get = res.headers.get("Content-Type")) !== null && _res$headers$get !== void 0 && _res$headers$get.includes("application/json")) {
3648
+ if ((_res$headers$get2 = res.headers.get("Content-Type")) !== null && _res$headers$get2 !== void 0 && _res$headers$get2.includes("application/json")) {
3539
3649
  const json = await res.json();
3540
3650
  return result.err({
3541
3651
  errorType: "other",
@@ -3554,7 +3664,45 @@ class ValOpsHttp extends ValOps {
3554
3664
  });
3555
3665
  }
3556
3666
  async saveBase64EncodedBinaryFileFromPatch(filePath, parentRef, patchId, data, type, metadata) {
3557
- throw Error("TODO: implement");
3667
+ return fetch(`${this.contentUrl}/v1/${this.project}/patches/${patchId}/files`, {
3668
+ method: "POST",
3669
+ headers: {
3670
+ ...this.authHeaders,
3671
+ "Content-Type": "application/json"
3672
+ },
3673
+ body: JSON.stringify({
3674
+ filePath: filePath,
3675
+ data,
3676
+ type,
3677
+ metadata
3678
+ })
3679
+ }).then(async res => {
3680
+ if (res.ok) {
3681
+ const parsed = SavePatchFileResponse.safeParse(await res.json());
3682
+ if (parsed.success) {
3683
+ return {
3684
+ patchId: parsed.data.patchId,
3685
+ filePath: parsed.data.filePath
3686
+ };
3687
+ }
3688
+ return {
3689
+ error: {
3690
+ message: `Could not parse save patch file response. Error: ${fromError(parsed.error)}`
3691
+ }
3692
+ };
3693
+ }
3694
+ return {
3695
+ error: {
3696
+ message: "Could not save patch file. HTTP error: " + res.status + " " + res.statusText
3697
+ }
3698
+ };
3699
+ }).catch(e => {
3700
+ return {
3701
+ error: {
3702
+ message: `Could save source binary file in patch (connection error?): ${e.toString()}`
3703
+ }
3704
+ };
3705
+ });
3558
3706
  }
3559
3707
  async getHttpFiles(files) {
3560
3708
  const params = new URLSearchParams();
@@ -3565,7 +3713,7 @@ class ValOpsHttp extends ValOps {
3565
3713
  params.set("body_sha",
3566
3714
  // We use this for cache invalidation
3567
3715
  Internal.getSHA256Hash(textEncoder.encode(stringifiedFiles)));
3568
- return fetch(`${this.hostUrl}/v1/${this.project}/files?${params}`, {
3716
+ return fetch(`${this.contentUrl}/v1/${this.project}/files?${params}`, {
3569
3717
  method: "PUT",
3570
3718
  // Yes, PUT is weird. Weirder to have a body in a GET request.
3571
3719
  headers: {
@@ -3658,7 +3806,7 @@ class ValOpsHttp extends ValOps {
3658
3806
  const params = new URLSearchParams();
3659
3807
  params.set("file_path", filePath);
3660
3808
  try {
3661
- const metadataRes = await fetch(`${this.hostUrl}/v1/${this.project}/patches/${patchId}/files?${params}`, {
3809
+ const metadataRes = await fetch(`${this.contentUrl}/v1/${this.project}/patches/${patchId}/files?${params}`, {
3662
3810
  headers: {
3663
3811
  ...this.authHeaders,
3664
3812
  "Content-Type": "application/json"
@@ -3712,7 +3860,7 @@ class ValOpsHttp extends ValOps {
3712
3860
  };
3713
3861
  }
3714
3862
  async deletePatches(patchIds) {
3715
- return fetch(`${this.hostUrl}/v1/${this.project}/patches`, {
3863
+ return fetch(`${this.contentUrl}/v1/${this.project}/patches`, {
3716
3864
  method: "DELETE",
3717
3865
  headers: {
3718
3866
  ...this.authHeaders,
@@ -3758,11 +3906,44 @@ class ValOpsHttp extends ValOps {
3758
3906
  };
3759
3907
  });
3760
3908
  }
3761
- async commit(prepared, message, committer, newBranch) {
3909
+ async getCommitMessage(preparedCommit) {
3910
+ var _res$headers$get3;
3911
+ const res = await fetch(`${this.contentUrl}/v1/${this.project}/commit-summary`, {
3912
+ method: "POST",
3913
+ headers: {
3914
+ ...this.authHeaders,
3915
+ "Content-Type": "application/json"
3916
+ },
3917
+ body: JSON.stringify({
3918
+ patchedSourceFiles: preparedCommit.patchedSourceFiles,
3919
+ previousSourceFiles: preparedCommit.previousSourceFiles
3920
+ })
3921
+ });
3922
+ if (res.ok) {
3923
+ const json = await res.json();
3924
+ return {
3925
+ commitSummary: json.commitSummary
3926
+ };
3927
+ }
3928
+ if ((_res$headers$get3 = res.headers.get("Content-Type")) !== null && _res$headers$get3 !== void 0 && _res$headers$get3.includes("application/json")) {
3929
+ const json = await res.json();
3930
+ return {
3931
+ error: {
3932
+ message: json.message
3933
+ }
3934
+ };
3935
+ }
3936
+ return {
3937
+ error: {
3938
+ message: "Could not get commit message. HTTP error: " + res.status + " " + res.statusText
3939
+ }
3940
+ };
3941
+ }
3942
+ async commit(prepared, message, committer, filesDirectory, newBranch) {
3762
3943
  try {
3763
- var _res$headers$get2;
3944
+ var _res$headers$get4;
3764
3945
  const existingBranch = this.branch;
3765
- const res = await fetch(`${this.hostUrl}/v1/${this.project}/commit`, {
3946
+ const res = await fetch(`${this.contentUrl}/v1/${this.project}/commit`, {
3766
3947
  method: "POST",
3767
3948
  headers: {
3768
3949
  ...this.authHeaders,
@@ -3774,6 +3955,7 @@ class ValOpsHttp extends ValOps {
3774
3955
  appliedPatches: prepared.appliedPatches,
3775
3956
  commit: this.commitSha,
3776
3957
  root: this.root,
3958
+ filesDirectory,
3777
3959
  baseSha: await this.getBaseSha(),
3778
3960
  committer,
3779
3961
  message,
@@ -3796,7 +3978,7 @@ class ValOpsHttp extends ValOps {
3796
3978
  }
3797
3979
  };
3798
3980
  }
3799
- if ((_res$headers$get2 = res.headers.get("Content-Type")) !== null && _res$headers$get2 !== void 0 && _res$headers$get2.includes("application/json")) {
3981
+ if ((_res$headers$get4 = res.headers.get("Content-Type")) !== null && _res$headers$get4 !== void 0 && _res$headers$get4.includes("application/json")) {
3800
3982
  const json = await res.json();
3801
3983
  if (json.isNotFastForward) {
3802
3984
  return {
@@ -3828,8 +4010,8 @@ class ValOpsHttp extends ValOps {
3828
4010
 
3829
4011
  // #region profiles
3830
4012
  async getProfiles() {
3831
- var _res$headers$get3;
3832
- const res = await fetch(`${this.hostUrl}/v1/${this.project}/profiles`, {
4013
+ var _res$headers$get5;
4014
+ const res = await fetch(`${this.contentUrl}/v1/${this.project}/profiles`, {
3833
4015
  headers: {
3834
4016
  ...this.authHeaders,
3835
4017
  "Content-Type": "application/json"
@@ -3843,7 +4025,7 @@ class ValOpsHttp extends ValOps {
3843
4025
  }
3844
4026
  return parsed.data.profiles;
3845
4027
  }
3846
- if ((_res$headers$get3 = res.headers.get("Content-Type")) !== null && _res$headers$get3 !== void 0 && _res$headers$get3.includes("application/json")) {
4028
+ if ((_res$headers$get5 = res.headers.get("Content-Type")) !== null && _res$headers$get5 !== void 0 && _res$headers$get5.includes("application/json")) {
3847
4029
  const json = await res.json();
3848
4030
  throw Error(`Could not get profiles (status: ${res.status}): ${"message" in json ? json.message : "Unknown error"}`);
3849
4031
  }
@@ -3881,6 +4063,7 @@ const ValServer = (valModules, options, callbacks) => {
3881
4063
  url.searchParams.set("state", token);
3882
4064
  return url.toString();
3883
4065
  };
4066
+ const commit = options.mode === "http" ? options.commit : undefined;
3884
4067
  const getAppErrorUrl = error => {
3885
4068
  if (!options.project) {
3886
4069
  throw new Error("Project is not set");
@@ -4343,6 +4526,22 @@ const ValServer = (valModules, options, callbacks) => {
4343
4526
  ...req.body,
4344
4527
  profileId: "id" in auth ? auth.id : undefined
4345
4528
  });
4529
+ if (currentStat.type === "error" && currentStat.networkError) {
4530
+ return {
4531
+ status: 503,
4532
+ json: {
4533
+ message: "Network error"
4534
+ }
4535
+ };
4536
+ }
4537
+ if (currentStat.type === "error" && currentStat.unauthorized) {
4538
+ return {
4539
+ status: 401,
4540
+ json: {
4541
+ message: "Unauthorized"
4542
+ }
4543
+ };
4544
+ }
4346
4545
  if (currentStat.type === "error") {
4347
4546
  return {
4348
4547
  status: 500,
@@ -4353,6 +4552,7 @@ const ValServer = (valModules, options, callbacks) => {
4353
4552
  status: 200,
4354
4553
  json: {
4355
4554
  ...currentStat,
4555
+ mode: serverOps instanceof ValOpsFS ? "fs" : serverOps instanceof ValOpsHttp ? "http" : "unknown",
4356
4556
  config: options.config
4357
4557
  }
4358
4558
  };
@@ -4380,7 +4580,7 @@ const ValServer = (valModules, options, callbacks) => {
4380
4580
  };
4381
4581
  }
4382
4582
  const patches = req.body.patches;
4383
- const parentRef = req.body.parentRef;
4583
+ let parentRef = req.body.parentRef;
4384
4584
  const authorId = "id" in auth ? auth.id : null;
4385
4585
  const newPatchIds = [];
4386
4586
  for (const patch of patches) {
@@ -4411,6 +4611,10 @@ const ValServer = (valModules, options, callbacks) => {
4411
4611
  };
4412
4612
  }
4413
4613
  } else {
4614
+ parentRef = {
4615
+ type: "patch",
4616
+ patchId: createPatchRes.value.patchId
4617
+ };
4414
4618
  newPatchIds.push(createPatchRes.value.patchId);
4415
4619
  }
4416
4620
  }
@@ -4418,10 +4622,7 @@ const ValServer = (valModules, options, callbacks) => {
4418
4622
  status: 200,
4419
4623
  json: {
4420
4624
  newPatchIds,
4421
- parentRef: {
4422
- type: "patch",
4423
- patchId: newPatchIds[newPatchIds.length - 1]
4424
- }
4625
+ parentRef
4425
4626
  }
4426
4627
  };
4427
4628
  },
@@ -4446,13 +4647,10 @@ const ValServer = (valModules, options, callbacks) => {
4446
4647
  }
4447
4648
  };
4448
4649
  }
4449
- const omit_patch = query.omit_patch === true;
4450
- const authors = query.author;
4650
+ const excludePatchOps = query.exclude_patch_ops === true;
4451
4651
  const fetchedPatchesRes = await serverOps.fetchPatches({
4452
- authors,
4453
4652
  patchIds: query.patch_id,
4454
- omitPatch: omit_patch,
4455
- moduleFilePaths: query.module_file_path
4653
+ excludePatchOps: excludePatchOps
4456
4654
  });
4457
4655
  if (fetchedPatchesRes.error) {
4458
4656
  // Error is singular
@@ -4633,8 +4831,17 @@ const ValServer = (valModules, options, callbacks) => {
4633
4831
  }
4634
4832
  const patchOps = await serverOps.fetchPatches({
4635
4833
  patchIds: undefined,
4636
- omitPatch: false
4834
+ excludePatchOps: false
4637
4835
  });
4836
+ // We check authorization here, because it is the first call to the backend
4837
+ if (patchOps.error && patchOps.unauthorized) {
4838
+ return {
4839
+ status: 401,
4840
+ json: {
4841
+ message: "Unauthorized"
4842
+ }
4843
+ };
4844
+ }
4638
4845
  const patchAnalysis = serverOps.analyzePatches(patchOps.patches);
4639
4846
  let sourcesRes = await serverOps.getSources();
4640
4847
  const onlyPatchedTreeModules = await serverOps.getSources({
@@ -4713,17 +4920,16 @@ const ValServer = (valModules, options, callbacks) => {
4713
4920
  },
4714
4921
  "/profiles": {
4715
4922
  GET: async req => {
4716
- // const cookies = req.cookies;
4717
- // const auth = getAuth(cookies);
4718
- // if (auth.error) {
4719
- // return {
4720
- // status: 401,
4721
- // json: {
4722
- // message: auth.error,
4723
- // },
4724
- // };
4725
- // }
4726
-
4923
+ const cookies = req.cookies;
4924
+ const auth = getAuth(cookies);
4925
+ if (auth.error) {
4926
+ return {
4927
+ status: 401,
4928
+ json: {
4929
+ message: auth.error
4930
+ }
4931
+ };
4932
+ }
4727
4933
  const profiles = await serverOps.getProfiles();
4728
4934
  return {
4729
4935
  status: 200,
@@ -4733,6 +4939,49 @@ const ValServer = (valModules, options, callbacks) => {
4733
4939
  };
4734
4940
  }
4735
4941
  },
4942
+ "/commit-summary": {
4943
+ GET: async req => {
4944
+ const cookies = req.cookies;
4945
+ const auth = getAuth(cookies);
4946
+ if (auth.error) {
4947
+ return {
4948
+ status: 401,
4949
+ json: {
4950
+ message: auth.error
4951
+ }
4952
+ };
4953
+ }
4954
+ const query = req.query;
4955
+ const patchIds = query.patch_id;
4956
+ const patches = await serverOps.fetchPatches({
4957
+ patchIds,
4958
+ excludePatchOps: false
4959
+ });
4960
+ const analysis = serverOps.analyzePatches(patches.patches, patches.commits, commit);
4961
+ const preparedCommit = await serverOps.prepare({
4962
+ ...analysis,
4963
+ ...patches
4964
+ });
4965
+ const res = await serverOps.getCommitSummary(preparedCommit);
4966
+ if (res.error) {
4967
+ console.error("Failed to summarize", res.error);
4968
+ return {
4969
+ status: 400,
4970
+ json: {
4971
+ message: res.error.message
4972
+ }
4973
+ };
4974
+ }
4975
+ return {
4976
+ status: 200,
4977
+ json: {
4978
+ baseSha: await serverOps.getBaseSha(),
4979
+ patchIds,
4980
+ commitSummary: res.commitSummary
4981
+ }
4982
+ };
4983
+ }
4984
+ },
4736
4985
  "/save": {
4737
4986
  POST: async req => {
4738
4987
  const cookies = req.cookies;
@@ -4765,9 +5014,9 @@ const ValServer = (valModules, options, callbacks) => {
4765
5014
  } = bodyRes.data;
4766
5015
  const patches = await serverOps.fetchPatches({
4767
5016
  patchIds,
4768
- omitPatch: false
5017
+ excludePatchOps: false
4769
5018
  });
4770
- const analysis = serverOps.analyzePatches(patches.patches);
5019
+ const analysis = serverOps.analyzePatches(patches.patches, patches.commits, commit);
4771
5020
  const preparedCommit = await serverOps.prepare({
4772
5021
  ...analysis,
4773
5022
  ...patches
@@ -4799,7 +5048,24 @@ const ValServer = (valModules, options, callbacks) => {
4799
5048
  };
4800
5049
  } else if (serverOps instanceof ValOpsHttp) {
4801
5050
  if (auth.error === undefined && auth.id) {
4802
- const commitRes = await serverOps.commit(preparedCommit, "Update content: " + Object.keys(analysis.patchesByModule) + " modules changed", auth.id);
5051
+ var _options$config$ai, _options$config$files;
5052
+ let message = body.message || "Update content: " + Object.keys(analysis.patchesByModule) + " modules changed";
5053
+ if (!((_options$config$ai = options.config.ai) !== null && _options$config$ai !== void 0 && (_options$config$ai = _options$config$ai.commitMessages) !== null && _options$config$ai !== void 0 && _options$config$ai.disabled)) {
5054
+ const res = await serverOps.getCommitMessage(preparedCommit);
5055
+ console.log({
5056
+ res
5057
+ });
5058
+ if (res.error) {
5059
+ // ignore
5060
+ console.error("Failed to get commit message", res.error.message);
5061
+ } else {
5062
+ message = res.commitSummary;
5063
+ }
5064
+ }
5065
+ console.log({
5066
+ message
5067
+ });
5068
+ const commitRes = await serverOps.commit(preparedCommit, message, auth.id, ((_options$config$files = options.config.files) === null || _options$config$files === void 0 ? void 0 : _options$config$files.directory) || "/public/val");
4803
5069
  if (commitRes.error) {
4804
5070
  console.error("Failed to commit", commitRes.error);
4805
5071
  if ("isNotFastForward" in commitRes && commitRes.isNotFastForward) {