@le-space/core 0.1.16 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/index.d.ts +14 -0
  2. package/index.js +151 -47
  3. package/package.json +2 -2
package/index.d.ts CHANGED
@@ -334,6 +334,20 @@ declare function retainSuccessfulDeployments(args: {
334
334
  hash: string;
335
335
  result: Awaited<ReturnType<typeof forgetAlephMessages>>;
336
336
  }[];
337
+ forgetStageResults: {
338
+ stage: "instances" | "dependents";
339
+ hashes: string[];
340
+ skipped?: boolean;
341
+ skippedReason?: string;
342
+ forgottenHashes: string[];
343
+ outstandingForgetHashes: string[];
344
+ statuses: Record<string, string>;
345
+ forgetResult: Awaited<ReturnType<typeof forgetAlephMessages>> | null;
346
+ followUpForgetResults: Array<{
347
+ hash: string;
348
+ result: Awaited<ReturnType<typeof forgetAlephMessages>>;
349
+ }>;
350
+ }[];
337
351
  }>;
338
352
 
339
353
  declare function createPortForwardAggregateContent(args: {
package/index.js CHANGED
@@ -841,6 +841,26 @@ function retentionRecordId(record) {
841
841
  function hashesFromRetentionRecord(record) {
842
842
  return [record.instance_item_hash, record.rootfs_item_hash, record.site_item_hash].filter(Boolean);
843
843
  }
844
+ function uniqueHashes(hashes) {
845
+ return [...new Set(hashes.filter(Boolean))];
846
+ }
847
+ function dependentHashesFromRetentionRecord(record) {
848
+ return [record.rootfs_item_hash, record.site_item_hash].filter(Boolean);
849
+ }
850
+ function splitForgetStages(args) {
851
+ const instanceForgetHashes = uniqueHashes(args.prunedRecords.map((record) => record.instance_item_hash)).filter(
852
+ (hash) => !args.retainedHashes.has(hash)
853
+ );
854
+ const dependentForgetHashes = uniqueHashes([
855
+ ...args.prunedRecords.flatMap(dependentHashesFromRetentionRecord),
856
+ ...args.extraForgetHashes
857
+ ]).filter((hash) => !args.retainedHashes.has(hash) && !instanceForgetHashes.includes(hash));
858
+ return {
859
+ instanceForgetHashes,
860
+ dependentForgetHashes,
861
+ orderedForgetHashes: [...instanceForgetHashes, ...dependentForgetHashes]
862
+ };
863
+ }
844
864
  async function fetchAggregateKey(args) {
845
865
  const requestUrl = new URL(`/api/v0/aggregates/${args.address}.json`, args.apiHost ?? "https://api2.aleph.im");
846
866
  requestUrl.searchParams.set("keys", args.key);
@@ -918,6 +938,73 @@ async function classifyForgetHashes(args) {
918
938
  statuses
919
939
  };
920
940
  }
941
+ async function executeForgetStage(args) {
942
+ const stageHashes = uniqueHashes(args.hashes);
943
+ let forgetResult = null;
944
+ const followUpForgetResults = [];
945
+ if (stageHashes.length === 0) {
946
+ return {
947
+ hashes: stageHashes,
948
+ forgottenHashes: [],
949
+ outstandingForgetHashes: [],
950
+ statuses: {},
951
+ forgetResult,
952
+ followUpForgetResults
953
+ };
954
+ }
955
+ let classified = await classifyForgetHashes({
956
+ hashes: stageHashes,
957
+ fetch: args.fetch,
958
+ apiHost: args.apiHost
959
+ });
960
+ if (classified.outstandingForgetHashes.length > 0) {
961
+ forgetResult = await forgetAlephMessages({
962
+ sender: args.sender,
963
+ hashes: classified.outstandingForgetHashes,
964
+ reason: args.reason,
965
+ signer: args.signer,
966
+ hasher: args.hasher,
967
+ fetch: args.fetch,
968
+ channel: args.channel,
969
+ apiHost: args.apiHost,
970
+ now: args.now
971
+ });
972
+ classified = await classifyForgetHashes({
973
+ hashes: stageHashes,
974
+ fetch: args.fetch,
975
+ apiHost: args.apiHost
976
+ });
977
+ if (classified.outstandingForgetHashes.length > 0) {
978
+ for (const hash of classified.outstandingForgetHashes) {
979
+ const result = await forgetAlephMessages({
980
+ sender: args.sender,
981
+ hashes: [hash],
982
+ reason: args.reason,
983
+ signer: args.signer,
984
+ hasher: args.hasher,
985
+ fetch: args.fetch,
986
+ channel: args.channel,
987
+ apiHost: args.apiHost,
988
+ now: args.now
989
+ });
990
+ followUpForgetResults.push({ hash, result });
991
+ }
992
+ classified = await classifyForgetHashes({
993
+ hashes: stageHashes,
994
+ fetch: args.fetch,
995
+ apiHost: args.apiHost
996
+ });
997
+ }
998
+ }
999
+ return {
1000
+ hashes: stageHashes,
1001
+ forgottenHashes: classified.forgottenHashes,
1002
+ outstandingForgetHashes: classified.outstandingForgetHashes,
1003
+ statuses: classified.statuses,
1004
+ forgetResult,
1005
+ followUpForgetResults
1006
+ };
1007
+ }
921
1008
  async function retainSuccessfulDeployments(args) {
922
1009
  const keepCount = Math.max(0, Number.parseInt(String(args.keepCount ?? 0), 10) || 0);
923
1010
  const aggregateKey = asString3(args.aggregateKey) ?? SUCCESSFUL_DEPLOYMENTS_AGGREGATE_KEY;
@@ -944,10 +1031,13 @@ async function retainSuccessfulDeployments(args) {
944
1031
  const retainedRecords = keepCount > 0 ? uniqueRecords.slice(0, keepCount) : [];
945
1032
  const prunedRecords = keepCount > 0 ? uniqueRecords.slice(keepCount) : uniqueRecords;
946
1033
  const retainedHashes = new Set(retainedRecords.flatMap(hashesFromRetentionRecord));
947
- const extraForgetHashes = [...new Set((args.extraForgetHashes ?? []).filter(Boolean))];
948
- const forgetHashes = [.../* @__PURE__ */ new Set([...prunedRecords.flatMap(hashesFromRetentionRecord), ...extraForgetHashes])].filter(
949
- (hash) => !retainedHashes.has(hash)
950
- );
1034
+ const extraForgetHashes = uniqueHashes(args.extraForgetHashes ?? []);
1035
+ const { instanceForgetHashes, dependentForgetHashes, orderedForgetHashes } = splitForgetStages({
1036
+ prunedRecords,
1037
+ extraForgetHashes,
1038
+ retainedHashes
1039
+ });
1040
+ const forgetHashes = orderedForgetHashes;
951
1041
  const aggregateContent = {
952
1042
  keep: keepCount,
953
1043
  updated_at: (/* @__PURE__ */ new Date()).toISOString(),
@@ -964,25 +1054,40 @@ async function retainSuccessfulDeployments(args) {
964
1054
  apiHost: args.apiHost,
965
1055
  now: args.now
966
1056
  });
967
- let forgetResult = null;
968
- let followUpForgetResults = [];
1057
+ const forgetReason = args.reason ?? `Prune successful deployments beyond retention limit ${keepCount}`;
1058
+ const forgetStageResults = [];
969
1059
  let forgottenHashes = [];
970
1060
  let outstandingForgetHashes = [];
971
1061
  let forgetStatuses = {};
972
- if (forgetHashes.length > 0) {
973
- const initiallyOutstanding = await classifyForgetHashes({
974
- hashes: forgetHashes,
1062
+ let forgetResult = null;
1063
+ const followUpForgetResults = [];
1064
+ if (instanceForgetHashes.length > 0) {
1065
+ const instanceStage = await executeForgetStage({
1066
+ sender: args.sender,
1067
+ hashes: instanceForgetHashes,
1068
+ reason: forgetReason,
1069
+ signer: args.signer,
1070
+ hasher: args.hasher,
975
1071
  fetch: args.fetch,
976
- apiHost: args.apiHost
1072
+ channel: args.channel,
1073
+ apiHost: args.apiHost,
1074
+ now: args.now
977
1075
  });
978
- forgottenHashes = initiallyOutstanding.forgottenHashes;
979
- outstandingForgetHashes = initiallyOutstanding.outstandingForgetHashes;
980
- forgetStatuses = initiallyOutstanding.statuses;
981
- if (outstandingForgetHashes.length > 0) {
982
- forgetResult = await forgetAlephMessages({
1076
+ forgetStageResults.push({ stage: "instances", ...instanceStage });
1077
+ forgottenHashes.push(...instanceStage.forgottenHashes);
1078
+ outstandingForgetHashes.push(...instanceStage.outstandingForgetHashes);
1079
+ forgetStatuses = { ...forgetStatuses, ...instanceStage.statuses };
1080
+ if (!forgetResult && instanceStage.forgetResult) {
1081
+ forgetResult = instanceStage.forgetResult;
1082
+ }
1083
+ followUpForgetResults.push(...instanceStage.followUpForgetResults);
1084
+ }
1085
+ if (dependentForgetHashes.length > 0) {
1086
+ if (outstandingForgetHashes.length === 0) {
1087
+ const dependentStage = await executeForgetStage({
983
1088
  sender: args.sender,
984
- hashes: outstandingForgetHashes,
985
- reason: args.reason ?? `Prune successful deployments beyond retention limit ${keepCount}`,
1089
+ hashes: dependentForgetHashes,
1090
+ reason: forgetReason,
986
1091
  signer: args.signer,
987
1092
  hasher: args.hasher,
988
1093
  fetch: args.fetch,
@@ -990,40 +1095,38 @@ async function retainSuccessfulDeployments(args) {
990
1095
  apiHost: args.apiHost,
991
1096
  now: args.now
992
1097
  });
993
- let postBatch = await classifyForgetHashes({
994
- hashes: forgetHashes,
1098
+ forgetStageResults.push({ stage: "dependents", ...dependentStage });
1099
+ forgottenHashes.push(...dependentStage.forgottenHashes);
1100
+ outstandingForgetHashes.push(...dependentStage.outstandingForgetHashes);
1101
+ forgetStatuses = { ...forgetStatuses, ...dependentStage.statuses };
1102
+ if (!forgetResult && dependentStage.forgetResult) {
1103
+ forgetResult = dependentStage.forgetResult;
1104
+ }
1105
+ followUpForgetResults.push(...dependentStage.followUpForgetResults);
1106
+ } else {
1107
+ const dependentStageStatus = await classifyForgetHashes({
1108
+ hashes: dependentForgetHashes,
995
1109
  fetch: args.fetch,
996
1110
  apiHost: args.apiHost
997
1111
  });
998
- forgottenHashes = postBatch.forgottenHashes;
999
- outstandingForgetHashes = postBatch.outstandingForgetHashes;
1000
- forgetStatuses = postBatch.statuses;
1001
- if (outstandingForgetHashes.length > 0) {
1002
- for (const hash of outstandingForgetHashes) {
1003
- const result = await forgetAlephMessages({
1004
- sender: args.sender,
1005
- hashes: [hash],
1006
- reason: args.reason ?? `Prune successful deployments beyond retention limit ${keepCount}`,
1007
- signer: args.signer,
1008
- hasher: args.hasher,
1009
- fetch: args.fetch,
1010
- channel: args.channel,
1011
- apiHost: args.apiHost,
1012
- now: args.now
1013
- });
1014
- followUpForgetResults.push({ hash, result });
1015
- }
1016
- postBatch = await classifyForgetHashes({
1017
- hashes: forgetHashes,
1018
- fetch: args.fetch,
1019
- apiHost: args.apiHost
1020
- });
1021
- forgottenHashes = postBatch.forgottenHashes;
1022
- outstandingForgetHashes = postBatch.outstandingForgetHashes;
1023
- forgetStatuses = postBatch.statuses;
1024
- }
1112
+ forgetStageResults.push({
1113
+ stage: "dependents",
1114
+ hashes: dependentForgetHashes,
1115
+ skipped: true,
1116
+ skippedReason: "Waiting for instance forget stage to complete before pruning dependent store items.",
1117
+ forgottenHashes: dependentStageStatus.forgottenHashes,
1118
+ outstandingForgetHashes: dependentStageStatus.outstandingForgetHashes,
1119
+ statuses: dependentStageStatus.statuses,
1120
+ forgetResult: null,
1121
+ followUpForgetResults: []
1122
+ });
1123
+ forgottenHashes.push(...dependentStageStatus.forgottenHashes);
1124
+ outstandingForgetHashes.push(...dependentStageStatus.outstandingForgetHashes);
1125
+ forgetStatuses = { ...forgetStatuses, ...dependentStageStatus.statuses };
1025
1126
  }
1026
1127
  }
1128
+ forgottenHashes = uniqueHashes(forgottenHashes);
1129
+ outstandingForgetHashes = uniqueHashes(outstandingForgetHashes);
1027
1130
  return {
1028
1131
  sender: args.sender,
1029
1132
  aggregateKey,
@@ -1036,7 +1139,8 @@ async function retainSuccessfulDeployments(args) {
1036
1139
  outstandingForgetHashes,
1037
1140
  forgetStatuses,
1038
1141
  forgetResult,
1039
- followUpForgetResults
1142
+ followUpForgetResults,
1143
+ forgetStageResults
1040
1144
  };
1041
1145
  }
1042
1146
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@le-space/core",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Reusable Aleph deployment, runtime, and guest lifecycle logic.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -16,6 +16,6 @@
16
16
  "access": "public"
17
17
  },
18
18
  "dependencies": {
19
- "@le-space/shared-types": "0.1.16"
19
+ "@le-space/shared-types": "0.1.18"
20
20
  }
21
21
  }