@valbuild/server 0.68.2 → 0.69.0

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.
@@ -1565,10 +1565,13 @@ class ValOps {
1565
1565
  }
1566
1566
 
1567
1567
  // #region analyzePatches
1568
- analyzePatches(sortedPatches) {
1568
+ analyzePatches(sortedPatches, commits, currentCommitSha) {
1569
1569
  const patchesByModule = {};
1570
1570
  const fileLastUpdatedByPatchId = {};
1571
1571
  for (const patch of sortedPatches) {
1572
+ if (patch.appliedAt) {
1573
+ continue;
1574
+ }
1572
1575
  for (const op of patch.patch) {
1573
1576
  if (op.op === "file") {
1574
1577
  const filePath = op.filePath;
@@ -1607,7 +1610,7 @@ class ValOps {
1607
1610
  const errors = {};
1608
1611
  for (const patchData of analysis.patches) {
1609
1612
  const path = patchData.path;
1610
- if (!sources[path]) {
1613
+ if (sources[path] === undefined) {
1611
1614
  if (!errors[path]) {
1612
1615
  errors[path] = [];
1613
1616
  }
@@ -1884,6 +1887,8 @@ class ValOps {
1884
1887
  patchesByModule,
1885
1888
  fileLastUpdatedByPatchId
1886
1889
  } = patchAnalysis;
1890
+ const patchedSourceFiles = {};
1891
+ const previousSourceFiles = {};
1887
1892
  const applySourceFilePatches = async (path, patches) => {
1888
1893
  const sourceFileRes = await this.getSourceFile(path);
1889
1894
  const errors = [];
@@ -1899,6 +1904,7 @@ class ValOps {
1899
1904
  };
1900
1905
  }
1901
1906
  const sourceFile = sourceFileRes.data;
1907
+ previousSourceFiles[path] = sourceFile;
1902
1908
  let tsSourceFile = ts__default["default"].createSourceFile("<val>", sourceFile, ts__default["default"].ScriptTarget.ES2015);
1903
1909
  const appliedPatches = [];
1904
1910
  const triedPatches = [];
@@ -1976,7 +1982,6 @@ class ValOps {
1976
1982
  const appliedPatches = {};
1977
1983
  const triedPatches = {};
1978
1984
  const skippedPatches = {};
1979
- const patchedSourceFiles = {};
1980
1985
 
1981
1986
  //
1982
1987
  const globalAppliedPatches = [];
@@ -2017,6 +2022,7 @@ class ValOps {
2017
2022
  sourceFilePatchErrors,
2018
2023
  binaryFilePatchErrors,
2019
2024
  patchedSourceFiles,
2025
+ previousSourceFiles,
2020
2026
  patchedBinaryFilesDescriptors,
2021
2027
  appliedPatches,
2022
2028
  skippedPatches,
@@ -2034,7 +2040,7 @@ class ValOps {
2034
2040
  if (parentRef.type !== "head") {
2035
2041
  // 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
2036
2042
  const patchOps = await this.fetchPatches({
2037
- omitPatch: false
2043
+ excludePatchOps: false
2038
2044
  });
2039
2045
  const patchAnalysis = this.analyzePatches(patchOps.patches);
2040
2046
  const tree = await this.getSources({
@@ -2058,7 +2064,7 @@ class ValOps {
2058
2064
  }
2059
2065
  });
2060
2066
  }
2061
- if (!source) {
2067
+ if (source === undefined) {
2062
2068
  console.error(`Cannot patch. Module source at path: '${path}' does not exist`);
2063
2069
  return fp.result.err({
2064
2070
  errorType: "other",
@@ -2370,6 +2376,13 @@ class ValOpsFS extends ValOps {
2370
2376
  async onInit() {
2371
2377
  // do nothing
2372
2378
  }
2379
+ async getCommitSummary() {
2380
+ return {
2381
+ error: {
2382
+ message: "Val is in development / local mode. Cannot generate summary"
2383
+ }
2384
+ };
2385
+ }
2373
2386
  async getStat(params) {
2374
2387
  // In ValOpsFS, we don't have a websocket server to listen to file changes so we use long-polling.
2375
2388
  // If a file that Val depends on changes, we break the connection and tell the client to request again to get the latest values.
@@ -2551,7 +2564,7 @@ class ValOpsFS extends ValOps {
2551
2564
  }
2552
2565
  patches[parsedPatch.data.patchId] = {
2553
2566
  ...parsedPatch.data,
2554
- appliedAt: parsedBase ? parsedBase.data : null
2567
+ appliedAt: null
2555
2568
  };
2556
2569
  }
2557
2570
  });
@@ -2571,17 +2584,9 @@ class ValOpsFS extends ValOps {
2571
2584
  return parentRef.type === "head" ? "head" : parentRef.patchId;
2572
2585
  }
2573
2586
  async fetchPatches(filters) {
2574
- const fetchPatchesRes = await this.fetchPatchesFromFS(!!filters.omitPatch);
2575
- const sortedPatches = this.createPatchChain(fetchPatchesRes.patches).filter(patchData => {
2576
- if (filters.authors && !(patchData.authorId === null || filters.authors.includes(patchData.authorId))) {
2577
- return false;
2578
- }
2579
- if (filters.moduleFilePaths && !filters.moduleFilePaths.includes(patchData.path)) {
2580
- return false;
2581
- }
2582
- return true;
2583
- }).map(patchData => {
2584
- if (filters.omitPatch) {
2587
+ const fetchPatchesRes = await this.fetchPatchesFromFS(!!filters.excludePatchOps);
2588
+ const sortedPatches = this.createPatchChain(fetchPatchesRes.patches).map(patchData => {
2589
+ if (filters.excludePatchOps) {
2585
2590
  return {
2586
2591
  ...patchData,
2587
2592
  patch: undefined
@@ -2594,7 +2599,7 @@ class ValOpsFS extends ValOps {
2594
2599
  errors: fetchPatchesRes.errors
2595
2600
  };
2596
2601
  }
2597
- async fetchPatchesFromFS(omitPath) {
2602
+ async fetchPatchesFromFS(excludePatchOps) {
2598
2603
  const patches = {};
2599
2604
  const {
2600
2605
  errors,
@@ -2603,7 +2608,7 @@ class ValOpsFS extends ValOps {
2603
2608
  for (const [patchIdS, patch] of Object.entries(allPatches)) {
2604
2609
  const patchId = patchIdS;
2605
2610
  patches[patchId] = {
2606
- patch: omitPath ? undefined : patch.patch,
2611
+ patch: excludePatchOps ? undefined : patch.patch,
2607
2612
  parentRef: patch.parentRef,
2608
2613
  path: patch.path,
2609
2614
  baseSha: patch.baseSha,
@@ -3197,7 +3202,7 @@ const textEncoder = new TextEncoder();
3197
3202
  const PatchId = zod.z.string().refine(s => !!s); // TODO: validate
3198
3203
  const CommitSha = zod.z.string().refine(s => !!s); // TODO: validate
3199
3204
  zod.z.string().refine(s => !!s); // TODO: validate
3200
- const AuthorId = zod.z.string().refine(s => !!s); // TODO: validate
3205
+ zod.z.string().refine(s => !!s); // TODO: validate
3201
3206
  const ModuleFilePath = zod.z.string().refine(s => !!s); // TODO: validate
3202
3207
  const Metadata = zod.z.union([zod.z.object({
3203
3208
  mimeType: zod.z.string(),
@@ -3211,20 +3216,28 @@ const MetadataRes = zod.z.object({
3211
3216
  metadata: Metadata,
3212
3217
  type: zod.z.union([zod.z.literal("file"), zod.z.literal("image")]).nullable()
3213
3218
  });
3214
- const BasePatchResponse = zod.z.object({
3215
- path: ModuleFilePath,
3216
- patchId: PatchId,
3217
- authorId: AuthorId.nullable(),
3218
- createdAt: zod.z.string().datetime(),
3219
- baseSha: zod.z.string()
3219
+ const SummaryResponse = zod.z.object({
3220
+ commitSummary: zod.z.string().nullable()
3220
3221
  });
3221
- const GetPatches = zod.z.object({
3222
- patches: zod.z.array(zod.z.intersection(zod.z.object({
3223
- patch: internal.Patch.optional()
3224
- }), BasePatchResponse)),
3225
- errors: zod.z.array(zod.z.object({
3226
- patchId: PatchId.optional(),
3227
- message: zod.z.string()
3222
+ const GetApplicablePatches = zod.z.object({
3223
+ patches: zod.z.array(zod.z.object({
3224
+ path: zod.z.string(),
3225
+ patch: internal.Patch.nullable(),
3226
+ patchId: zod.z.string(),
3227
+ authorId: zod.z.string().nullable(),
3228
+ baseSha: zod.z.string(),
3229
+ createdAt: zod.z.string(),
3230
+ applied: zod.z.object({
3231
+ commitSha: zod.z.string()
3232
+ }).nullable()
3233
+ })),
3234
+ commits: zod.z.array(zod.z.object({
3235
+ commitSha: zod.z.string(),
3236
+ clientCommitSha: zod.z.string(),
3237
+ parentCommitSha: zod.z.string(),
3238
+ branch: zod.z.string(),
3239
+ creator: zod.z.string(),
3240
+ createdAt: zod.z.string()
3228
3241
  })).optional()
3229
3242
  });
3230
3243
  const FilesResponse = zod.z.object({
@@ -3261,7 +3274,7 @@ const DeletePatchesResponse = zod.z.object({
3261
3274
  patchId: PatchId
3262
3275
  })).optional()
3263
3276
  });
3264
- zod.z.object({
3277
+ const SavePatchFileResponse = zod.z.object({
3265
3278
  patchId: PatchId,
3266
3279
  filePath: ModuleFilePath
3267
3280
  });
@@ -3280,11 +3293,11 @@ const ProfilesResponse = zod.z.object({
3280
3293
  }))
3281
3294
  });
3282
3295
  class ValOpsHttp extends ValOps {
3283
- constructor(hostUrl, project, commitSha,
3296
+ constructor(contentUrl, project, commitSha,
3284
3297
  // TODO: CommitSha
3285
3298
  branch, apiKey, valModules, options) {
3286
3299
  super(valModules, options);
3287
- this.hostUrl = hostUrl;
3300
+ this.contentUrl = contentUrl;
3288
3301
  this.project = project;
3289
3302
  this.commitSha = commitSha;
3290
3303
  this.branch = branch;
@@ -3296,6 +3309,70 @@ class ValOpsHttp extends ValOps {
3296
3309
  async onInit() {
3297
3310
  // TODO: unused for now. Implement or remove
3298
3311
  }
3312
+ async getCommitSummary(preparedCommit) {
3313
+ try {
3314
+ var _res$headers$get;
3315
+ const res = await fetch(`${this.contentUrl}/v1/${this.project}/commit-summary`, {
3316
+ method: "POST",
3317
+ headers: {
3318
+ ...this.authHeaders,
3319
+ "Content-Type": "application/json"
3320
+ },
3321
+ body: JSON.stringify({
3322
+ patchedSourceFiles: preparedCommit.patchedSourceFiles,
3323
+ previousSourceFiles: preparedCommit.previousSourceFiles
3324
+ })
3325
+ });
3326
+ if (res.ok) {
3327
+ const json = await res.json();
3328
+ const parsed = SummaryResponse.safeParse(json);
3329
+ if (parsed.success) {
3330
+ return {
3331
+ commitSummary: parsed.data.commitSummary
3332
+ };
3333
+ }
3334
+ console.error(`Could not parse summary response. Error: ${zodValidationError.fromError(parsed.error).toString()}`);
3335
+ return {
3336
+ error: {
3337
+ 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.`
3338
+ }
3339
+ };
3340
+ }
3341
+ if (res.status === 401) {
3342
+ console.error("Unauthorized to get summary");
3343
+ return {
3344
+ error: {
3345
+ 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."
3346
+ }
3347
+ };
3348
+ }
3349
+ const unknownErrorMessage = `Could not get summary. HTTP error: ${res.status} ${res.statusText}`;
3350
+ if ((_res$headers$get = res.headers.get("Content-Type")) !== null && _res$headers$get !== void 0 && _res$headers$get.includes("application/json")) {
3351
+ const json = await res.json();
3352
+ if (json.message) {
3353
+ console.error("Summary error:", json.message);
3354
+ return {
3355
+ error: {
3356
+ message: json.message
3357
+ }
3358
+ };
3359
+ }
3360
+ }
3361
+ console.error(unknownErrorMessage);
3362
+ return {
3363
+ error: {
3364
+ message: unknownErrorMessage
3365
+ }
3366
+ };
3367
+ } catch (e) {
3368
+ console.error("Could not get summary (connection error?):", e);
3369
+ return {
3370
+ error: {
3371
+ message: `Could not get summary. Error: ${e instanceof Error ? e.message : JSON.stringify(e)}`
3372
+ }
3373
+ };
3374
+ }
3375
+ }
3299
3376
  async getStat(params) {
3300
3377
  if (!(params !== null && params !== void 0 && params.profileId)) {
3301
3378
  return {
@@ -3308,11 +3385,23 @@ class ValOpsHttp extends ValOps {
3308
3385
  const currentBaseSha = await this.getBaseSha();
3309
3386
  const currentSchemaSha = await this.getSchemaSha();
3310
3387
  const allPatchData = await this.fetchPatches({
3311
- omitPatch: true,
3312
- authors: undefined,
3313
- patchIds: undefined,
3314
- moduleFilePaths: undefined
3388
+ excludePatchOps: true,
3389
+ patchIds: undefined
3315
3390
  });
3391
+ if ("error" in allPatchData && allPatchData.error && allPatchData.unauthorized) {
3392
+ return {
3393
+ type: "error",
3394
+ error: allPatchData.error,
3395
+ unauthorized: true
3396
+ };
3397
+ }
3398
+ if ("error" in allPatchData && allPatchData.error && allPatchData.networkError) {
3399
+ return {
3400
+ type: "error",
3401
+ error: allPatchData.error,
3402
+ networkError: true
3403
+ };
3404
+ }
3316
3405
  // We think these errors will be picked up else where (?), so we only return an error here if there are no patches
3317
3406
  if (allPatchData.patches.length === 0) {
3318
3407
  let message;
@@ -3359,7 +3448,7 @@ class ValOpsHttp extends ValOps {
3359
3448
  };
3360
3449
  }
3361
3450
  async getWebSocketNonce(profileId) {
3362
- return fetch(`${this.hostUrl}/v1/${this.project}/websocket/nonces`, {
3451
+ return fetch(`${this.contentUrl}/v1/${this.project}/websocket/nonces`, {
3363
3452
  method: "POST",
3364
3453
  body: JSON.stringify({
3365
3454
  branch: this.branch,
@@ -3436,16 +3525,12 @@ class ValOpsHttp extends ValOps {
3436
3525
  if (patchIds === undefined || patchIds.length === 0) {
3437
3526
  return this.fetchPatchesInternal({
3438
3527
  patchIds: patchIds,
3439
- authors: filters.authors,
3440
- moduleFilePaths: filters.moduleFilePaths,
3441
- omitPatch: filters.omitPatch
3528
+ excludePatchOps: filters.excludePatchOps
3442
3529
  });
3443
3530
  }
3444
3531
  for (const res of await Promise.all(patchIdChunks.map(patchIdChunk => this.fetchPatchesInternal({
3445
3532
  patchIds: patchIdChunk,
3446
- authors: filters.authors,
3447
- moduleFilePaths: filters.moduleFilePaths,
3448
- omitPatch: filters.omitPatch
3533
+ excludePatchOps: filters.excludePatchOps
3449
3534
  })))) {
3450
3535
  if ("error" in res) {
3451
3536
  return res;
@@ -3463,72 +3548,97 @@ class ValOpsHttp extends ValOps {
3463
3548
  async fetchPatchesInternal(filters) {
3464
3549
  const params = [];
3465
3550
  params.push(["branch", this.branch]);
3551
+ params.push(["commit", this.commitSha]);
3466
3552
  if (filters.patchIds) {
3467
3553
  for (const patchId of filters.patchIds) {
3468
3554
  params.push(["patch_id", patchId]);
3469
3555
  }
3470
3556
  }
3471
- if (filters.authors) {
3472
- for (const author of filters.authors) {
3473
- params.push(["author_id", author]);
3474
- }
3475
- }
3476
- if (filters.omitPatch) {
3477
- params.push(["omit_patch", "true"]);
3478
- }
3479
- if (filters.moduleFilePaths) {
3480
- for (const moduleFilePath of filters.moduleFilePaths) {
3481
- params.push(["module_file_path", moduleFilePath]);
3482
- }
3557
+ if (filters.excludePatchOps) {
3558
+ params.push(["exclude_patch_ops", "true"]);
3483
3559
  }
3484
3560
  const searchParams = new URLSearchParams(params);
3485
- return fetch(`${this.hostUrl}/v1/${this.project}/patches${searchParams.size > 0 ? `?${searchParams.toString()}` : ""}`, {
3486
- headers: {
3487
- ...this.authHeaders,
3488
- "Content-Type": "application/json"
3489
- }
3490
- }).then(async res => {
3561
+ try {
3562
+ const patchesRes = await fetch(`${this.contentUrl}/v1/${this.project}/applicable/patches${searchParams.size > 0 ? `?${searchParams.toString()}` : ""}`, {
3563
+ headers: this.authHeaders
3564
+ });
3491
3565
  const patches = [];
3492
- if (res.ok) {
3493
- const json = await res.json();
3494
- const parsed = GetPatches.safeParse(json);
3566
+ if (patchesRes.ok) {
3567
+ const json = await patchesRes.json();
3568
+ const parsed = GetApplicablePatches.safeParse(json);
3495
3569
  if (parsed.success) {
3496
3570
  const errors = [];
3497
3571
  const data = parsed.data;
3498
3572
  for (const patchesRes of data.patches) {
3573
+ var _patchesRes$applied;
3499
3574
  patches.push({
3500
3575
  authorId: patchesRes.authorId,
3501
3576
  createdAt: patchesRes.createdAt,
3502
- appliedAt: null,
3503
3577
  patchId: patchesRes.patchId,
3504
3578
  path: patchesRes.path,
3505
3579
  baseSha: patchesRes.baseSha,
3506
- patch: filters.omitPatch ? undefined : patchesRes.patch
3580
+ patch: patchesRes.patch,
3581
+ appliedAt: (_patchesRes$applied = patchesRes.applied) !== null && _patchesRes$applied !== void 0 && _patchesRes$applied.commitSha ? {
3582
+ commitSha: patchesRes.applied.commitSha
3583
+ } : null
3507
3584
  });
3508
3585
  }
3586
+ const commits = [];
3587
+ if (data.commits) {
3588
+ for (const commit of data.commits) {
3589
+ commits.push({
3590
+ commitSha: commit.commitSha,
3591
+ clientCommitSha: commit.clientCommitSha,
3592
+ parentCommitSha: commit.parentCommitSha,
3593
+ branch: commit.branch,
3594
+ creator: commit.creator,
3595
+ createdAt: commit.createdAt
3596
+ });
3597
+ }
3598
+ }
3509
3599
  return {
3600
+ commits,
3510
3601
  patches,
3511
3602
  errors
3512
3603
  };
3513
3604
  }
3605
+ console.error("Could not parse patches response. Error: " + zodValidationError.fromError(parsed.error));
3606
+ return {
3607
+ patches,
3608
+ error: {
3609
+ 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.`
3610
+ }
3611
+ };
3612
+ }
3613
+ console.error("Could not get patches. HTTP error: " + patchesRes.status + " " + patchesRes.statusText);
3614
+ if (patchesRes.status === 401) {
3514
3615
  return {
3515
3616
  patches,
3516
3617
  error: {
3517
- message: `Could not parse get patches response. Error: ${zodValidationError.fromError(parsed.error)}`
3618
+ 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."
3518
3619
  }
3519
3620
  };
3520
3621
  }
3521
3622
  return {
3522
3623
  patches,
3523
3624
  error: {
3524
- message: "Could not get patches. HTTP error: " + res.status + " " + res.statusText
3625
+ message: "Could not your changes. It is most likely due to a network issue. Check your network connection and please try again."
3525
3626
  }
3526
3627
  };
3527
- });
3628
+ } catch (err) {
3629
+ console.error("Could not get patches (connection error):", err instanceof Error ? err.message : JSON.stringify(err));
3630
+ return {
3631
+ patches: [],
3632
+ networkError: true,
3633
+ error: {
3634
+ message: `Error: ${err instanceof Error ? err.message : JSON.stringify(err)}`
3635
+ }
3636
+ };
3637
+ }
3528
3638
  }
3529
3639
  async saveSourceFilePatch(path, patch, parentRef, authorId) {
3530
3640
  const baseSha = await this.getBaseSha();
3531
- return fetch(`${this.hostUrl}/v1/${this.project}/patches`, {
3641
+ return fetch(`${this.contentUrl}/v1/${this.project}/patches`, {
3532
3642
  method: "POST",
3533
3643
  headers: {
3534
3644
  ...this.authHeaders,
@@ -3545,7 +3655,7 @@ class ValOpsHttp extends ValOps {
3545
3655
  coreVersion: core.Internal.VERSION.core
3546
3656
  })
3547
3657
  }).then(async res => {
3548
- var _res$headers$get;
3658
+ var _res$headers$get2;
3549
3659
  if (res.ok) {
3550
3660
  const parsed = SavePatchResponse.safeParse(await res.json());
3551
3661
  if (parsed.success) {
@@ -3564,7 +3674,7 @@ class ValOpsHttp extends ValOps {
3564
3674
  message: "Conflict: " + (await res.text())
3565
3675
  });
3566
3676
  }
3567
- if ((_res$headers$get = res.headers.get("Content-Type")) !== null && _res$headers$get !== void 0 && _res$headers$get.includes("application/json")) {
3677
+ if ((_res$headers$get2 = res.headers.get("Content-Type")) !== null && _res$headers$get2 !== void 0 && _res$headers$get2.includes("application/json")) {
3568
3678
  const json = await res.json();
3569
3679
  return fp.result.err({
3570
3680
  errorType: "other",
@@ -3583,7 +3693,45 @@ class ValOpsHttp extends ValOps {
3583
3693
  });
3584
3694
  }
3585
3695
  async saveBase64EncodedBinaryFileFromPatch(filePath, parentRef, patchId, data, type, metadata) {
3586
- throw Error("TODO: implement");
3696
+ return fetch(`${this.contentUrl}/v1/${this.project}/patches/${patchId}/files`, {
3697
+ method: "POST",
3698
+ headers: {
3699
+ ...this.authHeaders,
3700
+ "Content-Type": "application/json"
3701
+ },
3702
+ body: JSON.stringify({
3703
+ filePath: filePath,
3704
+ data,
3705
+ type,
3706
+ metadata
3707
+ })
3708
+ }).then(async res => {
3709
+ if (res.ok) {
3710
+ const parsed = SavePatchFileResponse.safeParse(await res.json());
3711
+ if (parsed.success) {
3712
+ return {
3713
+ patchId: parsed.data.patchId,
3714
+ filePath: parsed.data.filePath
3715
+ };
3716
+ }
3717
+ return {
3718
+ error: {
3719
+ message: `Could not parse save patch file response. Error: ${zodValidationError.fromError(parsed.error)}`
3720
+ }
3721
+ };
3722
+ }
3723
+ return {
3724
+ error: {
3725
+ message: "Could not save patch file. HTTP error: " + res.status + " " + res.statusText
3726
+ }
3727
+ };
3728
+ }).catch(e => {
3729
+ return {
3730
+ error: {
3731
+ message: `Could save source binary file in patch (connection error?): ${e.toString()}`
3732
+ }
3733
+ };
3734
+ });
3587
3735
  }
3588
3736
  async getHttpFiles(files) {
3589
3737
  const params = new URLSearchParams();
@@ -3594,7 +3742,7 @@ class ValOpsHttp extends ValOps {
3594
3742
  params.set("body_sha",
3595
3743
  // We use this for cache invalidation
3596
3744
  core.Internal.getSHA256Hash(textEncoder.encode(stringifiedFiles)));
3597
- return fetch(`${this.hostUrl}/v1/${this.project}/files?${params}`, {
3745
+ return fetch(`${this.contentUrl}/v1/${this.project}/files?${params}`, {
3598
3746
  method: "PUT",
3599
3747
  // Yes, PUT is weird. Weirder to have a body in a GET request.
3600
3748
  headers: {
@@ -3687,7 +3835,7 @@ class ValOpsHttp extends ValOps {
3687
3835
  const params = new URLSearchParams();
3688
3836
  params.set("file_path", filePath);
3689
3837
  try {
3690
- const metadataRes = await fetch(`${this.hostUrl}/v1/${this.project}/patches/${patchId}/files?${params}`, {
3838
+ const metadataRes = await fetch(`${this.contentUrl}/v1/${this.project}/patches/${patchId}/files?${params}`, {
3691
3839
  headers: {
3692
3840
  ...this.authHeaders,
3693
3841
  "Content-Type": "application/json"
@@ -3741,7 +3889,7 @@ class ValOpsHttp extends ValOps {
3741
3889
  };
3742
3890
  }
3743
3891
  async deletePatches(patchIds) {
3744
- return fetch(`${this.hostUrl}/v1/${this.project}/patches`, {
3892
+ return fetch(`${this.contentUrl}/v1/${this.project}/patches`, {
3745
3893
  method: "DELETE",
3746
3894
  headers: {
3747
3895
  ...this.authHeaders,
@@ -3787,11 +3935,44 @@ class ValOpsHttp extends ValOps {
3787
3935
  };
3788
3936
  });
3789
3937
  }
3790
- async commit(prepared, message, committer, newBranch) {
3938
+ async getCommitMessage(preparedCommit) {
3939
+ var _res$headers$get3;
3940
+ const res = await fetch(`${this.contentUrl}/v1/${this.project}/commit-summary`, {
3941
+ method: "POST",
3942
+ headers: {
3943
+ ...this.authHeaders,
3944
+ "Content-Type": "application/json"
3945
+ },
3946
+ body: JSON.stringify({
3947
+ patchedSourceFiles: preparedCommit.patchedSourceFiles,
3948
+ previousSourceFiles: preparedCommit.previousSourceFiles
3949
+ })
3950
+ });
3951
+ if (res.ok) {
3952
+ const json = await res.json();
3953
+ return {
3954
+ commitSummary: json.commitSummary
3955
+ };
3956
+ }
3957
+ if ((_res$headers$get3 = res.headers.get("Content-Type")) !== null && _res$headers$get3 !== void 0 && _res$headers$get3.includes("application/json")) {
3958
+ const json = await res.json();
3959
+ return {
3960
+ error: {
3961
+ message: json.message
3962
+ }
3963
+ };
3964
+ }
3965
+ return {
3966
+ error: {
3967
+ message: "Could not get commit message. HTTP error: " + res.status + " " + res.statusText
3968
+ }
3969
+ };
3970
+ }
3971
+ async commit(prepared, message, committer, filesDirectory, newBranch) {
3791
3972
  try {
3792
- var _res$headers$get2;
3973
+ var _res$headers$get4;
3793
3974
  const existingBranch = this.branch;
3794
- const res = await fetch(`${this.hostUrl}/v1/${this.project}/commit`, {
3975
+ const res = await fetch(`${this.contentUrl}/v1/${this.project}/commit`, {
3795
3976
  method: "POST",
3796
3977
  headers: {
3797
3978
  ...this.authHeaders,
@@ -3803,6 +3984,7 @@ class ValOpsHttp extends ValOps {
3803
3984
  appliedPatches: prepared.appliedPatches,
3804
3985
  commit: this.commitSha,
3805
3986
  root: this.root,
3987
+ filesDirectory,
3806
3988
  baseSha: await this.getBaseSha(),
3807
3989
  committer,
3808
3990
  message,
@@ -3825,7 +4007,7 @@ class ValOpsHttp extends ValOps {
3825
4007
  }
3826
4008
  };
3827
4009
  }
3828
- if ((_res$headers$get2 = res.headers.get("Content-Type")) !== null && _res$headers$get2 !== void 0 && _res$headers$get2.includes("application/json")) {
4010
+ if ((_res$headers$get4 = res.headers.get("Content-Type")) !== null && _res$headers$get4 !== void 0 && _res$headers$get4.includes("application/json")) {
3829
4011
  const json = await res.json();
3830
4012
  if (json.isNotFastForward) {
3831
4013
  return {
@@ -3857,8 +4039,8 @@ class ValOpsHttp extends ValOps {
3857
4039
 
3858
4040
  // #region profiles
3859
4041
  async getProfiles() {
3860
- var _res$headers$get3;
3861
- const res = await fetch(`${this.hostUrl}/v1/${this.project}/profiles`, {
4042
+ var _res$headers$get5;
4043
+ const res = await fetch(`${this.contentUrl}/v1/${this.project}/profiles`, {
3862
4044
  headers: {
3863
4045
  ...this.authHeaders,
3864
4046
  "Content-Type": "application/json"
@@ -3872,7 +4054,7 @@ class ValOpsHttp extends ValOps {
3872
4054
  }
3873
4055
  return parsed.data.profiles;
3874
4056
  }
3875
- if ((_res$headers$get3 = res.headers.get("Content-Type")) !== null && _res$headers$get3 !== void 0 && _res$headers$get3.includes("application/json")) {
4057
+ if ((_res$headers$get5 = res.headers.get("Content-Type")) !== null && _res$headers$get5 !== void 0 && _res$headers$get5.includes("application/json")) {
3876
4058
  const json = await res.json();
3877
4059
  throw Error(`Could not get profiles (status: ${res.status}): ${"message" in json ? json.message : "Unknown error"}`);
3878
4060
  }
@@ -3910,6 +4092,7 @@ const ValServer = (valModules, options, callbacks) => {
3910
4092
  url.searchParams.set("state", token);
3911
4093
  return url.toString();
3912
4094
  };
4095
+ const commit = options.mode === "http" ? options.commit : undefined;
3913
4096
  const getAppErrorUrl = error => {
3914
4097
  if (!options.project) {
3915
4098
  throw new Error("Project is not set");
@@ -4372,6 +4555,22 @@ const ValServer = (valModules, options, callbacks) => {
4372
4555
  ...req.body,
4373
4556
  profileId: "id" in auth ? auth.id : undefined
4374
4557
  });
4558
+ if (currentStat.type === "error" && currentStat.networkError) {
4559
+ return {
4560
+ status: 503,
4561
+ json: {
4562
+ message: "Network error"
4563
+ }
4564
+ };
4565
+ }
4566
+ if (currentStat.type === "error" && currentStat.unauthorized) {
4567
+ return {
4568
+ status: 401,
4569
+ json: {
4570
+ message: "Unauthorized"
4571
+ }
4572
+ };
4573
+ }
4375
4574
  if (currentStat.type === "error") {
4376
4575
  return {
4377
4576
  status: 500,
@@ -4382,6 +4581,7 @@ const ValServer = (valModules, options, callbacks) => {
4382
4581
  status: 200,
4383
4582
  json: {
4384
4583
  ...currentStat,
4584
+ mode: serverOps instanceof ValOpsFS ? "fs" : serverOps instanceof ValOpsHttp ? "http" : "unknown",
4385
4585
  config: options.config
4386
4586
  }
4387
4587
  };
@@ -4409,7 +4609,7 @@ const ValServer = (valModules, options, callbacks) => {
4409
4609
  };
4410
4610
  }
4411
4611
  const patches = req.body.patches;
4412
- const parentRef = req.body.parentRef;
4612
+ let parentRef = req.body.parentRef;
4413
4613
  const authorId = "id" in auth ? auth.id : null;
4414
4614
  const newPatchIds = [];
4415
4615
  for (const patch of patches) {
@@ -4440,6 +4640,10 @@ const ValServer = (valModules, options, callbacks) => {
4440
4640
  };
4441
4641
  }
4442
4642
  } else {
4643
+ parentRef = {
4644
+ type: "patch",
4645
+ patchId: createPatchRes.value.patchId
4646
+ };
4443
4647
  newPatchIds.push(createPatchRes.value.patchId);
4444
4648
  }
4445
4649
  }
@@ -4447,10 +4651,7 @@ const ValServer = (valModules, options, callbacks) => {
4447
4651
  status: 200,
4448
4652
  json: {
4449
4653
  newPatchIds,
4450
- parentRef: {
4451
- type: "patch",
4452
- patchId: newPatchIds[newPatchIds.length - 1]
4453
- }
4654
+ parentRef
4454
4655
  }
4455
4656
  };
4456
4657
  },
@@ -4475,13 +4676,10 @@ const ValServer = (valModules, options, callbacks) => {
4475
4676
  }
4476
4677
  };
4477
4678
  }
4478
- const omit_patch = query.omit_patch === true;
4479
- const authors = query.author;
4679
+ const excludePatchOps = query.exclude_patch_ops === true;
4480
4680
  const fetchedPatchesRes = await serverOps.fetchPatches({
4481
- authors,
4482
4681
  patchIds: query.patch_id,
4483
- omitPatch: omit_patch,
4484
- moduleFilePaths: query.module_file_path
4682
+ excludePatchOps: excludePatchOps
4485
4683
  });
4486
4684
  if (fetchedPatchesRes.error) {
4487
4685
  // Error is singular
@@ -4662,8 +4860,17 @@ const ValServer = (valModules, options, callbacks) => {
4662
4860
  }
4663
4861
  const patchOps = await serverOps.fetchPatches({
4664
4862
  patchIds: undefined,
4665
- omitPatch: false
4863
+ excludePatchOps: false
4666
4864
  });
4865
+ // We check authorization here, because it is the first call to the backend
4866
+ if (patchOps.error && patchOps.unauthorized) {
4867
+ return {
4868
+ status: 401,
4869
+ json: {
4870
+ message: "Unauthorized"
4871
+ }
4872
+ };
4873
+ }
4667
4874
  const patchAnalysis = serverOps.analyzePatches(patchOps.patches);
4668
4875
  let sourcesRes = await serverOps.getSources();
4669
4876
  const onlyPatchedTreeModules = await serverOps.getSources({
@@ -4742,17 +4949,16 @@ const ValServer = (valModules, options, callbacks) => {
4742
4949
  },
4743
4950
  "/profiles": {
4744
4951
  GET: async req => {
4745
- // const cookies = req.cookies;
4746
- // const auth = getAuth(cookies);
4747
- // if (auth.error) {
4748
- // return {
4749
- // status: 401,
4750
- // json: {
4751
- // message: auth.error,
4752
- // },
4753
- // };
4754
- // }
4755
-
4952
+ const cookies = req.cookies;
4953
+ const auth = getAuth(cookies);
4954
+ if (auth.error) {
4955
+ return {
4956
+ status: 401,
4957
+ json: {
4958
+ message: auth.error
4959
+ }
4960
+ };
4961
+ }
4756
4962
  const profiles = await serverOps.getProfiles();
4757
4963
  return {
4758
4964
  status: 200,
@@ -4762,6 +4968,49 @@ const ValServer = (valModules, options, callbacks) => {
4762
4968
  };
4763
4969
  }
4764
4970
  },
4971
+ "/commit-summary": {
4972
+ GET: async req => {
4973
+ const cookies = req.cookies;
4974
+ const auth = getAuth(cookies);
4975
+ if (auth.error) {
4976
+ return {
4977
+ status: 401,
4978
+ json: {
4979
+ message: auth.error
4980
+ }
4981
+ };
4982
+ }
4983
+ const query = req.query;
4984
+ const patchIds = query.patch_id;
4985
+ const patches = await serverOps.fetchPatches({
4986
+ patchIds,
4987
+ excludePatchOps: false
4988
+ });
4989
+ const analysis = serverOps.analyzePatches(patches.patches, patches.commits, commit);
4990
+ const preparedCommit = await serverOps.prepare({
4991
+ ...analysis,
4992
+ ...patches
4993
+ });
4994
+ const res = await serverOps.getCommitSummary(preparedCommit);
4995
+ if (res.error) {
4996
+ console.error("Failed to summarize", res.error);
4997
+ return {
4998
+ status: 400,
4999
+ json: {
5000
+ message: res.error.message
5001
+ }
5002
+ };
5003
+ }
5004
+ return {
5005
+ status: 200,
5006
+ json: {
5007
+ baseSha: await serverOps.getBaseSha(),
5008
+ patchIds,
5009
+ commitSummary: res.commitSummary
5010
+ }
5011
+ };
5012
+ }
5013
+ },
4765
5014
  "/save": {
4766
5015
  POST: async req => {
4767
5016
  const cookies = req.cookies;
@@ -4794,9 +5043,9 @@ const ValServer = (valModules, options, callbacks) => {
4794
5043
  } = bodyRes.data;
4795
5044
  const patches = await serverOps.fetchPatches({
4796
5045
  patchIds,
4797
- omitPatch: false
5046
+ excludePatchOps: false
4798
5047
  });
4799
- const analysis = serverOps.analyzePatches(patches.patches);
5048
+ const analysis = serverOps.analyzePatches(patches.patches, patches.commits, commit);
4800
5049
  const preparedCommit = await serverOps.prepare({
4801
5050
  ...analysis,
4802
5051
  ...patches
@@ -4828,7 +5077,24 @@ const ValServer = (valModules, options, callbacks) => {
4828
5077
  };
4829
5078
  } else if (serverOps instanceof ValOpsHttp) {
4830
5079
  if (auth.error === undefined && auth.id) {
4831
- const commitRes = await serverOps.commit(preparedCommit, "Update content: " + Object.keys(analysis.patchesByModule) + " modules changed", auth.id);
5080
+ var _options$config$ai, _options$config$files;
5081
+ let message = body.message || "Update content: " + Object.keys(analysis.patchesByModule) + " modules changed";
5082
+ 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)) {
5083
+ const res = await serverOps.getCommitMessage(preparedCommit);
5084
+ console.log({
5085
+ res
5086
+ });
5087
+ if (res.error) {
5088
+ // ignore
5089
+ console.error("Failed to get commit message", res.error.message);
5090
+ } else {
5091
+ message = res.commitSummary;
5092
+ }
5093
+ }
5094
+ console.log({
5095
+ message
5096
+ });
5097
+ 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");
4832
5098
  if (commitRes.error) {
4833
5099
  console.error("Failed to commit", commitRes.error);
4834
5100
  if ("isNotFastForward" in commitRes && commitRes.isNotFastForward) {