@apilift/cli 1.5.3 → 1.5.4
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.
|
@@ -28013,11 +28013,13 @@ var init_schema = __esm({
|
|
|
28013
28013
|
});
|
|
28014
28014
|
proofPointer = pointerSchema.refine((value) => value.split("/").every((part) => !/\{(?:input|result|generated)\./u.test(part) || /^\{input\.[A-Za-z][A-Za-z0-9_-]*\}$/u.test(part)), "A dynamic JSON Pointer segment must be exactly {input.name}");
|
|
28015
28015
|
proofComparison = external_exports.union([external_exports.strictObject({ path: proofPointer, input: inputNameSchema }), external_exports.strictObject({ path: proofPointer, result: pointerSchema }), external_exports.strictObject({ path: proofPointer, value: valueSchema })]);
|
|
28016
|
-
proofSchema = external_exports.strictObject({ request: requestSchema, effect: external_exports.literal("read").optional(), select: external_exports.strictObject({ path: proofPointer, where: external_exports.array(proofComparison).min(1) }).optional(), equals: external_exports.array(proofComparison).min(1).optional(), absent: external_exports.literal(true).optional() }).superRefine((v2, ctx) => {
|
|
28016
|
+
proofSchema = external_exports.strictObject({ request: requestSchema, effect: external_exports.literal("read").optional(), select: external_exports.strictObject({ path: proofPointer, where: external_exports.array(proofComparison).min(1) }).optional(), equals: external_exports.array(proofComparison).min(1).optional(), response: external_exports.strictObject({ path: proofPointer.optional(), schema: jsonSchema }).optional(), absent: external_exports.literal(true).optional() }).superRefine((v2, ctx) => {
|
|
28017
28017
|
if (!!v2.equals === !!v2.absent)
|
|
28018
28018
|
ctx.addIssue({ code: "custom", message: "Exactly one of equals and absent is required" });
|
|
28019
28019
|
if (v2.select && v2.absent)
|
|
28020
28020
|
ctx.addIssue({ code: "custom", path: ["select"], message: "Collection selection cannot prove absence; use a targeted HTTP-404 read" });
|
|
28021
|
+
if (v2.response && v2.absent)
|
|
28022
|
+
ctx.addIssue({ code: "custom", path: ["response"], message: "An HTTP-404 absence proof has no response schema" });
|
|
28021
28023
|
if (!v2.effect && !["GET", "HEAD"].includes(v2.request.method))
|
|
28022
28024
|
ctx.addIssue({ code: "custom", path: ["request", "method"], message: "Proof request must be GET or HEAD unless effect is read" });
|
|
28023
28025
|
});
|
|
@@ -29459,11 +29459,13 @@ var responseSchema = external_exports.strictObject({ schema: jsonSchema.optional
|
|
|
29459
29459
|
});
|
|
29460
29460
|
var proofPointer = pointerSchema.refine((value) => value.split("/").every((part) => !/\{(?:input|result|generated)\./u.test(part) || /^\{input\.[A-Za-z][A-Za-z0-9_-]*\}$/u.test(part)), "A dynamic JSON Pointer segment must be exactly {input.name}");
|
|
29461
29461
|
var proofComparison = external_exports.union([external_exports.strictObject({ path: proofPointer, input: inputNameSchema }), external_exports.strictObject({ path: proofPointer, result: pointerSchema }), external_exports.strictObject({ path: proofPointer, value: valueSchema })]);
|
|
29462
|
-
var proofSchema = external_exports.strictObject({ request: requestSchema, effect: external_exports.literal("read").optional(), select: external_exports.strictObject({ path: proofPointer, where: external_exports.array(proofComparison).min(1) }).optional(), equals: external_exports.array(proofComparison).min(1).optional(), absent: external_exports.literal(true).optional() }).superRefine((v, ctx) => {
|
|
29462
|
+
var proofSchema = external_exports.strictObject({ request: requestSchema, effect: external_exports.literal("read").optional(), select: external_exports.strictObject({ path: proofPointer, where: external_exports.array(proofComparison).min(1) }).optional(), equals: external_exports.array(proofComparison).min(1).optional(), response: external_exports.strictObject({ path: proofPointer.optional(), schema: jsonSchema }).optional(), absent: external_exports.literal(true).optional() }).superRefine((v, ctx) => {
|
|
29463
29463
|
if (!!v.equals === !!v.absent)
|
|
29464
29464
|
ctx.addIssue({ code: "custom", message: "Exactly one of equals and absent is required" });
|
|
29465
29465
|
if (v.select && v.absent)
|
|
29466
29466
|
ctx.addIssue({ code: "custom", path: ["select"], message: "Collection selection cannot prove absence; use a targeted HTTP-404 read" });
|
|
29467
|
+
if (v.response && v.absent)
|
|
29468
|
+
ctx.addIssue({ code: "custom", path: ["response"], message: "An HTTP-404 absence proof has no response schema" });
|
|
29467
29469
|
if (!v.effect && !["GET", "HEAD"].includes(v.request.method))
|
|
29468
29470
|
ctx.addIssue({ code: "custom", path: ["request", "method"], message: "Proof request must be GET or HEAD unless effect is read" });
|
|
29469
29471
|
});
|
|
@@ -29644,7 +29646,7 @@ function validateDefinition(kind, name, value) {
|
|
|
29644
29646
|
for (const [i, comparison] of (definition2.proof?.select?.where ?? []).entries())
|
|
29645
29647
|
if ("input" in comparison && !names2.includes(comparison.input))
|
|
29646
29648
|
issues.push({ path: `/proof/select/where/${i}/input`, message: "Unknown input" });
|
|
29647
|
-
const proofPaths = [...definition2.proof?.equals ?? [], ...definition2.proof?.select?.where ?? [], ...definition2.proof?.select ? [definition2.proof.select] : []];
|
|
29649
|
+
const proofPaths = [...definition2.proof?.equals ?? [], ...definition2.proof?.select?.where ?? [], ...definition2.proof?.select ? [definition2.proof.select] : [], ...definition2.proof?.response?.path !== void 0 ? [{ path: definition2.proof.response.path }] : []];
|
|
29648
29650
|
for (const item of proofPaths)
|
|
29649
29651
|
for (const match of item.path.matchAll(/\{input\.([^{}]+)\}/gu))
|
|
29650
29652
|
if (!names2.includes(match[1]))
|
package/dist/apilift.js
CHANGED
|
@@ -28077,11 +28077,13 @@ var init_schema = __esm({
|
|
|
28077
28077
|
});
|
|
28078
28078
|
proofPointer = pointerSchema.refine((value) => value.split("/").every((part) => !/\{(?:input|result|generated)\./u.test(part) || /^\{input\.[A-Za-z][A-Za-z0-9_-]*\}$/u.test(part)), "A dynamic JSON Pointer segment must be exactly {input.name}");
|
|
28079
28079
|
proofComparison = external_exports.union([external_exports.strictObject({ path: proofPointer, input: inputNameSchema }), external_exports.strictObject({ path: proofPointer, result: pointerSchema }), external_exports.strictObject({ path: proofPointer, value: valueSchema })]);
|
|
28080
|
-
proofSchema = external_exports.strictObject({ request: requestSchema, effect: external_exports.literal("read").optional(), select: external_exports.strictObject({ path: proofPointer, where: external_exports.array(proofComparison).min(1) }).optional(), equals: external_exports.array(proofComparison).min(1).optional(), absent: external_exports.literal(true).optional() }).superRefine((v, ctx) => {
|
|
28080
|
+
proofSchema = external_exports.strictObject({ request: requestSchema, effect: external_exports.literal("read").optional(), select: external_exports.strictObject({ path: proofPointer, where: external_exports.array(proofComparison).min(1) }).optional(), equals: external_exports.array(proofComparison).min(1).optional(), response: external_exports.strictObject({ path: proofPointer.optional(), schema: jsonSchema }).optional(), absent: external_exports.literal(true).optional() }).superRefine((v, ctx) => {
|
|
28081
28081
|
if (!!v.equals === !!v.absent)
|
|
28082
28082
|
ctx.addIssue({ code: "custom", message: "Exactly one of equals and absent is required" });
|
|
28083
28083
|
if (v.select && v.absent)
|
|
28084
28084
|
ctx.addIssue({ code: "custom", path: ["select"], message: "Collection selection cannot prove absence; use a targeted HTTP-404 read" });
|
|
28085
|
+
if (v.response && v.absent)
|
|
28086
|
+
ctx.addIssue({ code: "custom", path: ["response"], message: "An HTTP-404 absence proof has no response schema" });
|
|
28085
28087
|
if (!v.effect && !["GET", "HEAD"].includes(v.request.method))
|
|
28086
28088
|
ctx.addIssue({ code: "custom", path: ["request", "method"], message: "Proof request must be GET or HEAD unless effect is read" });
|
|
28087
28089
|
});
|
|
@@ -28496,7 +28498,7 @@ function validateDefinition(kind, name, value) {
|
|
|
28496
28498
|
for (const [i, comparison] of (definition2.proof?.select?.where ?? []).entries())
|
|
28497
28499
|
if ("input" in comparison && !names2.includes(comparison.input))
|
|
28498
28500
|
issues.push({ path: `/proof/select/where/${i}/input`, message: "Unknown input" });
|
|
28499
|
-
const proofPaths = [...definition2.proof?.equals ?? [], ...definition2.proof?.select?.where ?? [], ...definition2.proof?.select ? [definition2.proof.select] : []];
|
|
28501
|
+
const proofPaths = [...definition2.proof?.equals ?? [], ...definition2.proof?.select?.where ?? [], ...definition2.proof?.select ? [definition2.proof.select] : [], ...definition2.proof?.response?.path !== void 0 ? [{ path: definition2.proof.response.path }] : []];
|
|
28500
28502
|
for (const item of proofPaths)
|
|
28501
28503
|
for (const match of item.path.matchAll(/\{input\.([^{}]+)\}/gu))
|
|
28502
28504
|
if (!names2.includes(match[1]))
|
|
@@ -28797,346 +28799,10 @@ var init_api2 = __esm({
|
|
|
28797
28799
|
}
|
|
28798
28800
|
});
|
|
28799
28801
|
|
|
28800
|
-
// src/version.ts
|
|
28801
|
-
import { readFileSync as readFileSync3 } from "node:fs";
|
|
28802
|
-
var cliVersion;
|
|
28803
|
-
var init_version = __esm({
|
|
28804
|
-
"src/version.ts"() {
|
|
28805
|
-
"use strict";
|
|
28806
|
-
cliVersion = JSON.parse(readFileSync3(new URL("../package.json", import.meta.url), "utf8")).version;
|
|
28807
|
-
}
|
|
28808
|
-
});
|
|
28809
|
-
|
|
28810
|
-
// src/api.ts
|
|
28811
|
-
function retryDelay(response, attempt) {
|
|
28812
|
-
const value = response.headers.get("retry-after");
|
|
28813
|
-
if (value) {
|
|
28814
|
-
const seconds = Number(value);
|
|
28815
|
-
if (Number.isFinite(seconds) && seconds >= 0) return Math.min(seconds * 1e3, 5e3);
|
|
28816
|
-
const date5 = Date.parse(value);
|
|
28817
|
-
if (Number.isFinite(date5)) return Math.min(Math.max(date5 - Date.now(), 0), 5e3);
|
|
28818
|
-
}
|
|
28819
|
-
return 250 * 2 ** attempt;
|
|
28820
|
-
}
|
|
28821
|
-
function sleep(ms) {
|
|
28822
|
-
return new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
28823
|
-
}
|
|
28824
|
-
function createCliApi(baseUrl, fetcher = fetch, token, sessionId) {
|
|
28825
|
-
const transport = async (input2, init) => {
|
|
28826
|
-
const method = init?.method ?? "GET";
|
|
28827
|
-
const headers = new Headers(init?.headers);
|
|
28828
|
-
headers.set("Apilift-Capabilities", "distributed-rollouts-v1,discovery-proof-v2,dynamic-bindings-v1");
|
|
28829
|
-
headers.set("Apilift-Client", `cli/${cliVersion}`);
|
|
28830
|
-
if (token) headers.set("Authorization", `Bearer ${token}`);
|
|
28831
|
-
if (sessionId) headers.set("Apilift-Session", sessionId);
|
|
28832
|
-
const path2 = new URL(input2 instanceof Request ? input2.url : String(input2), baseUrl).pathname;
|
|
28833
|
-
const timeoutMs = method === "POST" && path2 === "/api/v1/installations" ? 3e4 : 1e4;
|
|
28834
|
-
for (let attempt = 0; ; attempt++) {
|
|
28835
|
-
try {
|
|
28836
|
-
const response = await fetcher(input2, { ...init, headers, signal: init?.signal ?? AbortSignal.timeout(timeoutMs) });
|
|
28837
|
-
if (method !== "GET" || attempt >= 2 || !retryStatuses.has(response.status)) {
|
|
28838
|
-
if (response.status !== 204 && !response.headers.get("content-type")?.toLowerCase().includes("json")) throw new ApiClientError(response.status, null);
|
|
28839
|
-
if (response.status !== 204) {
|
|
28840
|
-
try {
|
|
28841
|
-
await response.clone().json();
|
|
28842
|
-
} catch {
|
|
28843
|
-
throw new ApiClientError(response.status, null);
|
|
28844
|
-
}
|
|
28845
|
-
}
|
|
28846
|
-
return response;
|
|
28847
|
-
}
|
|
28848
|
-
await sleep(retryDelay(response, attempt));
|
|
28849
|
-
} catch (error62) {
|
|
28850
|
-
if (error62 instanceof ApiClientError) throw error62;
|
|
28851
|
-
if (method !== "GET") throw new ApiDeliveryUncertainError(error62);
|
|
28852
|
-
if (attempt >= 2) throw new ApiReadUnavailableError(error62);
|
|
28853
|
-
await sleep(250 * 2 ** attempt);
|
|
28854
|
-
}
|
|
28855
|
-
}
|
|
28856
|
-
};
|
|
28857
|
-
return createApiClient(baseUrl, transport);
|
|
28858
|
-
}
|
|
28859
|
-
var retryStatuses, ApiDeliveryUncertainError, ApiReadUnavailableError;
|
|
28860
|
-
var init_api3 = __esm({
|
|
28861
|
-
"src/api.ts"() {
|
|
28862
|
-
"use strict";
|
|
28863
|
-
init_version();
|
|
28864
|
-
init_api2();
|
|
28865
|
-
retryStatuses = /* @__PURE__ */ new Set([408, 429, 502, 503, 504]);
|
|
28866
|
-
ApiDeliveryUncertainError = class extends Error {
|
|
28867
|
-
constructor(cause) {
|
|
28868
|
-
super("The Registry did not confirm whether the mutation was applied");
|
|
28869
|
-
this.cause = cause;
|
|
28870
|
-
}
|
|
28871
|
-
};
|
|
28872
|
-
ApiReadUnavailableError = class extends Error {
|
|
28873
|
-
constructor(cause) {
|
|
28874
|
-
super("The Registry could not be reached after three attempts");
|
|
28875
|
-
this.cause = cause;
|
|
28876
|
-
}
|
|
28877
|
-
};
|
|
28878
|
-
}
|
|
28879
|
-
});
|
|
28880
|
-
|
|
28881
|
-
// src/commands/registry.ts
|
|
28882
|
-
function parseInvocation(argv) {
|
|
28883
|
-
const issues = [];
|
|
28884
|
-
let cursor = 0;
|
|
28885
|
-
let sessionLabel;
|
|
28886
|
-
let version2 = false;
|
|
28887
|
-
while (cursor < argv.length) {
|
|
28888
|
-
const token = argv[cursor];
|
|
28889
|
-
if (token === "--session") {
|
|
28890
|
-
const value = argv[cursor + 1];
|
|
28891
|
-
if (!value || value.startsWith("--")) issues.push("--session needs a worker label");
|
|
28892
|
-
else if (sessionLabel) issues.push("--session may appear only once");
|
|
28893
|
-
else sessionLabel = value;
|
|
28894
|
-
cursor += value && !value.startsWith("--") ? 2 : 1;
|
|
28895
|
-
} else if (token === "--version") {
|
|
28896
|
-
version2 = true;
|
|
28897
|
-
cursor++;
|
|
28898
|
-
} else break;
|
|
28899
|
-
}
|
|
28900
|
-
if (sessionLabel && (sessionLabel.length > 80 || !/^[A-Za-z0-9_-]+$/u.test(sessionLabel))) issues.push("--session must be 1 to 80 letters, digits, hyphens or underscores");
|
|
28901
|
-
const base2 = { sessionLabel, positionals: [], options: {}, flags: [], repeats: {}, actionArgs: [] };
|
|
28902
|
-
if (version2) {
|
|
28903
|
-
if (cursor < argv.length) issues.push("--version takes no command");
|
|
28904
|
-
return { ...issues.length ? {} : { invocation: { key: "version", ...base2 } }, issues };
|
|
28905
|
-
}
|
|
28906
|
-
const remaining = argv.slice(cursor);
|
|
28907
|
-
if (remaining.length === 1 && remaining[0] === "--help") return { invocation: { key: "helpCommands", ...base2 }, issues };
|
|
28908
|
-
const selected = Object.entries(commandRegistry).filter(([, command7]) => command7.path.every((part, index) => remaining[index] === part)).sort((left, right) => right[1].path.length - left[1].path.length)[0];
|
|
28909
|
-
if (!selected) return { issues: [`Unknown command: ${remaining.slice(0, 2).join(" ")}`] };
|
|
28910
|
-
const [key, command6] = selected;
|
|
28911
|
-
const positionals = [];
|
|
28912
|
-
const options2 = {};
|
|
28913
|
-
const flags = [];
|
|
28914
|
-
const repeats = {};
|
|
28915
|
-
const actionArgs = [];
|
|
28916
|
-
for (let index = command6.path.length; index < remaining.length; index++) {
|
|
28917
|
-
const token = remaining[index];
|
|
28918
|
-
if (token.startsWith("--")) {
|
|
28919
|
-
const name = token.slice(2);
|
|
28920
|
-
if (name === "session") {
|
|
28921
|
-
issues.push("--session must appear before the command");
|
|
28922
|
-
continue;
|
|
28923
|
-
}
|
|
28924
|
-
if (command6.values?.includes(name) || command6.repeat?.includes(name)) {
|
|
28925
|
-
const value = remaining[index + 1];
|
|
28926
|
-
if (!value || value.startsWith("--")) {
|
|
28927
|
-
issues.push(`--${name} needs a value`);
|
|
28928
|
-
continue;
|
|
28929
|
-
}
|
|
28930
|
-
if (command6.repeat?.includes(name)) (repeats[name] ??= []).push(value);
|
|
28931
|
-
else if (Object.hasOwn(options2, name)) issues.push(`--${name} may appear only once`);
|
|
28932
|
-
else options2[name] = value;
|
|
28933
|
-
index++;
|
|
28934
|
-
} else if (command6.flags?.includes(name)) {
|
|
28935
|
-
if (flags.includes(name)) issues.push(`--${name} may appear only once`);
|
|
28936
|
-
else flags.push(name);
|
|
28937
|
-
} else if (command6.actionFlags && positionals.length >= 2) actionArgs.push(token);
|
|
28938
|
-
else issues.push(`Unknown option --${name}`);
|
|
28939
|
-
} else if (command6.actionFlags && positionals.length >= 2 && actionArgs.length) actionArgs.push(token);
|
|
28940
|
-
else if (positionals.length < command6.max) positionals.push(token);
|
|
28941
|
-
else issues.push(`Unexpected argument ${token}`);
|
|
28942
|
-
}
|
|
28943
|
-
if (positionals.length < command6.min) issues.push(`${command6.path.join(" ") || "command"} needs ${command6.min} argument${command6.min === 1 ? "" : "s"}`);
|
|
28944
|
-
return { ...issues.length ? {} : { invocation: { key, sessionLabel, positionals, options: options2, flags, repeats, actionArgs } }, issues };
|
|
28945
|
-
}
|
|
28946
|
-
var commandRegistry;
|
|
28947
|
-
var init_registry = __esm({
|
|
28948
|
-
"src/commands/registry.ts"() {
|
|
28949
|
-
"use strict";
|
|
28950
|
-
commandRegistry = {
|
|
28951
|
-
root: { path: [], min: 0, max: 0 },
|
|
28952
|
-
setup: { path: ["setup"], min: 0, max: 0, values: ["code"] },
|
|
28953
|
-
setupContinue: { path: ["setup", "continue"], min: 0, max: 0 },
|
|
28954
|
-
doctor: { path: ["doctor"], min: 0, max: 0, values: ["app"] },
|
|
28955
|
-
update: { path: ["update"], min: 0, max: 0 },
|
|
28956
|
-
helpCommands: { path: ["help", "commands"], min: 0, max: 0 },
|
|
28957
|
-
appsSearch: { path: ["apps", "search"], min: 1, max: 1, values: ["domain", "limit", "cursor"] },
|
|
28958
|
-
appsUse: { path: ["apps", "use"], min: 1, max: 1 },
|
|
28959
|
-
appsRelease: { path: ["apps", "release"], min: 1, max: 1 },
|
|
28960
|
-
appsRefresh: { path: ["apps", "refresh"], min: 1, max: 1, values: ["action"] },
|
|
28961
|
-
appsNew: { path: ["apps", "new"], min: 1, max: 1 },
|
|
28962
|
-
appsUpdate: { path: ["apps", "update"], min: 1, max: 1 },
|
|
28963
|
-
appsHistory: { path: ["apps", "history"], min: 1, max: 1, values: ["resource", "limit", "cursor"] },
|
|
28964
|
-
actionsList: { path: ["actions", "list"], min: 1, max: 1, values: ["entity", "limit", "cursor"], flags: ["all"] },
|
|
28965
|
-
actionsSearch: { path: ["actions", "search"], min: 2, max: 2, values: ["entity", "limit", "cursor"] },
|
|
28966
|
-
actionsShow: { path: ["actions", "show"], min: 2, max: 11, values: ["input-template"], flags: ["schema"] },
|
|
28967
|
-
run: { path: ["run"], min: 2, max: 2, values: ["input", "output"], flags: ["check", "no-context"], repeat: ["select"], actionFlags: true },
|
|
28968
|
-
credentialsList: { path: ["credentials", "list"], min: 1, max: 2 },
|
|
28969
|
-
credentialsUse: { path: ["credentials", "use"], min: 3, max: 3 },
|
|
28970
|
-
credentialsAdd: { path: ["credentials", "add"], min: 2, max: 2 },
|
|
28971
|
-
credentialsRemove: { path: ["credentials", "remove"], min: 3, max: 3 },
|
|
28972
|
-
credentialsUnbound: { path: ["credentials", "unbound"], min: 0, max: 0 },
|
|
28973
|
-
credentialsAttach: { path: ["credentials", "attach"], min: 3, max: 3 },
|
|
28974
|
-
transportsShow: { path: ["transports", "show"], min: 1, max: 2 },
|
|
28975
|
-
browserCheck: { path: ["browser", "check"], min: 1, max: 1 },
|
|
28976
|
-
browserTabs: { path: ["browser", "tabs"], min: 1, max: 1, values: ["select"] },
|
|
28977
|
-
contextSet: { path: ["context", "set"], min: 2, max: 2, values: ["app"] },
|
|
28978
|
-
contextShow: { path: ["context", "show"], min: 0, max: 0, values: ["app"] },
|
|
28979
|
-
contextUnset: { path: ["context", "unset"], min: 1, max: 1, values: ["app"] },
|
|
28980
|
-
contextClear: { path: ["context", "clear"], min: 0, max: 0, values: ["app"] },
|
|
28981
|
-
discoverDraft: { path: ["discover", "draft"], min: 1, max: 2 },
|
|
28982
|
-
discoverCheck: { path: ["discover", "check"], min: 0, max: 0 },
|
|
28983
|
-
discoverRun: { path: ["discover", "run"], min: 0, max: 0, flags: ["proof-only"] },
|
|
28984
|
-
discoverPublish: { path: ["discover", "publish"], min: 0, max: 0 },
|
|
28985
|
-
discoverStatus: { path: ["discover", "status"], min: 0, max: 0 },
|
|
28986
|
-
discoverDefer: { path: ["discover", "defer"], min: 0, max: 0 },
|
|
28987
|
-
discoverDiscard: { path: ["discover", "discard"], min: 0, max: 0 },
|
|
28988
|
-
discoverRebase: { path: ["discover", "rebase"], min: 0, max: 0 },
|
|
28989
|
-
discoverRemove: { path: ["discover", "remove"], min: 2, max: 2 },
|
|
28990
|
-
discoverClose: { path: ["discover", "close"], min: 0, max: 0 },
|
|
28991
|
-
discoverApiAssess: { path: ["discover", "api", "assess"], min: 1, max: 1 },
|
|
28992
|
-
discoverApiSave: { path: ["discover", "api", "save"], min: 0, max: 0 },
|
|
28993
|
-
discoverApiStatus: { path: ["discover", "api", "status"], min: 0, max: 1 },
|
|
28994
|
-
discoverCaptureStart: { path: ["discover", "capture", "start"], min: 0, max: 0 },
|
|
28995
|
-
discoverCaptureStop: { path: ["discover", "capture", "stop"], min: 0, max: 0 },
|
|
28996
|
-
discoverCaptureList: { path: ["discover", "capture", "list"], min: 0, max: 0, values: ["limit", "cursor"] },
|
|
28997
|
-
discoverCaptureShow: { path: ["discover", "capture", "show"], min: 1, max: 1, values: ["part", "pointer"] },
|
|
28998
|
-
discoverCaptureSelect: { path: ["discover", "capture", "select"], min: 1, max: 1 },
|
|
28999
|
-
discoverCaptureAuth: { path: ["discover", "capture", "auth"], min: 1, max: 1 },
|
|
29000
|
-
discoverCaptureCancel: { path: ["discover", "capture", "cancel"], min: 0, max: 0 }
|
|
29001
|
-
};
|
|
29002
|
-
}
|
|
29003
|
-
});
|
|
29004
|
-
|
|
29005
|
-
// src/session.ts
|
|
29006
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
29007
|
-
function apiSessionId(installationId, session) {
|
|
29008
|
-
if (!session) return void 0;
|
|
29009
|
-
const hex3 = createHash2("sha256").update("apilift-api-session/v1\0").update(installationId).update("\0").update(session.id).digest("hex");
|
|
29010
|
-
return `${hex3.slice(0, 8)}-${hex3.slice(8, 12)}-5${hex3.slice(13, 16)}-a${hex3.slice(17, 20)}-${hex3.slice(20, 32)}`;
|
|
29011
|
-
}
|
|
29012
|
-
function agentSession(env, explicitLabel) {
|
|
29013
|
-
explicitLabel ??= env.APILIFT_SESSION;
|
|
29014
|
-
if (explicitLabel !== void 0 && !/^[A-Za-z0-9_-]{1,80}$/u.test(explicitLabel)) return null;
|
|
29015
|
-
const codex = env.CODEX_THREAD_ID || env.CODEX_SESSION_ID;
|
|
29016
|
-
const claude = env.CLAUDE_CODE_SESSION_ID;
|
|
29017
|
-
if (explicitLabel) {
|
|
29018
|
-
const agent2 = claude || env.CLAUDECODE ? "claude" : codex || env.CODEX_HOME ? "codex" : null;
|
|
29019
|
-
return agent2 ? { id: `${agent2}:label:${explicitLabel}`, agent: agent2 } : null;
|
|
29020
|
-
}
|
|
29021
|
-
if (codex && !claude) return { id: `codex:${codex}`, agent: "codex" };
|
|
29022
|
-
if (claude && !codex) return { id: `claude:${claude}`, agent: "claude" };
|
|
29023
|
-
return null;
|
|
29024
|
-
}
|
|
29025
|
-
function commandPrefix(label2) {
|
|
29026
|
-
return `apilift${label2 ? ` --session ${label2}` : ""}`;
|
|
29027
|
-
}
|
|
29028
|
-
var init_session = __esm({
|
|
29029
|
-
"src/session.ts"() {
|
|
29030
|
-
"use strict";
|
|
29031
|
-
}
|
|
29032
|
-
});
|
|
29033
|
-
|
|
29034
|
-
// src/browser-response.ts
|
|
29035
|
-
import { createHash as createHash3 } from "node:crypto";
|
|
29036
|
-
async function browserResponseBody(client, scopeId, value, maxBytes = 48 * 1024 * 1024) {
|
|
29037
|
-
if (value.bodyArtifact !== void 0) {
|
|
29038
|
-
const artifact = value.bodyArtifact;
|
|
29039
|
-
if (value.body != null || !artifact || typeof artifact.sha256 !== "string" || !/^[0-9a-f]{64}$/.test(artifact.sha256) || !Number.isInteger(artifact.bytes) || Number(artifact.bytes) < 1 || Number(artifact.bytes) > maxBytes || artifact.encoding !== "utf-8") throw new Error("Chrome returned invalid response evidence metadata");
|
|
29040
|
-
const bytes = await client.blob(scopeId, artifact.sha256);
|
|
29041
|
-
if (!bytes || bytes.length !== artifact.bytes || createHash3("sha256").update(bytes).digest("hex") !== artifact.sha256) throw new Error("Chrome response evidence is missing or failed its integrity check");
|
|
29042
|
-
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
29043
|
-
}
|
|
29044
|
-
if (value.body == null) return null;
|
|
29045
|
-
if (typeof value.body !== "string" || Buffer.byteLength(value.body, "utf8") > maxBytes) throw new Error("Chrome did not return complete response evidence");
|
|
29046
|
-
return value.body;
|
|
29047
|
-
}
|
|
29048
|
-
var init_browser_response = __esm({
|
|
29049
|
-
"src/browser-response.ts"() {
|
|
29050
|
-
"use strict";
|
|
29051
|
-
}
|
|
29052
|
-
});
|
|
29053
|
-
|
|
29054
|
-
// src/timings.ts
|
|
29055
|
-
import { appendFileSync } from "node:fs";
|
|
29056
|
-
import { resolve } from "node:path";
|
|
29057
|
-
function executionTimings() {
|
|
29058
|
-
return { brokerMs: 0, bridgeMs: 0, registryMs: 0, bindingMs: 0, replayMs: 0, appMs: 0, proofMs: 0, reportingMs: 0 };
|
|
29059
|
-
}
|
|
29060
|
-
async function timed(timings, stage, work) {
|
|
29061
|
-
const started = performance.now();
|
|
29062
|
-
try {
|
|
29063
|
-
return await work();
|
|
29064
|
-
} finally {
|
|
29065
|
-
if (timings) timings[stage] += performance.now() - started;
|
|
29066
|
-
}
|
|
29067
|
-
}
|
|
29068
|
-
function saveTimings(timings, commandMs) {
|
|
29069
|
-
if (!process.env.APILIFT_TIMING_FILE) return;
|
|
29070
|
-
try {
|
|
29071
|
-
appendFileSync(resolve(process.env.APILIFT_TIMING_FILE), JSON.stringify({ ...Object.fromEntries(Object.entries(timings).map(([key, value]) => [key, Math.round(value * 100) / 100])), commandMs: Math.round(commandMs * 100) / 100 }) + "\n", { mode: 384 });
|
|
29072
|
-
} catch {
|
|
29073
|
-
}
|
|
29074
|
-
}
|
|
29075
|
-
var init_timings = __esm({
|
|
29076
|
-
"src/timings.ts"() {
|
|
29077
|
-
"use strict";
|
|
29078
|
-
}
|
|
29079
|
-
});
|
|
29080
|
-
|
|
29081
|
-
// src/files.ts
|
|
29082
|
-
import { randomUUID } from "node:crypto";
|
|
29083
|
-
import { accessSync, constants, existsSync, statSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
29084
|
-
import { dirname, join as join2, resolve as resolve2 } from "node:path";
|
|
29085
|
-
function outputDestination(file2) {
|
|
29086
|
-
const target = resolve2(file2);
|
|
29087
|
-
if (existsSync(target)) {
|
|
29088
|
-
if (!statSync(target).isFile()) throw new Error("Output destination must be a regular file");
|
|
29089
|
-
accessSync(target, constants.W_OK);
|
|
29090
|
-
}
|
|
29091
|
-
const probe = join2(dirname(target), `.apilift-output-check-${randomUUID()}`);
|
|
29092
|
-
try {
|
|
29093
|
-
writeFileSync2(probe, "", { flag: "wx", mode: 384 });
|
|
29094
|
-
} finally {
|
|
29095
|
-
try {
|
|
29096
|
-
unlinkSync(probe);
|
|
29097
|
-
} catch {
|
|
29098
|
-
}
|
|
29099
|
-
}
|
|
29100
|
-
return target;
|
|
29101
|
-
}
|
|
29102
|
-
var init_files = __esm({
|
|
29103
|
-
"src/files.ts"() {
|
|
29104
|
-
"use strict";
|
|
29105
|
-
}
|
|
29106
|
-
});
|
|
29107
|
-
|
|
29108
|
-
// src/execution-reports.ts
|
|
29109
|
-
async function flushExecutionReports(api, state, budgetMs = 1e4) {
|
|
29110
|
-
const pending = state.pendingExecutionReports();
|
|
29111
|
-
if (!pending.length) return;
|
|
29112
|
-
const controller = new AbortController();
|
|
29113
|
-
let timer;
|
|
29114
|
-
try {
|
|
29115
|
-
const acknowledgment = await Promise.race([
|
|
29116
|
-
api.call("postExecutions", { body: { reports: pending.map((item) => item.report) }, signal: controller.signal }),
|
|
29117
|
-
new Promise((_, reject) => {
|
|
29118
|
-
timer = setTimeout(() => {
|
|
29119
|
-
controller.abort();
|
|
29120
|
-
reject(new Error("Report delivery deferred"));
|
|
29121
|
-
}, budgetMs);
|
|
29122
|
-
})
|
|
29123
|
-
]);
|
|
29124
|
-
state.acknowledgeExecutionReports(acknowledgment.results.map((item) => item.id));
|
|
29125
|
-
} catch {
|
|
29126
|
-
} finally {
|
|
29127
|
-
clearTimeout(timer);
|
|
29128
|
-
}
|
|
29129
|
-
}
|
|
29130
|
-
var init_execution_reports = __esm({
|
|
29131
|
-
"src/execution-reports.ts"() {
|
|
29132
|
-
"use strict";
|
|
29133
|
-
}
|
|
29134
|
-
});
|
|
29135
|
-
|
|
29136
28802
|
// src/usage/ledger.ts
|
|
29137
|
-
import { createHmac, randomBytes, randomUUID
|
|
29138
|
-
import { chmodSync as chmodSync2, mkdirSync as mkdirSync3, rmSync as rmSync2, writeFileSync as
|
|
29139
|
-
import { join as
|
|
28803
|
+
import { createHmac, randomBytes, randomUUID } from "node:crypto";
|
|
28804
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync3, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
28805
|
+
import { join as join2 } from "node:path";
|
|
29140
28806
|
import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
|
|
29141
28807
|
function purposeFor(key) {
|
|
29142
28808
|
return key.startsWith("discover") || key === "appsNew" || key === "appsUpdate" ? "discovery" : key.startsWith("setup") ? "setup" : "unknown";
|
|
@@ -29145,7 +28811,7 @@ function countedCommand(key) {
|
|
|
29145
28811
|
return !["root", "version", "helpCommands", "appsSearch", "actionsList", "actionsSearch", "actionsShow", "transportsShow", "appsHistory", "contextShow"].includes(key);
|
|
29146
28812
|
}
|
|
29147
28813
|
function newInvocationId() {
|
|
29148
|
-
return
|
|
28814
|
+
return randomUUID();
|
|
29149
28815
|
}
|
|
29150
28816
|
var UsageLedger;
|
|
29151
28817
|
var init_ledger = __esm({
|
|
@@ -29155,10 +28821,10 @@ var init_ledger = __esm({
|
|
|
29155
28821
|
db;
|
|
29156
28822
|
root;
|
|
29157
28823
|
constructor(dataRoot2) {
|
|
29158
|
-
this.root =
|
|
28824
|
+
this.root = join2(dataRoot2, "usage");
|
|
29159
28825
|
mkdirSync3(this.root, { recursive: true, mode: 448 });
|
|
29160
28826
|
chmodSync2(this.root, 448);
|
|
29161
|
-
const file2 =
|
|
28827
|
+
const file2 = join2(this.root, "ledger.sqlite");
|
|
29162
28828
|
this.db = new DatabaseSync2(file2);
|
|
29163
28829
|
chmodSync2(file2, 384);
|
|
29164
28830
|
this.db.exec("PRAGMA busy_timeout=5000; PRAGMA journal_mode=WAL");
|
|
@@ -29182,8 +28848,8 @@ var init_ledger = __esm({
|
|
|
29182
28848
|
return createHmac("sha256", this.secret()).update(JSON.stringify([runtime, nativeId])).digest("hex");
|
|
29183
28849
|
}
|
|
29184
28850
|
save(value) {
|
|
29185
|
-
const path2 =
|
|
29186
|
-
|
|
28851
|
+
const path2 = join2(this.root, `pending-${value.id}.json`);
|
|
28852
|
+
writeFileSync2(path2, JSON.stringify({ argv: value.argv, stdout: value.stdout, stderr: value.stderr }), { mode: 384, flag: "wx" });
|
|
29187
28853
|
this.db.prepare("INSERT INTO invocation (id,command_key,session_id,agent,started_at,finished_at,duration_ms,argv_json,output_path,purpose,execution_id) VALUES (?,?,?,?,?,?,?,?,?,?,?)").run(value.id, value.commandKey, value.session.id, value.session.agent, value.startedAt, value.finishedAt, value.durationMs, JSON.stringify(value.argv), path2, purposeFor(value.commandKey), value.executionId ?? null);
|
|
29188
28854
|
}
|
|
29189
28855
|
attachExecution(invocationId, executionId) {
|
|
@@ -29214,7 +28880,7 @@ var init_ledger = __esm({
|
|
|
29214
28880
|
this.db.prepare("INSERT INTO usage_meta (key,value) VALUES ('account_id',?) ON CONFLICT(key) DO UPDATE SET value=excluded.value").run(accountId);
|
|
29215
28881
|
}
|
|
29216
28882
|
clearForRevocation() {
|
|
29217
|
-
this.clearForAccountChange(`revoked:${
|
|
28883
|
+
this.clearForAccountChange(`revoked:${randomUUID()}`);
|
|
29218
28884
|
this.db.prepare("DELETE FROM usage_meta WHERE key='account_id'").run();
|
|
29219
28885
|
}
|
|
29220
28886
|
prune() {
|
|
@@ -29236,9 +28902,9 @@ var init_ledger = __esm({
|
|
|
29236
28902
|
});
|
|
29237
28903
|
|
|
29238
28904
|
// src/usage/baselines.ts
|
|
29239
|
-
import { randomUUID as
|
|
29240
|
-
import { chmodSync as chmodSync3, mkdirSync as mkdirSync4, writeFileSync as
|
|
29241
|
-
import { join as
|
|
28905
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
28906
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
28907
|
+
import { join as join3 } from "node:path";
|
|
29242
28908
|
function withBaselines(root, work) {
|
|
29243
28909
|
try {
|
|
29244
28910
|
const ledger = new UsageLedger(root);
|
|
@@ -29275,10 +28941,10 @@ var init_baselines = __esm({
|
|
|
29275
28941
|
finishPreparation(sessionId, appSlug, appId, method, at = /* @__PURE__ */ new Date()) {
|
|
29276
28942
|
const row = this.ledger.db.prepare("SELECT started_at FROM baseline_preparation_start WHERE session_id=? AND app_slug=?").get(sessionId, appSlug);
|
|
29277
28943
|
if (!row || this.ledger.db.prepare("SELECT 1 FROM baseline_candidate WHERE draft_id=?").get(`preparation:${sessionId}:${appId}:${method}`)) return;
|
|
29278
|
-
this.ledger.db.prepare("INSERT INTO baseline_candidate (id,draft_id,app_id,session_id,method,started_at,stopped_at) VALUES (?,?,?,?,?,?,?)").run(
|
|
28944
|
+
this.ledger.db.prepare("INSERT INTO baseline_candidate (id,draft_id,app_id,session_id,method,started_at,stopped_at) VALUES (?,?,?,?,?,?,?)").run(randomUUID2(), `preparation:${sessionId}:${appId}:${method}`, appId, sessionId, method, row.started_at, at.toISOString());
|
|
29279
28945
|
}
|
|
29280
28946
|
startCapture(draftId, appId, sessionId, at = /* @__PURE__ */ new Date()) {
|
|
29281
|
-
const id2 =
|
|
28947
|
+
const id2 = randomUUID2();
|
|
29282
28948
|
this.ledger.db.prepare("UPDATE baseline_candidate SET observation_finished_at=?,observation_reason='next-capture' WHERE session_id=? AND observation_version=1 AND observation_finished_at IS NULL").run(at.toISOString(), sessionId);
|
|
29283
28949
|
this.ledger.db.prepare("INSERT INTO baseline_candidate (id,draft_id,app_id,session_id,method,started_at,observation_version) VALUES (?,?,?,?,?,?,1)").run(id2, draftId, appId, sessionId, "browser", at.toISOString());
|
|
29284
28950
|
return id2;
|
|
@@ -29293,12 +28959,12 @@ var init_baselines = __esm({
|
|
|
29293
28959
|
this.ledger.db.prepare("UPDATE baseline_candidate SET observation_finished_at=?,observation_reason=CASE WHEN stopped_at IS NULL THEN 'cancelled' ELSE 'released' END WHERE draft_id=? AND method='browser' AND observation_version=1 AND observation_finished_at IS NULL").run(at.toISOString(), draftId);
|
|
29294
28960
|
}
|
|
29295
28961
|
recordDirect(input2) {
|
|
29296
|
-
const id2 =
|
|
29297
|
-
const dir =
|
|
28962
|
+
const id2 = randomUUID2(), at = input2.at ?? /* @__PURE__ */ new Date();
|
|
28963
|
+
const dir = join3(this.ledger.root, "pending-baselines");
|
|
29298
28964
|
mkdirSync4(dir, { recursive: true, mode: 448 });
|
|
29299
28965
|
chmodSync3(dir, 448);
|
|
29300
|
-
const path2 =
|
|
29301
|
-
|
|
28966
|
+
const path2 = join3(dir, `${id2}.json`);
|
|
28967
|
+
writeFileSync3(path2, JSON.stringify({ request: input2.request, response: input2.response }), { mode: 384, flag: "wx" });
|
|
29302
28968
|
this.ledger.db.prepare("INSERT INTO baseline_candidate (id,draft_id,app_id,session_id,method,started_at,stopped_at,duration_ms,payload_path,coverage,time_coverage) VALUES (?,?,?,?,?,?,?,?,?,'final','final')").run(id2, input2.draftId, input2.appId, input2.sessionId, "direct", at.toISOString(), at.toISOString(), Math.max(0, Math.round(input2.durationMs)), path2);
|
|
29303
28969
|
if (input2.invocationId) this.ledger.db.prepare("UPDATE baseline_candidate SET invocation_id=?,http_started_at=?,http_finished_at=? WHERE id=?").run(input2.invocationId, input2.startedAt ?? null, input2.finishedAt ?? null, id2);
|
|
29304
28970
|
return id2;
|
|
@@ -30826,7 +30492,7 @@ function draftTemplate(kind) {
|
|
|
30826
30492
|
""
|
|
30827
30493
|
].join("\n") : "";
|
|
30828
30494
|
const tabGuidance = ["action", "transport"].includes(kind) ? "// capture.tab is a selector returned by browser tabs; it selects the same signed-in Chrome tab for capture and discover run, including connection probes. Leave other sessions' tabs untouched.\n" : "";
|
|
30829
|
-
const captureGuidance = kind === "action" ? '// Public descriptions explain behavior, consequences and limits; do not instruct consumers to repeat runtime proof or browser checks. Author verification is separate from consumer judgment.\n// Request JSON/query uses typed {"$input":"name"} bindings; URL segments use {input.name}. Resolve every {unresolved.N} marker from retained evidence before running.\n// Keep only invariant protocol values constant; selected app values are inputs, even when public. Generalize one action across its supported choices.\n// Before discover run, construct verification.inputs from the consumer contract and published value sources. Use a materially different selection and configuration from the captured or documented example, not just another label. Resolve missing configuration sources first; unexplained JSON is not a substitute.\n// Accept verification.review only when the result confirms that selection and configuration and consumers can obtain the required inputs.\n// A readback through POST requires proof.effect: "read" alongside proof.request; HTTP method alone does not determine semantic effect.\n// JSON object keys may use {input.name}, e.g. {"{input.attribute_id}":{"$input":"value"}}.\n// Discovery-only mutation proof compares a readback path with exactly one input, primary result path or internal JSON value: equals: [{"path":"/ready","value":true}]. Public literals require semantic review; fixed proof expectations are not caller flags.\n// Proof URLs bind returned identifiers with {result./id}; JSON bodies/query use {"$result":"/id"}. Readback pointers may use a complete {input.name} segment for a dynamic key; slashes and tildes in its value are escaped.\n// For one member of a nested list: select: {"path":"/ticket/fields","where":[{"path":"/id","result":"/id"}]}; equals paths then refer to the single matching member. Compare identity and meaningful changed fields, not entire objects.\n// Repair a failed response/proof with discover run --proof-only; it reuses the saved primary response and sends only the readback. Publication still needs a successful test and accepted semantic review.\n// For large collections, investigate native search/filter/detail routes before enumeration. Search saved results locally and inspect only matching records; preserve structured dynamic fields.\n// After selecting a captured request, discover capture auth runs a bounded default search without authField or authScope. Set either only to narrow an observed field or location; browser-managed cookies need no locator.\n' : "";
|
|
30495
|
+
const captureGuidance = kind === "action" ? '// Public descriptions explain behavior, consequences and limits; do not instruct consumers to repeat runtime proof or browser checks. Author verification is separate from consumer judgment.\n// Request JSON/query uses typed {"$input":"name"} bindings; URL segments use {input.name}. Resolve every {unresolved.N} marker from retained evidence before running.\n// App-owned input source annotation: {"x-source":{"action":"ticket.list","path":"/*/id"}}. Run the source explicitly; it never runs implicitly.\n// Keep only invariant protocol values constant; selected app values are inputs, even when public. Generalize one action across its supported choices.\n// Before discover run, construct verification.inputs from the consumer contract and published value sources. Use a materially different selection and configuration from the captured or documented example, not just another label. Resolve missing configuration sources first; unexplained JSON is not a substitute.\n// Accept verification.review only when the result confirms that selection and configuration and consumers can obtain the required inputs.\n// A readback through POST requires proof.effect: "read" alongside proof.request; HTTP method alone does not determine semantic effect.\n// JSON object keys may use {input.name}, e.g. {"{input.attribute_id}":{"$input":"value"}}.\n// Discovery-only mutation proof compares a readback path with exactly one input, primary result path or internal JSON value: equals: [{"path":"/ready","value":true}]. Public literals require semantic review; fixed proof expectations are not caller flags.\n// Proof URLs bind returned identifiers with {result./id}; JSON bodies/query use {"$result":"/id"}. Readback pointers may use a complete {input.name} segment for a dynamic key; slashes and tildes in its value are escaped.\n// For one member of a nested list: select: {"path":"/ticket/fields","where":[{"path":"/id","result":"/id"}]}; equals paths then refer to the single matching member. Compare identity and meaningful changed fields, not entire objects.\n// For valid readback variants, keep identity equals and add proof.response: {path:"/state",schema:{enum:["ready","empty"]}}, relative to the selected member. Exclude pending states; use proof-only reads after completion.\n// Repair a failed response/proof with discover run --proof-only; it reuses the saved primary response and sends only the readback. Publication still needs a successful test and accepted semantic review.\n// For large collections, investigate native search/filter/detail routes before enumeration. Search saved results locally and inspect only matching records; preserve structured dynamic fields.\n// After selecting a captured request, discover capture auth runs a bounded default search without authField or authScope. Set either only to narrow an observed field or location; browser-managed cookies need no locator.\n' : "";
|
|
30830
30496
|
return `${head}${probeGuidance}${tabGuidance}${captureGuidance}${JSON.stringify(templates[kind], null, 2)}
|
|
30831
30497
|
`;
|
|
30832
30498
|
}
|
|
@@ -30844,13 +30510,13 @@ var init_envelope = __esm({
|
|
|
30844
30510
|
});
|
|
30845
30511
|
|
|
30846
30512
|
// src/discovery/drafts.ts
|
|
30847
|
-
import { randomUUID as
|
|
30848
|
-
import { chmodSync as chmodSync4, existsSync
|
|
30849
|
-
import { basename, dirname
|
|
30513
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
30514
|
+
import { chmodSync as chmodSync4, existsSync, mkdirSync as mkdirSync5, readFileSync as readFileSync3, renameSync, rmSync as rmSync3, rmdirSync, writeFileSync as writeFileSync4 } from "node:fs";
|
|
30515
|
+
import { basename, dirname, join as join4 } from "node:path";
|
|
30850
30516
|
function pathFor(root, appSlug, kind, name) {
|
|
30851
30517
|
if (!slugPattern.test(appSlug)) throw new Error("App slug is invalid");
|
|
30852
30518
|
if (kind === "action" ? !actionPattern.test(name) : kind !== "app" && !resourcePattern.test(name)) throw new Error("Resource name is invalid");
|
|
30853
|
-
return kind === "app" ?
|
|
30519
|
+
return kind === "app" ? join4(root, "drafts", diskName(appSlug), "app.jsonc") : join4(root, "drafts", diskName(appSlug), paths[kind], `${diskName(name)}.jsonc`);
|
|
30854
30520
|
}
|
|
30855
30521
|
function record2(row) {
|
|
30856
30522
|
return { id: String(row.id), appSlug: String(row.app_slug), appId: row.app_id === null ? null : String(row.app_id), kind: String(row.kind), name: String(row.name), ownerSessionId: row.owner_session_id === null ? null : String(row.owner_session_id), filePath: String(row.file_path), intent: row.intent === "remove" ? "remove" : "edit", baseVersion: row.base_version === null ? null : Number(row.base_version) };
|
|
@@ -30917,12 +30583,12 @@ var init_drafts = __esm({
|
|
|
30917
30583
|
}
|
|
30918
30584
|
const previousSessions = this.state.db.prepare("SELECT session_id FROM discovery_session WHERE app_slug=? AND app_id IS NOT ?").all(appSlug, appId);
|
|
30919
30585
|
const changed = stale.length > 0 || previousSessions.length > 0;
|
|
30920
|
-
const archivedDrafts = changed ?
|
|
30586
|
+
const archivedDrafts = changed ? join4(this.root, "retired-drafts", randomUUID3()) : void 0;
|
|
30921
30587
|
if (archivedDrafts) mkdirSync5(archivedDrafts, { recursive: true, mode: 448 });
|
|
30922
30588
|
for (const draft of stale) {
|
|
30923
|
-
if (
|
|
30924
|
-
const archived =
|
|
30925
|
-
mkdirSync5(
|
|
30589
|
+
if (existsSync(draft.filePath)) {
|
|
30590
|
+
const archived = join4(archivedDrafts, paths[draft.kind], basename(draft.filePath));
|
|
30591
|
+
mkdirSync5(dirname(archived), { recursive: true, mode: 448 });
|
|
30926
30592
|
renameSync(draft.filePath, archived);
|
|
30927
30593
|
moved.push({ from: draft.filePath, to: archived });
|
|
30928
30594
|
}
|
|
@@ -30933,9 +30599,9 @@ var init_drafts = __esm({
|
|
|
30933
30599
|
}
|
|
30934
30600
|
if (changed && this.hasTable("discovery_research")) {
|
|
30935
30601
|
const research = this.state.db.prepare("SELECT file_path FROM discovery_research WHERE app_slug=?").all(appSlug);
|
|
30936
|
-
for (const row of research) if (
|
|
30937
|
-
const archived =
|
|
30938
|
-
mkdirSync5(
|
|
30602
|
+
for (const row of research) if (existsSync(row.file_path)) {
|
|
30603
|
+
const archived = join4(archivedDrafts, "api", basename(row.file_path));
|
|
30604
|
+
mkdirSync5(dirname(archived), { recursive: true, mode: 448 });
|
|
30939
30605
|
renameSync(row.file_path, archived);
|
|
30940
30606
|
moved.push({ from: row.file_path, to: archived });
|
|
30941
30607
|
}
|
|
@@ -30998,7 +30664,7 @@ var init_drafts = __esm({
|
|
|
30998
30664
|
const serialized = JSON.stringify(body);
|
|
30999
30665
|
const existing = this.publication(draftId);
|
|
31000
30666
|
if (existing) return existing;
|
|
31001
|
-
const intent = { requestId:
|
|
30667
|
+
const intent = { requestId: randomUUID3(), requestBody: serialized };
|
|
31002
30668
|
this.state.db.prepare("INSERT INTO discovery_publication (draft_id,request_id,request_body) VALUES (?,?,?)").run(draftId, intent.requestId, serialized);
|
|
31003
30669
|
return intent;
|
|
31004
30670
|
}
|
|
@@ -31035,9 +30701,9 @@ var init_drafts = __esm({
|
|
|
31035
30701
|
this.state.db.prepare("INSERT INTO discovery_request_attempt (draft_id,fingerprint,state,response_path,response_digest) VALUES (?,?,?,?,?) ON CONFLICT(draft_id,fingerprint) DO UPDATE SET state=excluded.state,response_path=CASE WHEN excluded.state='possibly-dispatched' AND excluded.response_path IS NULL THEN NULL ELSE COALESCE(excluded.response_path,discovery_request_attempt.response_path) END,response_digest=CASE WHEN excluded.state='possibly-dispatched' AND excluded.response_path IS NULL THEN NULL ELSE COALESCE(excluded.response_digest,discovery_request_attempt.response_digest) END").run(draftId, fingerprint2, state, responsePath ?? null, responseDigest ?? null);
|
|
31036
30702
|
}
|
|
31037
30703
|
artifactPath(draftId, name) {
|
|
31038
|
-
const directory =
|
|
30704
|
+
const directory = join4(this.root, "draft-evidence", draftId, randomUUID3());
|
|
31039
30705
|
mkdirSync5(directory, { recursive: true, mode: 448 });
|
|
31040
|
-
return
|
|
30706
|
+
return join4(directory, name);
|
|
31041
30707
|
}
|
|
31042
30708
|
finished(sessionId) {
|
|
31043
30709
|
const row = this.state.db.prepare("SELECT result_json FROM discovery_finished WHERE session_id=?").get(sessionId);
|
|
@@ -31048,7 +30714,7 @@ var init_drafts = __esm({
|
|
|
31048
30714
|
if (!draft) return null;
|
|
31049
30715
|
if (publishedResult === void 0 && this.publication(draft.id)) throw new DraftConflict("selected-draft", "A publication request may have been sent; reconcile it before discarding this draft");
|
|
31050
30716
|
withBaselines(this.root, (baselines) => baselines.closeObservation(draft.id, "released"));
|
|
31051
|
-
const paths2 = [draft.filePath, `${draft.filePath}.current.json`,
|
|
30717
|
+
const paths2 = [draft.filePath, `${draft.filePath}.current.json`, join4(this.root, "draft-evidence", draft.id)];
|
|
31052
30718
|
const evidence = this.evidence(draft.id);
|
|
31053
30719
|
if (evidence) paths2.push(evidence.resultPath);
|
|
31054
30720
|
if (this.hasTable("discovery_request_attempt")) for (const row of this.state.db.prepare("SELECT response_path FROM discovery_request_attempt WHERE draft_id=? AND response_path IS NOT NULL").all(draft.id)) paths2.push(row.response_path);
|
|
@@ -31079,12 +30745,12 @@ var init_drafts = __esm({
|
|
|
31079
30745
|
async cleanup(closeScope) {
|
|
31080
30746
|
for (const row of this.state.db.prepare("SELECT * FROM discovery_cleanup").all()) {
|
|
31081
30747
|
for (const path2 of new Set(JSON.parse(row.paths_json))) {
|
|
31082
|
-
rmSync3(path2, { force: true, recursive: path2 ===
|
|
31083
|
-
let parent =
|
|
31084
|
-
while (parent !== this.root && parent.startsWith(`${
|
|
30748
|
+
rmSync3(path2, { force: true, recursive: path2 === join4(this.root, "draft-evidence", row.draft_id) });
|
|
30749
|
+
let parent = dirname(path2);
|
|
30750
|
+
while (parent !== this.root && parent.startsWith(`${join4(this.root, "drafts")}/`)) {
|
|
31085
30751
|
try {
|
|
31086
30752
|
rmdirSync(parent);
|
|
31087
|
-
parent =
|
|
30753
|
+
parent = dirname(parent);
|
|
31088
30754
|
} catch {
|
|
31089
30755
|
break;
|
|
31090
30756
|
}
|
|
@@ -31110,13 +30776,13 @@ var init_drafts = __esm({
|
|
|
31110
30776
|
if (existing?.owner_session_id && existing.owner_session_id !== input2.sessionId) throw new DraftConflict("owned-draft", `${input2.kind} ${name} is owned by another agent session; its file was preserved`);
|
|
31111
30777
|
if (existing && existing.app_id !== (input2.appId ?? null)) throw new DraftConflict("selected-draft", "The retained draft belongs to a different app; reopen the app from its current registry identity before editing");
|
|
31112
30778
|
if (existing) filePath = String(existing.file_path);
|
|
31113
|
-
const id2 = existing ? String(existing.id) :
|
|
30779
|
+
const id2 = existing ? String(existing.id) : randomUUID3();
|
|
31114
30780
|
if (!existing) this.state.db.prepare("INSERT INTO discovery_draft (id,app_slug,app_id,kind,name,owner_session_id,file_path,base_version) VALUES (?,?,?,?,?,?,?,?)").run(id2, input2.appSlug, input2.appId ?? null, input2.kind, name, input2.sessionId, filePath, input2.baseVersion ?? null);
|
|
31115
30781
|
else this.state.db.prepare("UPDATE discovery_draft SET owner_session_id=? WHERE id=?").run(input2.sessionId, id2);
|
|
31116
30782
|
this.state.db.prepare("DELETE FROM discovery_deferred WHERE draft_id=?").run(id2);
|
|
31117
30783
|
this.state.db.prepare("INSERT INTO selected_discovery_draft (session_id,draft_id) VALUES (?,?) ON CONFLICT(session_id) DO UPDATE SET draft_id=excluded.draft_id").run(input2.sessionId, id2);
|
|
31118
|
-
mkdirSync5(
|
|
31119
|
-
if (!
|
|
30784
|
+
mkdirSync5(dirname(filePath), { recursive: true, mode: 448 });
|
|
30785
|
+
if (!existsSync(filePath) && existing?.intent !== "remove") writeFileSync4(filePath, draftTemplate(input2.kind), { flag: "wx", mode: 384 });
|
|
31120
30786
|
chmodSync4(filePath, 384);
|
|
31121
30787
|
const result3 = this.selected(input2.sessionId);
|
|
31122
30788
|
this.state.db.exec("COMMIT");
|
|
@@ -31142,11 +30808,11 @@ var init_drafts = __esm({
|
|
|
31142
30808
|
this.state.db.exec("COMMIT");
|
|
31143
30809
|
return this.selected(input2.sessionId);
|
|
31144
30810
|
}
|
|
31145
|
-
const id2 =
|
|
30811
|
+
const id2 = randomUUID3();
|
|
31146
30812
|
this.state.db.prepare("INSERT INTO discovery_draft (id,app_slug,app_id,kind,name,owner_session_id,file_path,base_version,intent) VALUES (?,?,?,?,?,?,?,?,'remove')").run(id2, input2.appSlug, input2.appId, input2.kind, input2.name, input2.sessionId, filePath, input2.baseVersion);
|
|
31147
30813
|
this.state.db.prepare("INSERT INTO selected_discovery_draft (session_id,draft_id) VALUES (?,?)").run(input2.sessionId, id2);
|
|
31148
|
-
mkdirSync5(
|
|
31149
|
-
|
|
30814
|
+
mkdirSync5(dirname(filePath), { recursive: true, mode: 448 });
|
|
30815
|
+
writeFileSync4(filePath, `// Publish to remove this resource. No records inside the app are changed.
|
|
31150
30816
|
${JSON.stringify({ remove: true, expectedVersion: input2.baseVersion }, null, 2)}
|
|
31151
30817
|
`, { flag: "wx", mode: 384 });
|
|
31152
30818
|
this.state.db.exec("COMMIT");
|
|
@@ -31156,31 +30822,367 @@ ${JSON.stringify({ remove: true, expectedVersion: input2.baseVersion }, null, 2)
|
|
|
31156
30822
|
throw error62;
|
|
31157
30823
|
}
|
|
31158
30824
|
}
|
|
31159
|
-
defer(sessionId) {
|
|
31160
|
-
this.state.db.exec("BEGIN IMMEDIATE");
|
|
31161
|
-
try {
|
|
31162
|
-
const draft = this.selected(sessionId);
|
|
31163
|
-
if (draft) {
|
|
31164
|
-
withBaselines(this.root, (baselines) => baselines.closeObservation(draft.id, "released"));
|
|
31165
|
-
this.state.db.prepare("INSERT INTO discovery_deferred (draft_id,session_id) VALUES (?,?) ON CONFLICT(draft_id) DO UPDATE SET session_id=excluded.session_id").run(draft.id, sessionId);
|
|
31166
|
-
this.state.db.prepare("DELETE FROM selected_discovery_draft WHERE session_id=?").run(sessionId);
|
|
31167
|
-
this.state.db.prepare("UPDATE discovery_draft SET owner_session_id=NULL WHERE id=? AND owner_session_id=?").run(draft.id, sessionId);
|
|
31168
|
-
}
|
|
31169
|
-
this.state.db.exec("COMMIT");
|
|
31170
|
-
return draft;
|
|
31171
|
-
} catch (error62) {
|
|
31172
|
-
this.state.db.exec("ROLLBACK");
|
|
31173
|
-
throw error62;
|
|
30825
|
+
defer(sessionId) {
|
|
30826
|
+
this.state.db.exec("BEGIN IMMEDIATE");
|
|
30827
|
+
try {
|
|
30828
|
+
const draft = this.selected(sessionId);
|
|
30829
|
+
if (draft) {
|
|
30830
|
+
withBaselines(this.root, (baselines) => baselines.closeObservation(draft.id, "released"));
|
|
30831
|
+
this.state.db.prepare("INSERT INTO discovery_deferred (draft_id,session_id) VALUES (?,?) ON CONFLICT(draft_id) DO UPDATE SET session_id=excluded.session_id").run(draft.id, sessionId);
|
|
30832
|
+
this.state.db.prepare("DELETE FROM selected_discovery_draft WHERE session_id=?").run(sessionId);
|
|
30833
|
+
this.state.db.prepare("UPDATE discovery_draft SET owner_session_id=NULL WHERE id=? AND owner_session_id=?").run(draft.id, sessionId);
|
|
30834
|
+
}
|
|
30835
|
+
this.state.db.exec("COMMIT");
|
|
30836
|
+
return draft;
|
|
30837
|
+
} catch (error62) {
|
|
30838
|
+
this.state.db.exec("ROLLBACK");
|
|
30839
|
+
throw error62;
|
|
30840
|
+
}
|
|
30841
|
+
}
|
|
30842
|
+
readSelected(sessionId) {
|
|
30843
|
+
const draft = this.selected(sessionId);
|
|
30844
|
+
return draft ? { draft, source: readFileSync3(draft.filePath, "utf8") } : null;
|
|
30845
|
+
}
|
|
30846
|
+
};
|
|
30847
|
+
}
|
|
30848
|
+
});
|
|
30849
|
+
|
|
30850
|
+
// src/version.ts
|
|
30851
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
30852
|
+
var cliVersion;
|
|
30853
|
+
var init_version = __esm({
|
|
30854
|
+
"src/version.ts"() {
|
|
30855
|
+
"use strict";
|
|
30856
|
+
cliVersion = JSON.parse(readFileSync4(new URL("../package.json", import.meta.url), "utf8")).version;
|
|
30857
|
+
}
|
|
30858
|
+
});
|
|
30859
|
+
|
|
30860
|
+
// src/api.ts
|
|
30861
|
+
function retryDelay(response, attempt) {
|
|
30862
|
+
const value = response.headers.get("retry-after");
|
|
30863
|
+
if (value) {
|
|
30864
|
+
const seconds = Number(value);
|
|
30865
|
+
if (Number.isFinite(seconds) && seconds >= 0) return Math.min(seconds * 1e3, 5e3);
|
|
30866
|
+
const date5 = Date.parse(value);
|
|
30867
|
+
if (Number.isFinite(date5)) return Math.min(Math.max(date5 - Date.now(), 0), 5e3);
|
|
30868
|
+
}
|
|
30869
|
+
return 250 * 2 ** attempt;
|
|
30870
|
+
}
|
|
30871
|
+
function sleep(ms) {
|
|
30872
|
+
return new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
30873
|
+
}
|
|
30874
|
+
function createCliApi(baseUrl, fetcher = fetch, token, sessionId) {
|
|
30875
|
+
const transport = async (input2, init) => {
|
|
30876
|
+
const method = init?.method ?? "GET";
|
|
30877
|
+
const headers = new Headers(init?.headers);
|
|
30878
|
+
headers.set("Apilift-Capabilities", "distributed-rollouts-v1,discovery-proof-v2,dynamic-bindings-v1");
|
|
30879
|
+
headers.set("Apilift-Client", `cli/${cliVersion}`);
|
|
30880
|
+
if (token) headers.set("Authorization", `Bearer ${token}`);
|
|
30881
|
+
if (sessionId) headers.set("Apilift-Session", sessionId);
|
|
30882
|
+
const path2 = new URL(input2 instanceof Request ? input2.url : String(input2), baseUrl).pathname;
|
|
30883
|
+
const timeoutMs = method === "POST" && path2 === "/api/v1/installations" ? 3e4 : 1e4;
|
|
30884
|
+
for (let attempt = 0; ; attempt++) {
|
|
30885
|
+
try {
|
|
30886
|
+
const response = await fetcher(input2, { ...init, headers, signal: init?.signal ?? AbortSignal.timeout(timeoutMs) });
|
|
30887
|
+
if (method !== "GET" || attempt >= 2 || !retryStatuses.has(response.status)) {
|
|
30888
|
+
if (response.status !== 204 && !response.headers.get("content-type")?.toLowerCase().includes("json")) throw new ApiClientError(response.status, null);
|
|
30889
|
+
if (response.status !== 204) {
|
|
30890
|
+
try {
|
|
30891
|
+
await response.clone().json();
|
|
30892
|
+
} catch {
|
|
30893
|
+
throw new ApiClientError(response.status, null);
|
|
30894
|
+
}
|
|
30895
|
+
}
|
|
30896
|
+
return response;
|
|
30897
|
+
}
|
|
30898
|
+
await sleep(retryDelay(response, attempt));
|
|
30899
|
+
} catch (error62) {
|
|
30900
|
+
if (error62 instanceof ApiClientError) throw error62;
|
|
30901
|
+
if (method !== "GET") throw new ApiDeliveryUncertainError(error62);
|
|
30902
|
+
if (attempt >= 2) throw new ApiReadUnavailableError(error62);
|
|
30903
|
+
await sleep(250 * 2 ** attempt);
|
|
30904
|
+
}
|
|
30905
|
+
}
|
|
30906
|
+
};
|
|
30907
|
+
return createApiClient(baseUrl, transport);
|
|
30908
|
+
}
|
|
30909
|
+
var retryStatuses, ApiDeliveryUncertainError, ApiReadUnavailableError;
|
|
30910
|
+
var init_api3 = __esm({
|
|
30911
|
+
"src/api.ts"() {
|
|
30912
|
+
"use strict";
|
|
30913
|
+
init_version();
|
|
30914
|
+
init_api2();
|
|
30915
|
+
retryStatuses = /* @__PURE__ */ new Set([408, 429, 502, 503, 504]);
|
|
30916
|
+
ApiDeliveryUncertainError = class extends Error {
|
|
30917
|
+
constructor(cause) {
|
|
30918
|
+
super("The Registry did not confirm whether the mutation was applied");
|
|
30919
|
+
this.cause = cause;
|
|
30920
|
+
}
|
|
30921
|
+
};
|
|
30922
|
+
ApiReadUnavailableError = class extends Error {
|
|
30923
|
+
constructor(cause) {
|
|
30924
|
+
super("The Registry could not be reached after three attempts");
|
|
30925
|
+
this.cause = cause;
|
|
30926
|
+
}
|
|
30927
|
+
};
|
|
30928
|
+
}
|
|
30929
|
+
});
|
|
30930
|
+
|
|
30931
|
+
// src/commands/registry.ts
|
|
30932
|
+
function parseInvocation(argv) {
|
|
30933
|
+
const issues = [];
|
|
30934
|
+
let cursor = 0;
|
|
30935
|
+
let sessionLabel;
|
|
30936
|
+
let version2 = false;
|
|
30937
|
+
while (cursor < argv.length) {
|
|
30938
|
+
const token = argv[cursor];
|
|
30939
|
+
if (token === "--session") {
|
|
30940
|
+
const value = argv[cursor + 1];
|
|
30941
|
+
if (!value || value.startsWith("--")) issues.push("--session needs a worker label");
|
|
30942
|
+
else if (sessionLabel) issues.push("--session may appear only once");
|
|
30943
|
+
else sessionLabel = value;
|
|
30944
|
+
cursor += value && !value.startsWith("--") ? 2 : 1;
|
|
30945
|
+
} else if (token === "--version") {
|
|
30946
|
+
version2 = true;
|
|
30947
|
+
cursor++;
|
|
30948
|
+
} else break;
|
|
30949
|
+
}
|
|
30950
|
+
if (sessionLabel && (sessionLabel.length > 80 || !/^[A-Za-z0-9_-]+$/u.test(sessionLabel))) issues.push("--session must be 1 to 80 letters, digits, hyphens or underscores");
|
|
30951
|
+
const base2 = { sessionLabel, positionals: [], options: {}, flags: [], repeats: {}, actionArgs: [] };
|
|
30952
|
+
if (version2) {
|
|
30953
|
+
if (cursor < argv.length) issues.push("--version takes no command");
|
|
30954
|
+
return { ...issues.length ? {} : { invocation: { key: "version", ...base2 } }, issues };
|
|
30955
|
+
}
|
|
30956
|
+
const remaining = argv.slice(cursor);
|
|
30957
|
+
if (remaining.length === 1 && remaining[0] === "--help") return { invocation: { key: "helpCommands", ...base2 }, issues };
|
|
30958
|
+
const selected = Object.entries(commandRegistry).filter(([, command7]) => command7.path.every((part, index) => remaining[index] === part)).sort((left, right) => right[1].path.length - left[1].path.length)[0];
|
|
30959
|
+
if (!selected) return { issues: [`Unknown command: ${remaining.slice(0, 2).join(" ")}`] };
|
|
30960
|
+
const [key, command6] = selected;
|
|
30961
|
+
const positionals = [];
|
|
30962
|
+
const options2 = {};
|
|
30963
|
+
const flags = [];
|
|
30964
|
+
const repeats = {};
|
|
30965
|
+
const actionArgs = [];
|
|
30966
|
+
for (let index = command6.path.length; index < remaining.length; index++) {
|
|
30967
|
+
const token = remaining[index];
|
|
30968
|
+
if (token.startsWith("--")) {
|
|
30969
|
+
const name = token.slice(2);
|
|
30970
|
+
if (name === "session") {
|
|
30971
|
+
issues.push("--session must appear before the command");
|
|
30972
|
+
continue;
|
|
30973
|
+
}
|
|
30974
|
+
if (command6.values?.includes(name) || command6.repeat?.includes(name)) {
|
|
30975
|
+
const value = remaining[index + 1];
|
|
30976
|
+
if (!value || value.startsWith("--")) {
|
|
30977
|
+
issues.push(`--${name} needs a value`);
|
|
30978
|
+
continue;
|
|
31174
30979
|
}
|
|
31175
|
-
|
|
31176
|
-
|
|
31177
|
-
|
|
31178
|
-
|
|
31179
|
-
}
|
|
30980
|
+
if (command6.repeat?.includes(name)) (repeats[name] ??= []).push(value);
|
|
30981
|
+
else if (Object.hasOwn(options2, name)) issues.push(`--${name} may appear only once`);
|
|
30982
|
+
else options2[name] = value;
|
|
30983
|
+
index++;
|
|
30984
|
+
} else if (command6.flags?.includes(name)) {
|
|
30985
|
+
if (flags.includes(name)) issues.push(`--${name} may appear only once`);
|
|
30986
|
+
else flags.push(name);
|
|
30987
|
+
} else if (command6.actionFlags && positionals.length >= 2) actionArgs.push(token);
|
|
30988
|
+
else issues.push(`Unknown option --${name}`);
|
|
30989
|
+
} else if (command6.actionFlags && positionals.length >= 2 && actionArgs.length) actionArgs.push(token);
|
|
30990
|
+
else if (positionals.length < command6.max) positionals.push(token);
|
|
30991
|
+
else issues.push(`Unexpected argument ${token}`);
|
|
30992
|
+
}
|
|
30993
|
+
if (positionals.length < command6.min) issues.push(`${command6.path.join(" ") || "command"} needs ${command6.min} argument${command6.min === 1 ? "" : "s"}`);
|
|
30994
|
+
return { ...issues.length ? {} : { invocation: { key, sessionLabel, positionals, options: options2, flags, repeats, actionArgs } }, issues };
|
|
30995
|
+
}
|
|
30996
|
+
var commandRegistry;
|
|
30997
|
+
var init_registry = __esm({
|
|
30998
|
+
"src/commands/registry.ts"() {
|
|
30999
|
+
"use strict";
|
|
31000
|
+
commandRegistry = {
|
|
31001
|
+
root: { path: [], min: 0, max: 0 },
|
|
31002
|
+
setup: { path: ["setup"], min: 0, max: 0, values: ["code"] },
|
|
31003
|
+
setupContinue: { path: ["setup", "continue"], min: 0, max: 0 },
|
|
31004
|
+
doctor: { path: ["doctor"], min: 0, max: 0, values: ["app"] },
|
|
31005
|
+
update: { path: ["update"], min: 0, max: 0 },
|
|
31006
|
+
helpCommands: { path: ["help", "commands"], min: 0, max: 0 },
|
|
31007
|
+
appsSearch: { path: ["apps", "search"], min: 1, max: 1, values: ["domain", "limit", "cursor"] },
|
|
31008
|
+
appsUse: { path: ["apps", "use"], min: 1, max: 1 },
|
|
31009
|
+
appsRelease: { path: ["apps", "release"], min: 1, max: 1 },
|
|
31010
|
+
appsRefresh: { path: ["apps", "refresh"], min: 1, max: 1, values: ["action"] },
|
|
31011
|
+
appsNew: { path: ["apps", "new"], min: 1, max: 1 },
|
|
31012
|
+
appsUpdate: { path: ["apps", "update"], min: 1, max: 1 },
|
|
31013
|
+
appsHistory: { path: ["apps", "history"], min: 1, max: 1, values: ["resource", "limit", "cursor"] },
|
|
31014
|
+
actionsList: { path: ["actions", "list"], min: 1, max: 1, values: ["entity", "limit", "cursor"], flags: ["all"] },
|
|
31015
|
+
actionsSearch: { path: ["actions", "search"], min: 2, max: 2, values: ["entity", "limit", "cursor"] },
|
|
31016
|
+
actionsShow: { path: ["actions", "show"], min: 2, max: 11, values: ["input-template"], flags: ["schema"] },
|
|
31017
|
+
run: { path: ["run"], min: 2, max: 2, values: ["input", "output"], flags: ["check", "no-context"], repeat: ["select"], actionFlags: true },
|
|
31018
|
+
credentialsList: { path: ["credentials", "list"], min: 1, max: 2 },
|
|
31019
|
+
credentialsUse: { path: ["credentials", "use"], min: 3, max: 3 },
|
|
31020
|
+
credentialsAdd: { path: ["credentials", "add"], min: 2, max: 2 },
|
|
31021
|
+
credentialsRemove: { path: ["credentials", "remove"], min: 3, max: 3 },
|
|
31022
|
+
credentialsUnbound: { path: ["credentials", "unbound"], min: 0, max: 0 },
|
|
31023
|
+
credentialsAttach: { path: ["credentials", "attach"], min: 3, max: 3 },
|
|
31024
|
+
transportsShow: { path: ["transports", "show"], min: 1, max: 2 },
|
|
31025
|
+
browserCheck: { path: ["browser", "check"], min: 1, max: 1 },
|
|
31026
|
+
browserTabs: { path: ["browser", "tabs"], min: 1, max: 1, values: ["select"] },
|
|
31027
|
+
contextSet: { path: ["context", "set"], min: 2, max: 2, values: ["app"] },
|
|
31028
|
+
contextShow: { path: ["context", "show"], min: 0, max: 0, values: ["app"] },
|
|
31029
|
+
contextUnset: { path: ["context", "unset"], min: 1, max: 1, values: ["app"] },
|
|
31030
|
+
contextClear: { path: ["context", "clear"], min: 0, max: 0, values: ["app"] },
|
|
31031
|
+
discoverDraft: { path: ["discover", "draft"], min: 1, max: 2 },
|
|
31032
|
+
discoverCheck: { path: ["discover", "check"], min: 0, max: 0 },
|
|
31033
|
+
discoverRun: { path: ["discover", "run"], min: 0, max: 0, flags: ["proof-only"] },
|
|
31034
|
+
discoverPublish: { path: ["discover", "publish"], min: 0, max: 0 },
|
|
31035
|
+
discoverStatus: { path: ["discover", "status"], min: 0, max: 0 },
|
|
31036
|
+
discoverDefer: { path: ["discover", "defer"], min: 0, max: 0 },
|
|
31037
|
+
discoverDiscard: { path: ["discover", "discard"], min: 0, max: 0 },
|
|
31038
|
+
discoverRebase: { path: ["discover", "rebase"], min: 0, max: 0 },
|
|
31039
|
+
discoverRemove: { path: ["discover", "remove"], min: 2, max: 2 },
|
|
31040
|
+
discoverClose: { path: ["discover", "close"], min: 0, max: 0 },
|
|
31041
|
+
discoverApiAssess: { path: ["discover", "api", "assess"], min: 1, max: 1 },
|
|
31042
|
+
discoverApiSave: { path: ["discover", "api", "save"], min: 0, max: 0 },
|
|
31043
|
+
discoverApiStatus: { path: ["discover", "api", "status"], min: 0, max: 1 },
|
|
31044
|
+
discoverCaptureStart: { path: ["discover", "capture", "start"], min: 0, max: 0 },
|
|
31045
|
+
discoverCaptureStop: { path: ["discover", "capture", "stop"], min: 0, max: 0 },
|
|
31046
|
+
discoverCaptureList: { path: ["discover", "capture", "list"], min: 0, max: 0, values: ["limit", "cursor"] },
|
|
31047
|
+
discoverCaptureShow: { path: ["discover", "capture", "show"], min: 1, max: 1, values: ["part", "pointer"] },
|
|
31048
|
+
discoverCaptureSelect: { path: ["discover", "capture", "select"], min: 1, max: 1 },
|
|
31049
|
+
discoverCaptureAuth: { path: ["discover", "capture", "auth"], min: 1, max: 1 },
|
|
31050
|
+
discoverCaptureCancel: { path: ["discover", "capture", "cancel"], min: 0, max: 0 }
|
|
31180
31051
|
};
|
|
31181
31052
|
}
|
|
31182
31053
|
});
|
|
31183
31054
|
|
|
31055
|
+
// src/session.ts
|
|
31056
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
31057
|
+
function apiSessionId(installationId, session) {
|
|
31058
|
+
if (!session) return void 0;
|
|
31059
|
+
const hex3 = createHash2("sha256").update("apilift-api-session/v1\0").update(installationId).update("\0").update(session.id).digest("hex");
|
|
31060
|
+
return `${hex3.slice(0, 8)}-${hex3.slice(8, 12)}-5${hex3.slice(13, 16)}-a${hex3.slice(17, 20)}-${hex3.slice(20, 32)}`;
|
|
31061
|
+
}
|
|
31062
|
+
function agentSession(env, explicitLabel) {
|
|
31063
|
+
explicitLabel ??= env.APILIFT_SESSION;
|
|
31064
|
+
if (explicitLabel !== void 0 && !/^[A-Za-z0-9_-]{1,80}$/u.test(explicitLabel)) return null;
|
|
31065
|
+
const codex = env.CODEX_THREAD_ID || env.CODEX_SESSION_ID;
|
|
31066
|
+
const claude = env.CLAUDE_CODE_SESSION_ID;
|
|
31067
|
+
if (explicitLabel) {
|
|
31068
|
+
const agent2 = claude || env.CLAUDECODE ? "claude" : codex || env.CODEX_HOME ? "codex" : null;
|
|
31069
|
+
return agent2 ? { id: `${agent2}:label:${explicitLabel}`, agent: agent2 } : null;
|
|
31070
|
+
}
|
|
31071
|
+
if (codex && !claude) return { id: `codex:${codex}`, agent: "codex" };
|
|
31072
|
+
if (claude && !codex) return { id: `claude:${claude}`, agent: "claude" };
|
|
31073
|
+
return null;
|
|
31074
|
+
}
|
|
31075
|
+
function commandPrefix(label2) {
|
|
31076
|
+
return `apilift${label2 ? ` --session ${label2}` : ""}`;
|
|
31077
|
+
}
|
|
31078
|
+
var init_session = __esm({
|
|
31079
|
+
"src/session.ts"() {
|
|
31080
|
+
"use strict";
|
|
31081
|
+
}
|
|
31082
|
+
});
|
|
31083
|
+
|
|
31084
|
+
// src/browser-response.ts
|
|
31085
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
31086
|
+
async function browserResponseBody(client, scopeId, value, maxBytes = 48 * 1024 * 1024) {
|
|
31087
|
+
if (value.bodyArtifact !== void 0) {
|
|
31088
|
+
const artifact = value.bodyArtifact;
|
|
31089
|
+
if (value.body != null || !artifact || typeof artifact.sha256 !== "string" || !/^[0-9a-f]{64}$/.test(artifact.sha256) || !Number.isInteger(artifact.bytes) || Number(artifact.bytes) < 1 || Number(artifact.bytes) > maxBytes || artifact.encoding !== "utf-8") throw new Error("Chrome returned invalid response evidence metadata");
|
|
31090
|
+
const bytes = await client.blob(scopeId, artifact.sha256);
|
|
31091
|
+
if (!bytes || bytes.length !== artifact.bytes || createHash3("sha256").update(bytes).digest("hex") !== artifact.sha256) throw new Error("Chrome response evidence is missing or failed its integrity check");
|
|
31092
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
31093
|
+
}
|
|
31094
|
+
if (value.body == null) return null;
|
|
31095
|
+
if (typeof value.body !== "string" || Buffer.byteLength(value.body, "utf8") > maxBytes) throw new Error("Chrome did not return complete response evidence");
|
|
31096
|
+
return value.body;
|
|
31097
|
+
}
|
|
31098
|
+
var init_browser_response = __esm({
|
|
31099
|
+
"src/browser-response.ts"() {
|
|
31100
|
+
"use strict";
|
|
31101
|
+
}
|
|
31102
|
+
});
|
|
31103
|
+
|
|
31104
|
+
// src/timings.ts
|
|
31105
|
+
import { appendFileSync } from "node:fs";
|
|
31106
|
+
import { resolve } from "node:path";
|
|
31107
|
+
function executionTimings() {
|
|
31108
|
+
return { brokerMs: 0, bridgeMs: 0, registryMs: 0, bindingMs: 0, replayMs: 0, appMs: 0, proofMs: 0, reportingMs: 0 };
|
|
31109
|
+
}
|
|
31110
|
+
async function timed(timings, stage, work) {
|
|
31111
|
+
const started = performance.now();
|
|
31112
|
+
try {
|
|
31113
|
+
return await work();
|
|
31114
|
+
} finally {
|
|
31115
|
+
if (timings) timings[stage] += performance.now() - started;
|
|
31116
|
+
}
|
|
31117
|
+
}
|
|
31118
|
+
function saveTimings(timings, commandMs) {
|
|
31119
|
+
if (!process.env.APILIFT_TIMING_FILE) return;
|
|
31120
|
+
try {
|
|
31121
|
+
appendFileSync(resolve(process.env.APILIFT_TIMING_FILE), JSON.stringify({ ...Object.fromEntries(Object.entries(timings).map(([key, value]) => [key, Math.round(value * 100) / 100])), commandMs: Math.round(commandMs * 100) / 100 }) + "\n", { mode: 384 });
|
|
31122
|
+
} catch {
|
|
31123
|
+
}
|
|
31124
|
+
}
|
|
31125
|
+
var init_timings = __esm({
|
|
31126
|
+
"src/timings.ts"() {
|
|
31127
|
+
"use strict";
|
|
31128
|
+
}
|
|
31129
|
+
});
|
|
31130
|
+
|
|
31131
|
+
// src/files.ts
|
|
31132
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
31133
|
+
import { accessSync, constants, existsSync as existsSync2, statSync, unlinkSync, writeFileSync as writeFileSync5 } from "node:fs";
|
|
31134
|
+
import { dirname as dirname2, join as join5, resolve as resolve2 } from "node:path";
|
|
31135
|
+
function outputDestination(file2) {
|
|
31136
|
+
const target = resolve2(file2);
|
|
31137
|
+
if (existsSync2(target)) {
|
|
31138
|
+
if (!statSync(target).isFile()) throw new Error("Output destination must be a regular file");
|
|
31139
|
+
accessSync(target, constants.W_OK);
|
|
31140
|
+
}
|
|
31141
|
+
const probe = join5(dirname2(target), `.apilift-output-check-${randomUUID4()}`);
|
|
31142
|
+
try {
|
|
31143
|
+
writeFileSync5(probe, "", { flag: "wx", mode: 384 });
|
|
31144
|
+
} finally {
|
|
31145
|
+
try {
|
|
31146
|
+
unlinkSync(probe);
|
|
31147
|
+
} catch {
|
|
31148
|
+
}
|
|
31149
|
+
}
|
|
31150
|
+
return target;
|
|
31151
|
+
}
|
|
31152
|
+
var init_files = __esm({
|
|
31153
|
+
"src/files.ts"() {
|
|
31154
|
+
"use strict";
|
|
31155
|
+
}
|
|
31156
|
+
});
|
|
31157
|
+
|
|
31158
|
+
// src/execution-reports.ts
|
|
31159
|
+
async function flushExecutionReports(api, state, budgetMs = 1e4) {
|
|
31160
|
+
const pending = state.pendingExecutionReports();
|
|
31161
|
+
if (!pending.length) return;
|
|
31162
|
+
const controller = new AbortController();
|
|
31163
|
+
let timer;
|
|
31164
|
+
try {
|
|
31165
|
+
const acknowledgment = await Promise.race([
|
|
31166
|
+
api.call("postExecutions", { body: { reports: pending.map((item) => item.report) }, signal: controller.signal }),
|
|
31167
|
+
new Promise((_, reject) => {
|
|
31168
|
+
timer = setTimeout(() => {
|
|
31169
|
+
controller.abort();
|
|
31170
|
+
reject(new Error("Report delivery deferred"));
|
|
31171
|
+
}, budgetMs);
|
|
31172
|
+
})
|
|
31173
|
+
]);
|
|
31174
|
+
state.acknowledgeExecutionReports(acknowledgment.results.map((item) => item.id));
|
|
31175
|
+
} catch {
|
|
31176
|
+
} finally {
|
|
31177
|
+
clearTimeout(timer);
|
|
31178
|
+
}
|
|
31179
|
+
}
|
|
31180
|
+
var init_execution_reports = __esm({
|
|
31181
|
+
"src/execution-reports.ts"() {
|
|
31182
|
+
"use strict";
|
|
31183
|
+
}
|
|
31184
|
+
});
|
|
31185
|
+
|
|
31184
31186
|
// src/discovery/credential-draft.ts
|
|
31185
31187
|
import { createHash as createHash4 } from "node:crypto";
|
|
31186
31188
|
import { readFileSync as readFileSync5 } from "node:fs";
|
|
@@ -32908,6 +32910,11 @@ function confirmProof(proof, body, primary, inputs, status) {
|
|
|
32908
32910
|
for (const comparison of proof.equals ?? []) {
|
|
32909
32911
|
if (!matches(comparison, selected)) throw new ResponseContractFailure(`Readback comparison failed at ${comparison.path || "/"}`);
|
|
32910
32912
|
}
|
|
32913
|
+
if (proof.response) {
|
|
32914
|
+
const value = proof.response.path !== void 0 ? pointer2(selected, proofPath(proof.response.path, inputs)) : selected;
|
|
32915
|
+
const validate2 = ajv3.compile(proof.response.schema);
|
|
32916
|
+
if (!validate2(value)) throw new ResponseContractFailure(`Readback response contract mismatch: ${ajv3.errorsText(validate2.errors, { dataVar: "readback" })}`);
|
|
32917
|
+
}
|
|
32911
32918
|
}
|
|
32912
32919
|
async function handleRun(invocation, api, state, session, fetcher, root, stdin = () => readFileSync7(0, "utf8"), onReport) {
|
|
32913
32920
|
const [appName, actionName] = invocation.positionals;
|
|
@@ -33152,7 +33159,7 @@ async function executeDraftVerification(input2) {
|
|
|
33152
33159
|
const generated = input2.primaryEvidence?.generated ?? (input2.kind === "action" && action && "generated" in action ? Object.fromEntries(Object.entries(action.generated ?? {}).map(([name, spec]) => [name, `${spec.prefix ?? ""}${randomUUID7()}`])) : {});
|
|
33153
33160
|
try {
|
|
33154
33161
|
values = effectiveInputs(schema, input2.primaryEvidence?.inputs ?? input2.sampleInputs, {}, true).values;
|
|
33155
|
-
if (action && "proof" in action && action.proof) for (const item of [...action.proof.equals ?? [], ...action.proof.select?.where ?? [], ...action.proof.select ? [action.proof.select] : []]) proofPath(item.path, values);
|
|
33162
|
+
if (action && "proof" in action && action.proof) for (const item of [...action.proof.equals ?? [], ...action.proof.select?.where ?? [], ...action.proof.select ? [action.proof.select] : [], ...action.proof.response?.path !== void 0 ? [{ path: action.proof.response.path }] : []]) proofPath(item.path, values);
|
|
33156
33163
|
const request2 = input2.kind === "action" ? action.request : probe.request;
|
|
33157
33164
|
prepared = prepareRequest(request2, input2.kind === "transport" && input2.probeOrigin ? { ...transport, baseUrl: input2.probeOrigin } : transport, values, generated);
|
|
33158
33165
|
} catch (error62) {
|
|
@@ -34245,7 +34252,7 @@ Publish removal: ${command4(invocation, "discover publish")}
|
|
|
34245
34252
|
Abandon removal: ${command4(invocation, "discover discard")}
|
|
34246
34253
|
`);
|
|
34247
34254
|
}
|
|
34248
|
-
function draftGuidance(invocation, draft, unavailable = false) {
|
|
34255
|
+
function draftGuidance(invocation, draft, unavailable = false, resumed = false) {
|
|
34249
34256
|
if (draft.intent === "remove") return `Selected the retained removal of ${label(draft.kind)} ${draft.name}. Nothing has been removed.
|
|
34250
34257
|
Review: ${draft.filePath}
|
|
34251
34258
|
Check dependencies: ${command4(invocation, "discover check")}
|
|
@@ -34259,6 +34266,10 @@ Recover this file: ${command4(invocation, "discover status")}
|
|
|
34259
34266
|
Keep for later (including evidence): ${command4(invocation, "discover defer")}
|
|
34260
34267
|
Abandon unpublished edits: ${command4(invocation, "discover discard")}
|
|
34261
34268
|
`;
|
|
34269
|
+
if (resumed) return `Resumed ${prefix}. Existing edits and evidence were retained.
|
|
34270
|
+
Edit: ${draft.filePath}
|
|
34271
|
+
|
|
34272
|
+
${local}`;
|
|
34262
34273
|
if (draft.kind === "app") return `Created an app draft for ${draft.appSlug}. Nothing has been published.
|
|
34263
34274
|
Edit: ${draft.filePath}
|
|
34264
34275
|
|
|
@@ -34322,6 +34333,7 @@ Create or edit it with ${command4(invocation, "discover draft action <entity.ver
|
|
|
34322
34333
|
File: ${selected.filePath}
|
|
34323
34334
|
`, 12);
|
|
34324
34335
|
const resource = current.appId ? await currentResource(api, current.appId, kind, name ?? "app") : null;
|
|
34336
|
+
const resumed = store.retained(current.appSlug).some((item) => item.kind === kind && item.name === (name ?? "app") && existsSync4(item.filePath));
|
|
34325
34337
|
const draft = store.open({ appSlug: current.appSlug, appId: current.appId ?? void 0, kind, name, sessionId: session.id, baseVersion: resource?.version });
|
|
34326
34338
|
if (draft.intent === "remove" && store.publication(draft.id)) return fail5(`A removal publication may have been sent. Reconcile its retained request with ${command4(invocation, "discover publish")} before changing, deferring or discarding it.
|
|
34327
34339
|
File: ${draft.filePath}
|
|
@@ -34334,7 +34346,7 @@ File: ${draft.filePath}
|
|
|
34334
34346
|
`, { mode: 384 });
|
|
34335
34347
|
}
|
|
34336
34348
|
void root;
|
|
34337
|
-
return ok4(draftGuidance(invocation, draft, Boolean(parseDraftEnvelope(readFileSync8(draft.filePath, "utf8")).envelope?.definition.unavailable)));
|
|
34349
|
+
return ok4(draftGuidance(invocation, draft, Boolean(parseDraftEnvelope(readFileSync8(draft.filePath, "utf8")).envelope?.definition.unavailable), resumed));
|
|
34338
34350
|
}
|
|
34339
34351
|
function requireDiscovery(store, session, invocation) {
|
|
34340
34352
|
const current = store.session(session.id);
|
|
@@ -35502,7 +35514,7 @@ async function finalizeOutput(output2, sink, directory = tmpdir2()) {
|
|
|
35502
35514
|
const size = () => Buffer.byteLength(stdout) + Buffer.byteLength(stderr);
|
|
35503
35515
|
try {
|
|
35504
35516
|
if (size() > displayBudget) {
|
|
35505
|
-
const root = await mkdtemp(join13(directory, "apilift-output-"));
|
|
35517
|
+
const root = await mkdtemp(join13(output2.outputDirectory ?? directory, "apilift-output-"));
|
|
35506
35518
|
await chmod(root, 448);
|
|
35507
35519
|
const streams = ["stdout", "stderr"];
|
|
35508
35520
|
streams.sort((left, right) => Buffer.byteLength(output2[right]) - Buffer.byteLength(output2[left]));
|
|
@@ -38892,6 +38904,7 @@ __export(cli_exports, {
|
|
|
38892
38904
|
runCli: () => runCli
|
|
38893
38905
|
});
|
|
38894
38906
|
import { hostname as hostname3, platform as platform3, arch } from "node:os";
|
|
38907
|
+
import { dirname as dirname13 } from "node:path";
|
|
38895
38908
|
function result2(stdout = "", exitCode = 0, stderr = "", dispatched = false) {
|
|
38896
38909
|
return { stdout, stderr, exitCode, dispatched };
|
|
38897
38910
|
}
|
|
@@ -39009,7 +39022,14 @@ Open ${site}/dashboard/get-started and then run:
|
|
|
39009
39022
|
}
|
|
39010
39023
|
if (invocation.key.startsWith("credentials") || invocation.key === "transportsShow") return await handleCredentials(invocation, api, state, session, site, dataRoot(env));
|
|
39011
39024
|
if (invocation.key.startsWith("browser")) return await handleBrowser(invocation, api, state, session, dataRoot(env));
|
|
39012
|
-
if (invocation.key.startsWith("discover") || ["appsNew", "appsUpdate", "appsHistory"].includes(invocation.key))
|
|
39025
|
+
if (invocation.key.startsWith("discover") || ["appsNew", "appsUpdate", "appsHistory"].includes(invocation.key)) {
|
|
39026
|
+
const output2 = await handleDiscover(invocation, api, state, session, fetcher, dataRoot(env), invocationId);
|
|
39027
|
+
if (session && Buffer.byteLength(output2.stdout) + Buffer.byteLength(output2.stderr) > displayBudget) {
|
|
39028
|
+
const store = new DraftStore(state, dataRoot(env)), draft = store.selected(session.id);
|
|
39029
|
+
if (draft?.ownerSessionId === session.id) output2.outputDirectory = dirname13(store.artifactPath(draft.id, "output"));
|
|
39030
|
+
}
|
|
39031
|
+
return output2;
|
|
39032
|
+
}
|
|
39013
39033
|
if (invocation.key === "run") return await handleRun(invocation, api, state, session, fetcher, dataRoot(env), void 0, onReport);
|
|
39014
39034
|
if (invocation.key === "setupContinue") {
|
|
39015
39035
|
await api.call("me");
|
|
@@ -39200,6 +39220,7 @@ var init_cli = __esm({
|
|
|
39200
39220
|
"use strict";
|
|
39201
39221
|
init_receipts();
|
|
39202
39222
|
init_lock();
|
|
39223
|
+
init_drafts();
|
|
39203
39224
|
init_api2();
|
|
39204
39225
|
init_api3();
|
|
39205
39226
|
init_registry();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apilift/cli",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": ">=24.16.0 <27"
|
|
38
38
|
},
|
|
39
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "77f4acfa3f2652928fea0a82245cc55b52a84e64",
|
|
40
40
|
"repository": {
|
|
41
41
|
"type": "git",
|
|
42
42
|
"url": "git+https://github.com/egor-sergeev/apilift.git",
|