Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions docs/ai.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Sends a request to supported LLMs using Box AI. This is intended for direct use,
USAGE
$ box ai:ask --prompt <value> --items <value>... [-t <value>] [--as-user <value>] [--no-color] [--json |
--csv] [-s | --save-to-file-path <value>] [--fields <value>] [--bulk-file-path <value>] [-h] [-v] [-y] [-q]
[--ai-agent <value>]
[--ai-agent <value>] [--raw-json | ]
FLAGS
-h, --help Show CLI help
Expand All @@ -36,6 +36,9 @@ FLAGS
--json Output formatted JSON
--no-color Turn off colors for logging
--prompt=<value> (required) The prompt for the AI request
--raw-json Output the raw API JSON response instead of the tsClient-normalized object fields.
Added as a non-breaking compatibility flag for users who need JSON field names to
match the API schema exactly. Implies --json.
--save-to-file-path=<value> Override default file path to save report
DESCRIPTION
Expand All @@ -55,7 +58,7 @@ Sends an AI request to supported Large Language Models (LLMs) and extracts metad
USAGE
$ box ai:extract --prompt <value> --items <value>... [-t <value>] [--as-user <value>] [--no-color] [--json |
--csv] [-s | --save-to-file-path <value>] [--fields <value>] [--bulk-file-path <value>] [-h] [-v] [-y] [-q]
[--ai-agent <value>]
[--raw-json | ] [--ai-agent <value>]
FLAGS
-h, --help Show CLI help
Expand All @@ -76,6 +79,9 @@ FLAGS
--json Output formatted JSON
--no-color Turn off colors for logging
--prompt=<value> (required) The prompt provided to a Large Language Model (LLM) in the request.
--raw-json Output the raw API JSON response instead of the tsClient-normalized object fields.
Added as a non-breaking compatibility flag for users who need JSON field names to
match the API schema exactly. Implies --json.
--save-to-file-path=<value> Override default file path to save report
DESCRIPTION
Expand Down
19 changes: 14 additions & 5 deletions docs/integration-mappings.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,8 @@ List Teams integration mappings
```
USAGE
$ box integration-mappings:teams [-t <value>] [--as-user <value>] [--no-color] [--json | --csv] [-s | --save-to-file-path
<value>] [--fields <value>] [--bulk-file-path <value>] [-h] [-v] [-y] [-q] [--max-items <value>] [--partner-item-id
<value>] [--partner-item-type <value>] [--box-item-id <value>] [--box-item-type <value>]
<value>] [--fields <value>] [--bulk-file-path <value>] [-h] [-v] [-y] [-q] [--max-items <value>] [--raw-json | ]
[--partner-item-id <value>] [--partner-item-type <value>] [--box-item-id <value>] [--box-item-type <value>]

FLAGS
-h, --help Show CLI help
Expand All @@ -258,6 +258,9 @@ FLAGS
--partner-item-id=<value> ID of the mapped item, for which the mapping should be returned
--partner-item-type=<value> Mapped item type, for which the mapping should be returned, value is one of: channel,
team
--raw-json Output the raw API JSON response instead of the tsClient-normalized object fields.
Added as a non-breaking compatibility flag for users who need JSON field names to
match the API schema exactly. Implies --json.
--save-to-file-path=<value> Override default file path to save report

DESCRIPTION
Expand Down Expand Up @@ -358,8 +361,8 @@ List Teams integration mappings
```
USAGE
$ box integration-mappings:teams:list [-t <value>] [--as-user <value>] [--no-color] [--json | --csv] [-s | --save-to-file-path
<value>] [--fields <value>] [--bulk-file-path <value>] [-h] [-v] [-y] [-q] [--max-items <value>] [--partner-item-id
<value>] [--partner-item-type <value>] [--box-item-id <value>] [--box-item-type <value>]
<value>] [--fields <value>] [--bulk-file-path <value>] [-h] [-v] [-y] [-q] [--max-items <value>] [--raw-json | ]
[--partner-item-id <value>] [--partner-item-type <value>] [--box-item-id <value>] [--box-item-type <value>]

FLAGS
-h, --help Show CLI help
Expand All @@ -383,6 +386,9 @@ FLAGS
--partner-item-id=<value> ID of the mapped item, for which the mapping should be returned
--partner-item-type=<value> Mapped item type, for which the mapping should be returned, value is one of: channel,
team
--raw-json Output the raw API JSON response instead of the tsClient-normalized object fields.
Added as a non-breaking compatibility flag for users who need JSON field names to
match the API schema exactly. Implies --json.
--save-to-file-path=<value> Override default file path to save report

DESCRIPTION
Expand All @@ -404,7 +410,7 @@ Update Teams integration mapping
```
USAGE
$ box integration-mappings:teams:update ID [-t <value>] [--as-user <value>] [--no-color] [--json | --csv] [-s | --save-to-file-path
<value>] [--fields <value>] [--bulk-file-path <value>] [-h] [-v] [-y] [-q] [--box-item-id <value>]
<value>] [--fields <value>] [--bulk-file-path <value>] [-h] [-v] [-y] [-q] [--raw-json | ] [--box-item-id <value>]

ARGUMENTS
ID ID of an integration mapping
Expand All @@ -423,6 +429,9 @@ FLAGS
--fields=<value> Comma separated list of fields to show
--json Output formatted JSON
--no-color Turn off colors for logging
--raw-json Output the raw API JSON response instead of the tsClient-normalized object fields.
Added as a non-breaking compatibility flag for users who need JSON field names to
match the API schema exactly. Implies --json.
--save-to-file-path=<value> Override default file path to save report

DESCRIPTION
Expand Down
58 changes: 57 additions & 1 deletion src/box-command.js
Original file line number Diff line number Diff line change
Expand Up @@ -1187,6 +1187,44 @@ class BoxCommand extends Command {
return client;
}

/**
* Returns true when raw API JSON output was requested.
*
* @returns {boolean} True if raw JSON output should be used
* @private
*/
_wantsRawJsonOutput() {
return Boolean(this.flags && this.flags['raw-json']);
}

/**
* Preserves default output behavior while adding raw JSON support.
*
* The generated TypeScript client can expose response objects with normalized
* field names that do not match the original API schema. That behavior was
* introduced as newer commands moved to `tsClient`. To fix the JSON output
* shape without a breaking change, commands that support `--raw-json` use this
* wrapper on the top-level response object before calling `output()`.
*
* @param {*} content The content to potentially replace with rawData
* @returns {*} The content to send to output formatting
*/
getOutputContentWithRawJsonSupport(content) {
if (typeof content === 'object' && content !== null) {
if (this._wantsRawJsonOutput()) {
return content.rawData ?? content;
}

if (Object.hasOwn(content, 'rawData')) {
const output = { ...content };
delete output.rawData;
return output;
}
}

return content;
}

/**
* Format data for output to stdout
* @param {*} content The content to output
Expand Down Expand Up @@ -1323,7 +1361,11 @@ class BoxCommand extends Command {
}

const page = await fetchPage(pageQueryParams);
const pageEntries = page.entries || [];
const rawPage =
typeof page?.rawData === 'object' && page.rawData !== null
? page.rawData
: page;
const pageEntries = rawPage.entries || page.entries || [];
entries.push(...pageEntries);
remaining -= pageEntries.length;
marker = page.nextMarker || page.next_marker;
Expand Down Expand Up @@ -1393,6 +1435,12 @@ class BoxCommand extends Command {
return 'json';
}

// Raw API payloads are only intended for JSON output, so `--raw-json`
// implicitly promotes the format to JSON without changing default behavior.
if (this._wantsRawJsonOutput()) {
return 'json';
}

if (this.flags.csv) {
return 'csv';
}
Expand Down Expand Up @@ -2214,6 +2262,14 @@ BoxCommand.flags = {
}),
};

BoxCommand.rawJsonFlags = Object.freeze({
'raw-json': Flags.boolean({
description:
'Output the raw API JSON response instead of the tsClient-normalized object fields. Added as a non-breaking compatibility flag for users who need JSON field names to match the API schema exactly. Implies --json.',
exclusive: ['csv'],
}),
});

BoxCommand.minFlags = _.pick(BoxCommand.flags, [
'no-color',
'help',
Expand Down
4 changes: 2 additions & 2 deletions src/commands/ai/ask.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ class AiAskCommand extends BoxCommand {
}

let answer = await this.tsClient.ai.createAiAsk(options);
delete answer.rawData;
await this.output(answer);
await this.output(this.getOutputContentWithRawJsonSupport(answer));
}
}

Expand Down Expand Up @@ -96,6 +95,7 @@ AiAskCommand.flags = {
}
},
}),
...BoxCommand.rawJsonFlags,
};

module.exports = AiAskCommand;
5 changes: 2 additions & 3 deletions src/commands/ai/extract.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ class AiExtractCommand extends BoxCommand {
}

let answer = await this.tsClient.ai.createAiExtract(options);

delete answer.rawData;
await this.output(answer);
await this.output(this.getOutputContentWithRawJsonSupport(answer));
}
}

Expand All @@ -37,6 +35,7 @@ AiExtractCommand._endpoint = 'post_ai_extract';
// Flags definition
AiExtractCommand.flags = {
...BoxCommand.flags,
...BoxCommand.rawJsonFlags,
prompt: Flags.string({
required: true,
description:
Expand Down
3 changes: 1 addition & 2 deletions src/commands/hubs/collaborations/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ class HubsCreateCollaborationCommand extends BoxCommand {
await this.tsClient.hubCollaborations.createHubCollaborationV2025R0(
requestBody
);
delete collaboration.rawData;
await this.output(collaboration);
await this.output(collaboration.rawData ?? collaboration);
}
}
HubsCreateCollaborationCommand.aliases = ['hubs:collaborations:add'];
Expand Down
3 changes: 1 addition & 2 deletions src/commands/hubs/collaborations/get.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ class HubsGetCollaborationCommand extends BoxCommand {
await this.tsClient.hubCollaborations.getHubCollaborationByIdV2025R0(
args.id
);
delete collaboration.rawData;
await this.output(collaboration);
await this.output(collaboration.rawData ?? collaboration);
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/commands/hubs/collaborations/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ class HubsUpdateCollaborationCommand extends BoxCommand {
role: flags.role,
}
);
delete collaboration.rawData;
await this.output(collaboration);
await this.output(collaboration.rawData ?? collaboration);
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/commands/hubs/copy.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ class HubsCopyCommand extends BoxCommand {
}

const hub = await this.tsClient.hubs.copyHubV2025R0(args.id, requestBody);
delete hub.rawData;
await this.output(hub);
await this.output(hub.rawData ?? hub);
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/commands/hubs/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ class HubsCreateCommand extends BoxCommand {
}

const hub = await this.tsClient.hubs.createHubV2025R0(requestBody);
delete hub.rawData;
await this.output(hub);
await this.output(hub.rawData ?? hub);
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/commands/hubs/get.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ class HubsGetCommand extends BoxCommand {
async run() {
const { args } = await this.parse(HubsGetCommand);
const hub = await this.tsClient.hubs.getHubByIdV2025R0(args.id);
delete hub.rawData;
await this.output(hub);
await this.output(hub.rawData ?? hub);
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/commands/hubs/items/manage.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ class HubsManageItemsCommand extends BoxCommand {
args.id,
{ operations }
);
delete response.rawData;
await this.output(response);
await this.output(response.rawData ?? response);
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/commands/hubs/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ class HubsUpdateCommand extends BoxCommand {
args.id,
requestBody
);
delete hub.rawData;
await this.output(hub);
await this.output(hub.rawData ?? hub);
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/commands/integration-mappings/teams/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ class IntegrationMappingsTeamsListCommand extends BoxCommand {
await this.tsClient.integrationMappings.getTeamsIntegrationMapping(
options
);
delete teamsIntegrationMappings.rawData;
await this.output(teamsIntegrationMappings);
await this.output(
this.getOutputContentWithRawJsonSupport(teamsIntegrationMappings)
);
}
}

Expand All @@ -47,6 +48,7 @@ IntegrationMappingsTeamsListCommand._endpoint =
IntegrationMappingsTeamsListCommand.flags = {
...BoxCommand.flags,
...PaginationUtilities.flags,
...BoxCommand.rawJsonFlags,
'partner-item-id': Flags.string({
hidden: false,
description:
Expand Down
6 changes: 4 additions & 2 deletions src/commands/integration-mappings/teams/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ class IntegrationMappingsTeamsUpdateCommand extends BoxCommand {
requestBody: body,
}
);
delete integrationMapping.rawData;
await this.output(integrationMapping);
await this.output(
this.getOutputContentWithRawJsonSupport(integrationMapping)
);
}
}

Expand All @@ -39,6 +40,7 @@ IntegrationMappingsTeamsUpdateCommand._endpoint =

IntegrationMappingsTeamsUpdateCommand.flags = {
...BoxCommand.flags,
...BoxCommand.rawJsonFlags,
'box-item-id': Flags.string({
description: 'ID of the mapped folder',
}),
Expand Down
41 changes: 41 additions & 0 deletions test/commands/ai.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,24 @@ describe('AI', function () {
const fixture = getFixture('ai/post_ai_ask_response');
const yamlFixture = getFixture('ai/post_ai_ask_response_yaml.txt');

test.nock(TEST_API_ROOT, (api) =>
api
.post('/2.0/ai/ask', expectedRequestBody)
.reply(200, expectedResponseBody)
)
.stdout()
.command([
'ai:ask',
'--items=content=one,two,three,id=12345,type=file',
'--prompt',
'What is the status of this document?',
'--raw-json',
'--token=test',
])
.it('should output the raw response when --raw-json is passed', (context) => {
assert.deepEqual(JSON.parse(context.stdout), expectedResponseBody);
});

test.nock(TEST_API_ROOT, (api) =>
api
.post('/2.0/ai/ask', expectedRequestBody)
Expand Down Expand Up @@ -301,6 +319,29 @@ describe('AI', function () {
const fixture = getFixture('ai/post_ai_extract_response');
const yamlFixture = getFixture('ai/post_ai_extract_response_yaml.txt');

test.nock(TEST_API_ROOT, (api) => {
api.post('/2.0/ai/extract', expectedRequestBody).reply(
200,
expectedResponseBody
);
})
.stdout()
.command([
'ai:extract',
'--items=content=one,two,three,id=12345,type=file',
'--prompt',
'firstName, lastName, location, yearOfBirth, company',
'--raw-json',
'--token=test',
])

.it(
'should output the raw response when --raw-json is passed',
(context) => {
assert.deepEqual(JSON.parse(context.stdout), expectedResponseBody);
}
);

test.nock(TEST_API_ROOT, (api) => {
api.post('/2.0/ai/extract', expectedRequestBody).reply(
200,
Expand Down
Loading
Loading