@ait-co/console-cli 0.1.15 → 0.1.16
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/dist/cli.mjs +130 -11
- package/dist/cli.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -1017,13 +1017,37 @@ var AitBundleError = class extends Error {
|
|
|
1017
1017
|
this.reason = args.reason;
|
|
1018
1018
|
}
|
|
1019
1019
|
};
|
|
1020
|
+
const AIT_MAGIC = new Uint8Array([
|
|
1021
|
+
65,
|
|
1022
|
+
73,
|
|
1023
|
+
84,
|
|
1024
|
+
66,
|
|
1025
|
+
85,
|
|
1026
|
+
78,
|
|
1027
|
+
68,
|
|
1028
|
+
76
|
|
1029
|
+
]);
|
|
1030
|
+
const ZIP_MAGIC = new Uint8Array([
|
|
1031
|
+
80,
|
|
1032
|
+
75,
|
|
1033
|
+
3,
|
|
1034
|
+
4
|
|
1035
|
+
]);
|
|
1036
|
+
function startsWith(bytes, prefix) {
|
|
1037
|
+
if (bytes.length < prefix.length) return false;
|
|
1038
|
+
for (let i = 0; i < prefix.length; i++) if (bytes[i] !== prefix[i]) return false;
|
|
1039
|
+
return true;
|
|
1040
|
+
}
|
|
1041
|
+
function detectBundleFormat(bytes) {
|
|
1042
|
+
if (startsWith(bytes, AIT_MAGIC)) return "ait";
|
|
1043
|
+
if (startsWith(bytes, ZIP_MAGIC)) return "zip";
|
|
1044
|
+
return "unknown";
|
|
1045
|
+
}
|
|
1020
1046
|
/**
|
|
1021
|
-
* Read the `.ait` at `path
|
|
1022
|
-
*
|
|
1023
|
-
*
|
|
1024
|
-
*
|
|
1025
|
-
* Errors are all surfaced as `AitBundleError` with a structured `reason`
|
|
1026
|
-
* so the command layer can render a typed `--json` failure.
|
|
1047
|
+
* Read the `.ait` at `path` and pull out `deploymentId`, auto-detecting
|
|
1048
|
+
* whether the file is the modern AIT header format or a legacy plain
|
|
1049
|
+
* zip. Returns the raw bytes so the caller can forward them to S3
|
|
1050
|
+
* without re-reading the file.
|
|
1027
1051
|
*/
|
|
1028
1052
|
async function readAitBundle(path) {
|
|
1029
1053
|
let buf;
|
|
@@ -1037,16 +1061,109 @@ async function readAitBundle(path) {
|
|
|
1037
1061
|
});
|
|
1038
1062
|
}
|
|
1039
1063
|
const bytes = new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
1064
|
+
const { deploymentId, format } = deploymentIdFromBundleBytes(bytes, path);
|
|
1040
1065
|
return {
|
|
1041
|
-
deploymentId
|
|
1042
|
-
bytes
|
|
1066
|
+
deploymentId,
|
|
1067
|
+
bytes,
|
|
1068
|
+
format
|
|
1043
1069
|
};
|
|
1044
1070
|
}
|
|
1045
1071
|
/**
|
|
1046
|
-
* Pure helper split out so tests can feed raw
|
|
1047
|
-
*
|
|
1072
|
+
* Pure helper split out so tests can feed raw bytes without a tmp file.
|
|
1073
|
+
* Throws `AitBundleError` on any parse failure. Returns the detected
|
|
1074
|
+
* format so callers that want to log it can.
|
|
1048
1075
|
*/
|
|
1049
1076
|
function deploymentIdFromBundleBytes(bytes, pathForError) {
|
|
1077
|
+
const format = detectBundleFormat(bytes);
|
|
1078
|
+
if (format === "ait") return {
|
|
1079
|
+
deploymentId: deploymentIdFromAitHeader(bytes, pathForError),
|
|
1080
|
+
format
|
|
1081
|
+
};
|
|
1082
|
+
if (format === "zip") return {
|
|
1083
|
+
deploymentId: deploymentIdFromLegacyZip(bytes, pathForError),
|
|
1084
|
+
format
|
|
1085
|
+
};
|
|
1086
|
+
throw new AitBundleError({
|
|
1087
|
+
path: pathForError,
|
|
1088
|
+
reason: "unrecognized-format",
|
|
1089
|
+
message: "bundle does not start with AITBUNDL or PK magic bytes — not a valid .ait or legacy zip bundle"
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
const AIT_MAGIC_SIZE = 8;
|
|
1093
|
+
const AIT_VERSION_SIZE = 4;
|
|
1094
|
+
const AIT_HEADER_SIZE = AIT_MAGIC_SIZE + AIT_VERSION_SIZE + 8;
|
|
1095
|
+
function deploymentIdFromAitHeader(bytes, pathForError) {
|
|
1096
|
+
if (bytes.length < AIT_HEADER_SIZE) throw new AitBundleError({
|
|
1097
|
+
path: pathForError,
|
|
1098
|
+
reason: "invalid-ait",
|
|
1099
|
+
message: "buffer too small to be a valid AIT file"
|
|
1100
|
+
});
|
|
1101
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
1102
|
+
const bundleLen = Number(view.getBigUint64(AIT_MAGIC_SIZE + AIT_VERSION_SIZE, false));
|
|
1103
|
+
if (!Number.isFinite(bundleLen) || bundleLen <= 0) throw new AitBundleError({
|
|
1104
|
+
path: pathForError,
|
|
1105
|
+
reason: "invalid-ait",
|
|
1106
|
+
message: `AIT bundle length is invalid (${bundleLen})`
|
|
1107
|
+
});
|
|
1108
|
+
const bundleStart = AIT_HEADER_SIZE;
|
|
1109
|
+
const bundleEnd = bundleStart + bundleLen;
|
|
1110
|
+
if (bytes.length < bundleEnd) throw new AitBundleError({
|
|
1111
|
+
path: pathForError,
|
|
1112
|
+
reason: "invalid-ait",
|
|
1113
|
+
message: "unexpected end of buffer reading AIT bundle protobuf"
|
|
1114
|
+
});
|
|
1115
|
+
const deploymentId = readProtobufStringFields(bytes.subarray(bundleStart, bundleEnd), [2, 3]).get(2);
|
|
1116
|
+
if (typeof deploymentId !== "string" || deploymentId === "") throw new AitBundleError({
|
|
1117
|
+
path: pathForError,
|
|
1118
|
+
reason: "missing-deployment-id",
|
|
1119
|
+
message: "AIT bundle protobuf is missing deploymentId (field 2)"
|
|
1120
|
+
});
|
|
1121
|
+
return deploymentId;
|
|
1122
|
+
}
|
|
1123
|
+
function readProtobufStringFields(bytes, wantedFieldNumbers) {
|
|
1124
|
+
const wanted = new Set(wantedFieldNumbers);
|
|
1125
|
+
const out = /* @__PURE__ */ new Map();
|
|
1126
|
+
const decoder = new TextDecoder("utf-8", { fatal: false });
|
|
1127
|
+
let offset = 0;
|
|
1128
|
+
while (offset < bytes.length) {
|
|
1129
|
+
const { value: tag, next } = readVarint(bytes, offset);
|
|
1130
|
+
offset = next;
|
|
1131
|
+
const fieldNumber = Number(tag >> 3n);
|
|
1132
|
+
const wireType = Number(tag & 7n);
|
|
1133
|
+
if (wireType === 0) offset = readVarint(bytes, offset).next;
|
|
1134
|
+
else if (wireType === 1) offset += 8;
|
|
1135
|
+
else if (wireType === 2) {
|
|
1136
|
+
const { value: len, next: afterLen } = readVarint(bytes, offset);
|
|
1137
|
+
offset = afterLen;
|
|
1138
|
+
const payloadEnd = offset + Number(len);
|
|
1139
|
+
if (payloadEnd > bytes.length) break;
|
|
1140
|
+
if (wanted.has(fieldNumber)) out.set(fieldNumber, decoder.decode(bytes.subarray(offset, payloadEnd)));
|
|
1141
|
+
offset = payloadEnd;
|
|
1142
|
+
} else if (wireType === 5) offset += 4;
|
|
1143
|
+
else break;
|
|
1144
|
+
}
|
|
1145
|
+
return out;
|
|
1146
|
+
}
|
|
1147
|
+
function readVarint(bytes, start) {
|
|
1148
|
+
let value = 0n;
|
|
1149
|
+
let shift = 0n;
|
|
1150
|
+
let i = start;
|
|
1151
|
+
for (let n = 0; n < 10 && i < bytes.length; n++, i++) {
|
|
1152
|
+
const byte = bytes[i];
|
|
1153
|
+
if (byte === void 0) break;
|
|
1154
|
+
value |= BigInt(byte & 127) << shift;
|
|
1155
|
+
if ((byte & 128) === 0) return {
|
|
1156
|
+
value,
|
|
1157
|
+
next: i + 1
|
|
1158
|
+
};
|
|
1159
|
+
shift += 7n;
|
|
1160
|
+
}
|
|
1161
|
+
return {
|
|
1162
|
+
value,
|
|
1163
|
+
next: i
|
|
1164
|
+
};
|
|
1165
|
+
}
|
|
1166
|
+
function deploymentIdFromLegacyZip(bytes, pathForError) {
|
|
1050
1167
|
let entries;
|
|
1051
1168
|
try {
|
|
1052
1169
|
entries = unzipSync(bytes, { filter: (file) => file.name === "app.json" });
|
|
@@ -1195,6 +1312,7 @@ async function runDeploy(args, deps = {}) {
|
|
|
1195
1312
|
workspaceId,
|
|
1196
1313
|
appId,
|
|
1197
1314
|
deploymentId,
|
|
1315
|
+
bundleFormat: bundleInfo.format,
|
|
1198
1316
|
bytes: bundleInfo.bytes.byteLength,
|
|
1199
1317
|
steps,
|
|
1200
1318
|
memo: memo ?? null,
|
|
@@ -1279,6 +1397,7 @@ async function runDeploy(args, deps = {}) {
|
|
|
1279
1397
|
workspaceId,
|
|
1280
1398
|
appId,
|
|
1281
1399
|
deploymentId,
|
|
1400
|
+
bundleFormat: bundleInfo.format,
|
|
1282
1401
|
uploaded,
|
|
1283
1402
|
reviewed,
|
|
1284
1403
|
released: release,
|
|
@@ -5410,7 +5529,7 @@ function resolveVersion() {
|
|
|
5410
5529
|
if (typeof injected === "string" && injected.length > 0) return injected;
|
|
5411
5530
|
} catch {}
|
|
5412
5531
|
try {
|
|
5413
|
-
return "0.1.
|
|
5532
|
+
return "0.1.16";
|
|
5414
5533
|
} catch {}
|
|
5415
5534
|
return "0.0.0-dev";
|
|
5416
5535
|
}
|