Add documentation to the commands for the CLI
This commit is contained in:
@@ -42,6 +42,7 @@ function parseVariablesFromOptions(
|
||||
): { variableIdentifier: string; value: string; roleIdentifier?: string }[] {
|
||||
const roleIdentifier = options["role"];
|
||||
|
||||
// Parse the variables from the options by checking if its starts with "var"
|
||||
return Object.entries(options)
|
||||
.filter(([key]) => key.startsWith("var"))
|
||||
.map(([key, value]) => ({
|
||||
@@ -81,10 +82,12 @@ async function buildAppendParams(
|
||||
const suitableResources = await invitation.findSuitableResources();
|
||||
const selectable = mapUnspentOutputsToSelectable(suitableResources);
|
||||
|
||||
// Get the required sats out with the default fee
|
||||
const requiredWithFee =
|
||||
(await invitation.getSatsOut().catch(() => 0n)) + DEFAULT_FEE;
|
||||
autoSelectGreedyUtxos(selectable, requiredWithFee);
|
||||
|
||||
// Get the inputs from the selectable UTXOs
|
||||
inputs = selectable
|
||||
.filter((u) => u.selected)
|
||||
.map((u) => ({
|
||||
@@ -92,12 +95,15 @@ async function buildAppendParams(
|
||||
outpointIndex: u.outpointIndex,
|
||||
}));
|
||||
|
||||
// If no inputs are found, print a message and return null
|
||||
if (inputs.length === 0) {
|
||||
deps.io.err("No suitable UTXOs found for auto-input selection.");
|
||||
return null;
|
||||
}
|
||||
deps.io.verbose(`Auto-selected ${inputs.length} input(s)`);
|
||||
} else if (options["addInput"]) {
|
||||
}
|
||||
// If the add input option is provided, parse the inputs from the options
|
||||
else if (options["addInput"]) {
|
||||
inputs = options["addInput"].split(",").map((entry) => {
|
||||
const separatorIndex = entry.lastIndexOf(":");
|
||||
if (separatorIndex === -1) {
|
||||
@@ -105,8 +111,12 @@ async function buildAppendParams(
|
||||
`Invalid input format "${entry}". Expected <txhash>:<vout> (e.g. abc123:0)`,
|
||||
);
|
||||
}
|
||||
|
||||
// Get the tx hash and vout from the entry
|
||||
const txHash = entry.substring(0, separatorIndex);
|
||||
const vout = parseInt(entry.substring(separatorIndex + 1), 10);
|
||||
|
||||
// If the tx hash or vout is not a string or isNaN, print a message and throw an error
|
||||
if (!txHash || isNaN(vout)) {
|
||||
throw new Error(
|
||||
`Invalid input format "${entry}". Expected <txhash>:<vout> (e.g. abc123:0)`,
|
||||
@@ -161,10 +171,12 @@ async function buildAppendParams(
|
||||
}
|
||||
}
|
||||
|
||||
// Get the template from the engine
|
||||
const template = await deps.app.engine.getTemplate(
|
||||
invitation.data.templateIdentifier,
|
||||
);
|
||||
|
||||
// Get the outputs from the template
|
||||
const outputs: any[] = await Promise.all(
|
||||
outputIdentifiers.map(async (outputId) => {
|
||||
// Try variable-based resolution first (e.g. sendSatoshis → recipientLockingscript)
|
||||
@@ -205,28 +217,37 @@ async function buildAppendParams(
|
||||
]),
|
||||
);
|
||||
|
||||
// Sum the total input sats
|
||||
let totalInputSats = 0n;
|
||||
// Iterate through the inputs and sum the valueSatoshis
|
||||
for (const input of inputs) {
|
||||
// Get the tx hash hex
|
||||
const txHashHex = binToHex(input.outpointTransactionHash);
|
||||
// Get the utxo from the utxo map
|
||||
const utxo = utxoMap.get(`${txHashHex}:${input.outpointIndex}`);
|
||||
if (!utxo) {
|
||||
// If the utxo is not found, print a message and return null
|
||||
deps.io.err(
|
||||
`UTXO not found: ${txHashHex}:${input.outpointIndex}. Make sure it exists in your wallet.`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
// Sum the valueSatoshis
|
||||
totalInputSats += BigInt(utxo.valueSatoshis);
|
||||
}
|
||||
deps.io.verbose(`Total input value: ${totalInputSats} satoshis`);
|
||||
|
||||
// Get the required sats out
|
||||
const requiredSats = await invitation.getSatsOut();
|
||||
deps.io.verbose(`Required output value: ${requiredSats} satoshis`);
|
||||
|
||||
// Get the change amount by subtracting the required sats out from the total input sats and the default fee
|
||||
const changeAmount = totalInputSats - requiredSats - DEFAULT_FEE;
|
||||
deps.io.verbose(
|
||||
`Change amount: ${changeAmount} satoshis (fee: ${DEFAULT_FEE})`,
|
||||
);
|
||||
|
||||
// If the change amount is less than 0, print a message and return null
|
||||
if (changeAmount < 0n) {
|
||||
deps.io.err(
|
||||
`Insufficient funds. Inputs total ${totalInputSats} sats, but need ${requiredSats + DEFAULT_FEE} sats (${requiredSats} required + ${DEFAULT_FEE} fee).`,
|
||||
@@ -234,10 +255,13 @@ async function buildAppendParams(
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the change amount is greater than or equal to the dust threshold, add the change output
|
||||
if (changeAmount >= DUST_THRESHOLD) {
|
||||
outputs.push({ valueSatoshis: changeAmount });
|
||||
deps.io.out(`Auto-adding change output: ${changeAmount} satoshis`);
|
||||
} else if (changeAmount > 0n) {
|
||||
}
|
||||
// If the change amount is greater than 0, print a message
|
||||
else if (changeAmount > 0n) {
|
||||
deps.io.out(
|
||||
`Change ${changeAmount} sats is below dust threshold (${DUST_THRESHOLD} sats), donating to miners as fee.`,
|
||||
);
|
||||
@@ -311,6 +335,7 @@ export const handleInvitationCommand = async (
|
||||
const subCommand = args[0];
|
||||
deps.io.verbose(`Invitation sub-command: ${subCommand}`);
|
||||
|
||||
// If there was no subcommand provided, print the help message and throw an error
|
||||
if (!subCommand) {
|
||||
deps.io.verbose("No sub-command provided");
|
||||
printInvitationHelp(deps.io);
|
||||
@@ -320,14 +345,18 @@ export const handleInvitationCommand = async (
|
||||
);
|
||||
}
|
||||
|
||||
// Switch statement to handle the different subcommands
|
||||
switch (subCommand) {
|
||||
case "create": {
|
||||
// Get the template query and action identifier from the arguments
|
||||
const templateQuery = args[1];
|
||||
const actionIdentifier = args[2];
|
||||
deps.io.verbose(
|
||||
`Template query: ${templateQuery}, action identifier: ${actionIdentifier}`,
|
||||
);
|
||||
|
||||
// If they didnt provide us with a template query or action identifier, print the help message and throw an error
|
||||
// TODO: Should probably print a specific help message for this command?
|
||||
if (!templateQuery || !actionIdentifier) {
|
||||
deps.io.verbose("No template file or action identifier provided");
|
||||
printInvitationHelp(deps.io);
|
||||
@@ -337,25 +366,31 @@ export const handleInvitationCommand = async (
|
||||
);
|
||||
}
|
||||
|
||||
// Resolve the template, this will check both filepath and identifier. Because we are flexible here, we will need to generate the identifier again after
|
||||
const template = await resolveTemplate(deps, templateQuery);
|
||||
const templateIdentifier = generateTemplateIdentifier(template);
|
||||
|
||||
// Create an XOInvitation. We will convert this into our own invitation instance afterwards
|
||||
const rawInvitation = await deps.app.engine.createInvitation({
|
||||
templateIdentifier,
|
||||
actionIdentifier,
|
||||
});
|
||||
deps.io.verbose(`XOInvitation created: ${formatObject(rawInvitation)}`);
|
||||
|
||||
// Create our own invitation instance out of the raw XOInvitation. This will also initate the SSE Session
|
||||
const invitationInstance = await deps.app.createInvitation(rawInvitation);
|
||||
deps.io.verbose(
|
||||
`Invitation created: ${formatObject(invitationInstance.data)}`,
|
||||
);
|
||||
|
||||
// Read the variables that were passed in via `-var-<name> <value>`
|
||||
const variables = parseVariablesFromOptions(options);
|
||||
deps.io.verbose(`Variables: ${formatObject(variables)}`);
|
||||
if (variables.length > 0) {
|
||||
await invitationInstance.addVariables(variables);
|
||||
}
|
||||
|
||||
// Build the parameters for the append call. This will resolve the inputs and outputs for the invitation.
|
||||
const params = await buildAppendParams(deps, invitationInstance, options);
|
||||
if (!params) {
|
||||
throw new CommandError(
|
||||
@@ -364,11 +399,14 @@ export const handleInvitationCommand = async (
|
||||
);
|
||||
}
|
||||
|
||||
// Append the inputs and outputs to the invitation
|
||||
const { inputs, outputs } = params;
|
||||
if (inputs.length > 0 || outputs.length > 0) {
|
||||
await invitationInstance.append({ inputs, outputs });
|
||||
}
|
||||
|
||||
// Write the invitation to a file in the working directory
|
||||
// TODO: Support the -o flag to specify the output path
|
||||
const invitationFilePath = `${deps.paths.workingDir}/inv-${invitationInstance.data.invitationIdentifier}.json`;
|
||||
deps.io.verbose(`Invitation file path: ${invitationFilePath}`);
|
||||
writeFileSync(
|
||||
@@ -379,6 +417,7 @@ export const handleInvitationCommand = async (
|
||||
`Invitation created: ${path.basename(invitationFilePath)} (${invitationInstance.data.invitationIdentifier})`,
|
||||
);
|
||||
|
||||
// Get the missing requirements for the invitation. This will tell us if we are missing any variables, inputs, outputs, or roles.
|
||||
const missingRequirements =
|
||||
await invitationInstance.getMissingRequirements();
|
||||
const hasMissing =
|
||||
@@ -388,14 +427,17 @@ export const handleInvitationCommand = async (
|
||||
(missingRequirements.roles !== undefined &&
|
||||
Object.keys(missingRequirements.roles).length > 0);
|
||||
|
||||
// If there are missing requirements, print them out
|
||||
if (hasMissing) {
|
||||
deps.io.out(`\n${bold("Remaining requirements:")}`);
|
||||
deps.io.out(formatObject(missingRequirements));
|
||||
} else {
|
||||
// If there are no missing requirements, sign the invitation if the user has requested it
|
||||
const shouldSign =
|
||||
options["sign"] === "true" || options["broadcast"] === "true";
|
||||
const shouldBroadcast = options["broadcast"] === "true";
|
||||
|
||||
// Sign the invitation if the user has requested it
|
||||
if (shouldSign) {
|
||||
await invitationInstance.sign();
|
||||
deps.io.out(
|
||||
@@ -403,6 +445,7 @@ export const handleInvitationCommand = async (
|
||||
);
|
||||
}
|
||||
|
||||
// Broadcast the transaction if the user has requested it
|
||||
if (shouldBroadcast) {
|
||||
const txHash = await invitationInstance.broadcast();
|
||||
deps.io.out(`Transaction broadcast: ${bold(txHash)}`);
|
||||
@@ -412,15 +455,20 @@ export const handleInvitationCommand = async (
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the invitation identifier
|
||||
return {
|
||||
invitationIdentifier: invitationInstance.data.invitationIdentifier,
|
||||
};
|
||||
}
|
||||
|
||||
case "append": {
|
||||
// Get the invitation identifier from the arguments
|
||||
const invitationIdentifier = args[1];
|
||||
deps.io.verbose(`Invitation identifier: ${invitationIdentifier}`);
|
||||
|
||||
// If they didnt provide us with an invitation identifier, print the help message and throw an error
|
||||
// TODO: Should probably print a specific help message for this command?
|
||||
if (!invitationIdentifier) {
|
||||
deps.io.verbose("No invitation identifier provided");
|
||||
printInvitationHelp(deps.io);
|
||||
@@ -430,9 +478,12 @@ export const handleInvitationCommand = async (
|
||||
);
|
||||
}
|
||||
|
||||
// Find the invitation instance in our list of invitations
|
||||
const invitation = deps.app.invitations.find(
|
||||
(inv) => inv.data.invitationIdentifier === invitationIdentifier,
|
||||
);
|
||||
|
||||
// If the invitation is not found, print an error and throw an error
|
||||
if (!invitation) {
|
||||
deps.io.err(`Invitation not found: ${invitationIdentifier}`);
|
||||
throw new CommandError(
|
||||
@@ -442,12 +493,14 @@ export const handleInvitationCommand = async (
|
||||
}
|
||||
deps.io.verbose(`Invitation: ${formatObject(invitation.data)}`);
|
||||
|
||||
// Parse the variables that were passed in via `-var-<name> <value>`
|
||||
const variables = parseVariablesFromOptions(options);
|
||||
deps.io.verbose(`Variables to append: ${formatObject(variables)}`);
|
||||
if (variables.length > 0) {
|
||||
await invitation.addVariables(variables);
|
||||
}
|
||||
|
||||
// Build the parameters for the append call. This will resolve the inputs and outputs for the invitation.
|
||||
const params = await buildAppendParams(deps, invitation, options);
|
||||
if (!params) {
|
||||
throw new CommandError(
|
||||
@@ -456,6 +509,7 @@ export const handleInvitationCommand = async (
|
||||
);
|
||||
}
|
||||
|
||||
// If there are no variables, inputs, or outputs, print an error and throw an error
|
||||
const { inputs, outputs } = params;
|
||||
if (
|
||||
variables.length === 0 &&
|
||||
@@ -468,18 +522,22 @@ export const handleInvitationCommand = async (
|
||||
throw new CommandError("invitation.append.empty", error);
|
||||
}
|
||||
|
||||
// Append the inputs and outputs to the invitation
|
||||
if (inputs.length > 0 || outputs.length > 0) {
|
||||
await invitation.append({ inputs, outputs });
|
||||
}
|
||||
deps.io.verbose(`Invitation appended: ${formatObject(invitation.data)}`);
|
||||
deps.io.out(`Invitation appended: ${invitationIdentifier}`);
|
||||
|
||||
// Write the invitation to a file in the working directory
|
||||
// TODO: Support the -o flag to specify the output path
|
||||
const invitationFilePath = `${deps.paths.workingDir}/inv-${invitation.data.invitationIdentifier}.json`;
|
||||
writeFileSync(invitationFilePath, encodeExtendedJson(invitation.data, 2));
|
||||
deps.io.out(
|
||||
`Invitation updated: ${path.basename(invitationFilePath)} (${invitation.data.invitationIdentifier})`,
|
||||
);
|
||||
|
||||
// Get the missing requirements for the invitation. This will tell us if we are missing any variables, inputs, outputs, or roles.
|
||||
const missingRequirements = await invitation.getMissingRequirements();
|
||||
const hasMissing =
|
||||
(missingRequirements.variables?.length ?? 0) > 0 ||
|
||||
@@ -488,19 +546,23 @@ export const handleInvitationCommand = async (
|
||||
(missingRequirements.roles !== undefined &&
|
||||
Object.keys(missingRequirements.roles).length > 0);
|
||||
|
||||
// If there are missing requirements, print them out
|
||||
if (hasMissing) {
|
||||
deps.io.out(`\n${bold("Remaining requirements:")}`);
|
||||
deps.io.out(formatObject(missingRequirements));
|
||||
} else {
|
||||
// If there are no missing requirements, sign the invitation if the user has requested it
|
||||
const shouldSign =
|
||||
options["sign"] === "true" || options["broadcast"] === "true";
|
||||
const shouldBroadcast = options["broadcast"] === "true";
|
||||
|
||||
// Sign the invitation if the user has requested it
|
||||
if (shouldSign) {
|
||||
await invitation.sign();
|
||||
deps.io.out(`Invitation signed: ${invitationIdentifier}`);
|
||||
}
|
||||
|
||||
// Broadcast the transaction if the user has requested it
|
||||
if (shouldBroadcast) {
|
||||
const txHash = await invitation.broadcast();
|
||||
deps.io.out(`Transaction broadcast: ${bold(txHash)}`);
|
||||
@@ -514,8 +576,12 @@ export const handleInvitationCommand = async (
|
||||
}
|
||||
|
||||
case "sign": {
|
||||
// Get the invitation identifier from the arguments
|
||||
const invitationIdentifier = args[1];
|
||||
deps.io.verbose(`Invitation identifier: ${invitationIdentifier}`);
|
||||
|
||||
// If they didnt provide us with an invitation identifier, print the help message and throw an error
|
||||
// TODO: Should probably print a specific help message for this command?
|
||||
if (!invitationIdentifier) {
|
||||
deps.io.verbose("No invitation identifier provided");
|
||||
printInvitationHelp(deps.io);
|
||||
@@ -525,10 +591,13 @@ export const handleInvitationCommand = async (
|
||||
);
|
||||
}
|
||||
|
||||
// Find the invitation instance in our list of invitations
|
||||
const invitation = deps.app.invitations.find(
|
||||
(candidate) =>
|
||||
candidate.data.invitationIdentifier === invitationIdentifier,
|
||||
);
|
||||
|
||||
// If the invitation is not found, print an error and throw an error
|
||||
if (!invitation) {
|
||||
deps.io.err(`Invitation not found: ${invitationIdentifier}`);
|
||||
throw new CommandError(
|
||||
@@ -538,15 +607,22 @@ export const handleInvitationCommand = async (
|
||||
}
|
||||
deps.io.verbose(`Invitation: ${formatObject(invitation.data)}`);
|
||||
|
||||
// Sign the invitation
|
||||
await invitation.sign();
|
||||
deps.io.verbose(`Invitation signed: ${formatObject(invitation.data)}`);
|
||||
deps.io.out(`Invitation signed: ${invitationIdentifier}`);
|
||||
|
||||
// Return the invitation identifier
|
||||
return { invitationIdentifier };
|
||||
}
|
||||
|
||||
|
||||
case "broadcast": {
|
||||
// Get the invitation identifier from the arguments
|
||||
const invitationIdentifier = args[1];
|
||||
deps.io.verbose(`Invitation identifier: ${invitationIdentifier}`);
|
||||
|
||||
// If they didnt provide us with an invitation identifier, print the help message and throw an error
|
||||
// TODO: Should probably print a specific help message for this command?
|
||||
if (!invitationIdentifier) {
|
||||
deps.io.verbose("No invitation identifier provided");
|
||||
printInvitationHelp(deps.io);
|
||||
@@ -556,10 +632,13 @@ export const handleInvitationCommand = async (
|
||||
);
|
||||
}
|
||||
|
||||
// Find the invitation instance in our list of invitations
|
||||
const invitation = deps.app.invitations.find(
|
||||
(candidate) =>
|
||||
candidate.data.invitationIdentifier === invitationIdentifier,
|
||||
);
|
||||
|
||||
// If the invitation is not found, print an error and throw an error
|
||||
if (!invitation) {
|
||||
deps.io.err(`Invitation not found: ${invitationIdentifier}`);
|
||||
throw new CommandError(
|
||||
@@ -569,17 +648,24 @@ export const handleInvitationCommand = async (
|
||||
}
|
||||
deps.io.verbose(`Invitation: ${formatObject(invitation.data)}`);
|
||||
|
||||
// Broadcast the transaction
|
||||
const txHash = await invitation.broadcast();
|
||||
deps.io.verbose(
|
||||
`Invitation broadcasted: ${formatObject(invitation.data)}`,
|
||||
);
|
||||
deps.io.out(`Transaction broadcast: ${bold(txHash)}`);
|
||||
|
||||
// Return the invitation identifier and transaction hash
|
||||
return { invitationIdentifier, txHash };
|
||||
}
|
||||
|
||||
case "requirements": {
|
||||
// Get the invitation identifier from the arguments
|
||||
const invitationIdentifier = args[1];
|
||||
deps.io.verbose(`Invitation identifier: ${invitationIdentifier}`);
|
||||
|
||||
// If they didnt provide us with an invitation identifier, print the help message and throw an error
|
||||
// TODO: Should probably print a specific help message for this command?
|
||||
if (!invitationIdentifier) {
|
||||
deps.io.verbose("No invitation identifier provided");
|
||||
printInvitationHelp(deps.io);
|
||||
@@ -589,10 +675,13 @@ export const handleInvitationCommand = async (
|
||||
);
|
||||
}
|
||||
|
||||
// Find the invitation instance in our list of invitations
|
||||
const invitation = deps.app.invitations.find(
|
||||
(candidate) =>
|
||||
candidate.data.invitationIdentifier === invitationIdentifier,
|
||||
);
|
||||
|
||||
// If the invitation is not found, print an error and throw an error
|
||||
if (!invitation) {
|
||||
deps.io.err(`Invitation not found: ${invitationIdentifier}`);
|
||||
throw new CommandError(
|
||||
@@ -602,18 +691,26 @@ export const handleInvitationCommand = async (
|
||||
}
|
||||
deps.io.verbose(`Invitation: ${formatObject(invitation.data)}`);
|
||||
|
||||
// List the requirements for the invitation
|
||||
const requirements = await deps.app.engine.listRequirements(
|
||||
invitation.data,
|
||||
);
|
||||
deps.io.verbose(`Requirements: ${formatObject(requirements)}`);
|
||||
deps.io.out(formatObject(requirements));
|
||||
|
||||
// Return the invitation identifier
|
||||
return { invitationIdentifier };
|
||||
}
|
||||
|
||||
case "inspect": {
|
||||
// Get the invitation file path from the arguments
|
||||
const invitationFilePath = args[1];
|
||||
|
||||
// If they didnt provide us with an invitation file path, print the help message and throw an error
|
||||
// TODO: Should probably print a specific help message for this command?
|
||||
deps.io.verbose(`Invitation file path: ${invitationFilePath}`);
|
||||
|
||||
// Read the invitation file
|
||||
if (!invitationFilePath) {
|
||||
deps.io.verbose("No invitation file provided");
|
||||
printInvitationHelp(deps.io);
|
||||
@@ -623,24 +720,31 @@ export const handleInvitationCommand = async (
|
||||
);
|
||||
}
|
||||
|
||||
// Read the invitation file (XOInvitation format, can be passed to the engine directly)
|
||||
const invitationFile = await readFileSync(invitationFilePath, "utf8");
|
||||
deps.io.verbose(`Invitation file: ${invitationFile}`);
|
||||
|
||||
// Parse the invitation file
|
||||
const invitation = JSON.parse(invitationFile);
|
||||
deps.io.verbose(`Invitation: ${formatObject(invitation)}`);
|
||||
|
||||
// Create the invitation instance (NOTE: Not an engine compatible invitation. This is the wrapped format)
|
||||
const invitationInstance = await deps.app.createInvitation(invitation);
|
||||
deps.io.verbose(
|
||||
`Invitation created: ${formatObject(invitationInstance.data)}`,
|
||||
);
|
||||
|
||||
// Get the template for the invitation
|
||||
const template = await deps.app.engine.getTemplate(
|
||||
invitationInstance.data.templateIdentifier,
|
||||
);
|
||||
|
||||
// Get the action for the invitation
|
||||
const action =
|
||||
template?.actions[invitationInstance.data.actionIdentifier];
|
||||
deps.io.verbose(`Action: ${formatObject(action)}`);
|
||||
|
||||
// If the action is not found, print an error and throw an error
|
||||
if (!action) {
|
||||
deps.io.err(
|
||||
`Action not found: ${invitationInstance.data.actionIdentifier}`,
|
||||
@@ -651,9 +755,11 @@ export const handleInvitationCommand = async (
|
||||
);
|
||||
}
|
||||
|
||||
// Get the status for the invitation
|
||||
const status = invitationInstance.status;
|
||||
deps.io.verbose(`Status: ${status}`);
|
||||
|
||||
// Get the entities for the invitation
|
||||
const entities = Array.from(
|
||||
new Set(
|
||||
invitationInstance.data.commits.map(
|
||||
@@ -663,6 +769,7 @@ export const handleInvitationCommand = async (
|
||||
);
|
||||
deps.io.verbose(`Entities: ${formatObject(entities)}`);
|
||||
|
||||
// Get the entities with roles for the invitation
|
||||
const entitiesWithRoles = entities.map((entity) => {
|
||||
return {
|
||||
entityIdentifier: entity,
|
||||
@@ -685,21 +792,25 @@ export const handleInvitationCommand = async (
|
||||
};
|
||||
});
|
||||
|
||||
// Get the inputs for the invitation
|
||||
const inputs = invitationInstance.data.commits.flatMap(
|
||||
(commit) => commit.data.inputs ?? [],
|
||||
);
|
||||
deps.io.verbose(`Inputs: ${formatObject(inputs)}`);
|
||||
|
||||
// Get the outputs for the invitation
|
||||
const outputs = invitationInstance.data.commits.flatMap(
|
||||
(commit) => commit.data.outputs ?? [],
|
||||
);
|
||||
deps.io.verbose(`Outputs: ${formatObject(outputs)}`);
|
||||
|
||||
// Get the variables for the invitation
|
||||
const variables = invitationInstance.data.commits.flatMap(
|
||||
(commit) => commit.data.variables ?? [],
|
||||
);
|
||||
deps.io.verbose(`Variables: ${formatObject(variables)}`);
|
||||
|
||||
// Return the invitation details
|
||||
return {
|
||||
templateName: template?.name ?? "Unknown",
|
||||
actionIdentifier: invitationInstance.data.actionIdentifier,
|
||||
@@ -712,9 +823,12 @@ export const handleInvitationCommand = async (
|
||||
}
|
||||
|
||||
case "import": {
|
||||
// Get the invitation file path from the arguments
|
||||
const invitationFilePath = args[1];
|
||||
deps.io.verbose(`Invitation file path: ${invitationFilePath}`);
|
||||
|
||||
// If they didnt provide us with an invitation file path, print the help message and throw an error
|
||||
// TODO: Should probably print a specific help message for this command?
|
||||
if (!invitationFilePath) {
|
||||
deps.io.verbose("No invitation file provided");
|
||||
printInvitationHelp(deps.io);
|
||||
@@ -724,26 +838,41 @@ export const handleInvitationCommand = async (
|
||||
);
|
||||
}
|
||||
|
||||
// Read the invitation file (XOInvitation format, can be passed to the engine directly)
|
||||
const invitationFile = await readFileSync(invitationFilePath, "utf8");
|
||||
deps.io.verbose(`Invitation file: ${invitationFile}`);
|
||||
|
||||
// Parse the invitation file
|
||||
const invitation = JSON.parse(invitationFile);
|
||||
deps.io.verbose(`Invitation: ${formatObject(invitation)}`);
|
||||
|
||||
// "Creates" the invitiation in the engine. This method acts as both creation or import depending on the data that is being passed in
|
||||
const xoInvitation = await deps.app.engine.createInvitation(invitation);
|
||||
deps.io.verbose(`XOInvitation: ${formatObject(xoInvitation)}`);
|
||||
|
||||
// Create the invitation instance (NOTE: Not an engine compatible invitation. This is the wrapped format)
|
||||
const invitationInstance = await deps.app.createInvitation(xoInvitation);
|
||||
deps.io.verbose(
|
||||
`Invitation created: ${formatObject(invitationInstance.data)}`,
|
||||
);
|
||||
|
||||
// Return the invitation identifier
|
||||
return {
|
||||
invitationIdentifier: invitationInstance.data.invitationIdentifier,
|
||||
};
|
||||
}
|
||||
|
||||
case "list": {
|
||||
// List all the invitations
|
||||
const invitations = await Promise.all(
|
||||
// Iterate over the invitations and compile them into a list of data that we can use to display them with another loop later.
|
||||
deps.app.invitations.map(async (invitation) => {
|
||||
// Get the template for the invitation
|
||||
const template = await deps.app.engine.getTemplate(
|
||||
invitation.data.templateIdentifier,
|
||||
);
|
||||
|
||||
// Get the role identifier for the invitation
|
||||
return {
|
||||
invitationIdentifier: invitation.data.invitationIdentifier,
|
||||
templateIdentifier: invitation.data.templateIdentifier,
|
||||
@@ -755,15 +884,22 @@ export const handleInvitationCommand = async (
|
||||
}),
|
||||
);
|
||||
deps.io.verbose(`Invitations: ${formatObject(invitations)}`);
|
||||
|
||||
// Format the invitations into a list of strings that we can display to the user
|
||||
const formattedInvitations = invitations.map(
|
||||
(invitation) =>
|
||||
`${bold(invitation.templateName)} ${dim(invitation.status)} ${dim(invitation.invitationIdentifier)} ${dim(invitation.actionIdentifier)} (${dim(invitation.roleIdentifier)})`,
|
||||
);
|
||||
|
||||
// Display the invitations to the user
|
||||
deps.io.out(formattedInvitations.join("\n"));
|
||||
|
||||
// Return the number of invitations
|
||||
return { count: invitations.length };
|
||||
}
|
||||
|
||||
default:
|
||||
// If the sub-command is not found, print an error and throw an error
|
||||
deps.io.verbose(`Unknown invitation sub-command: ${subCommand}`);
|
||||
printInvitationHelp(deps.io);
|
||||
throw new CommandError(
|
||||
|
||||
Reference in New Issue
Block a user