@terros-inc/cli 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.js +1 -1
- package/dist/api/query.js +2 -2
- package/dist/auth/auth0.js +15 -15
- package/dist/auth/tokens.js +3 -3
- package/dist/commands/auth.js +3 -3
- package/dist/crud/index.js +2 -2
- package/dist/crud/input.js +7 -2
- package/dist/crud/input.test.js +69 -0
- package/dist/crud/parameters.js +3 -7
- package/dist/index.js +2 -2
- package/dist/messages.js +1 -5
- package/package.json +7 -2
- package/terros.yml +20 -20
package/cli.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import './dist/index.js'
|
|
2
|
+
import './dist/index.js'
|
package/dist/api/query.js
CHANGED
package/dist/auth/auth0.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
+
import open from 'open';
|
|
2
|
+
import { DateTime } from 'luxon';
|
|
1
3
|
import { AUTH0_CLIENT_ID, AUTH0_DOMAIN } from "./constants.js";
|
|
2
|
-
import open from "open";
|
|
3
|
-
import { DateTime } from "luxon";
|
|
4
4
|
export async function signInToAuth0() {
|
|
5
5
|
const res = await fetch(`${AUTH0_DOMAIN}/oauth/device/code`, {
|
|
6
6
|
method: 'POST',
|
|
7
7
|
headers: {
|
|
8
|
-
|
|
8
|
+
'Content-Type': 'application/json',
|
|
9
9
|
},
|
|
10
10
|
body: JSON.stringify({
|
|
11
11
|
client_id: AUTH0_CLIENT_ID,
|
|
12
|
-
scope: 'offline_access'
|
|
13
|
-
})
|
|
12
|
+
scope: 'offline_access',
|
|
13
|
+
}),
|
|
14
14
|
});
|
|
15
15
|
if (!res.ok)
|
|
16
16
|
throw new Error('Failed to get OAuth device code');
|
|
17
|
-
const body = await res.json();
|
|
17
|
+
const body = (await res.json());
|
|
18
18
|
const deadline = DateTime.now().plus({ seconds: body.expires_in });
|
|
19
19
|
await open(body.verification_uri_complete);
|
|
20
20
|
console.log(`Confirm that the code in your browser matches: ${body.user_code}`);
|
|
@@ -33,36 +33,36 @@ async function pollForToken(deadline, interval, deviceCode) {
|
|
|
33
33
|
const res = await fetch(`${AUTH0_DOMAIN}/oauth/token`, {
|
|
34
34
|
method: 'POST',
|
|
35
35
|
headers: {
|
|
36
|
-
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
37
|
},
|
|
38
38
|
body: JSON.stringify({
|
|
39
39
|
client_id: AUTH0_CLIENT_ID,
|
|
40
40
|
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
41
|
-
device_code: deviceCode
|
|
42
|
-
})
|
|
41
|
+
device_code: deviceCode,
|
|
42
|
+
}),
|
|
43
43
|
});
|
|
44
44
|
if (!res.ok) {
|
|
45
|
-
const body = await res.json();
|
|
45
|
+
const body = (await res.json());
|
|
46
46
|
if (body.error === 'access_denied')
|
|
47
47
|
throw new Error('Authorization request denied');
|
|
48
48
|
return pollForToken(deadline, interval, deviceCode);
|
|
49
49
|
}
|
|
50
|
-
return await res.json();
|
|
50
|
+
return (await res.json());
|
|
51
51
|
}
|
|
52
52
|
export async function refreshTokens(refreshToken) {
|
|
53
53
|
const res = await fetch(`${AUTH0_DOMAIN}/oauth/token`, {
|
|
54
54
|
method: 'POST',
|
|
55
55
|
headers: {
|
|
56
|
-
'Content-Type': 'application/json'
|
|
56
|
+
'Content-Type': 'application/json',
|
|
57
57
|
},
|
|
58
58
|
body: JSON.stringify({
|
|
59
59
|
client_id: AUTH0_CLIENT_ID,
|
|
60
60
|
grant_type: 'refresh_token',
|
|
61
|
-
refresh_token: refreshToken
|
|
62
|
-
})
|
|
61
|
+
refresh_token: refreshToken,
|
|
62
|
+
}),
|
|
63
63
|
});
|
|
64
64
|
if (res.ok) {
|
|
65
|
-
return await res.json();
|
|
65
|
+
return (await res.json());
|
|
66
66
|
}
|
|
67
67
|
throw new Error('Unable to refresh token, it may be expired. Run `terros auth login` to sign in again');
|
|
68
68
|
}
|
package/dist/auth/tokens.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { DateTime } from 'luxon';
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
1
|
import { join } from 'node:path';
|
|
4
|
-
import {
|
|
2
|
+
import { homedir } from 'node:os';
|
|
5
3
|
import { mkdir, writeFile, readFile } from 'node:fs/promises';
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
|
+
import { DateTime } from 'luxon';
|
|
6
6
|
import { refreshTokens } from "./auth0.js";
|
|
7
7
|
export async function getTokens() {
|
|
8
8
|
const tokens = await readTokens();
|
package/dist/commands/auth.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { signInToAuth0 } from "../auth/auth0.js";
|
|
2
1
|
import { getTokens, saveTokens } from "../auth/tokens.js";
|
|
2
|
+
import { signInToAuth0 } from "../auth/auth0.js";
|
|
3
3
|
export const authCommands = {
|
|
4
4
|
login: {
|
|
5
5
|
description: 'Sign in to Terros',
|
|
@@ -18,6 +18,6 @@ export const authCommands = {
|
|
|
18
18
|
return;
|
|
19
19
|
}
|
|
20
20
|
console.log(tokens.access_token);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
23
|
};
|
package/dist/crud/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { dirname, resolve } from 'node:path';
|
|
3
1
|
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
4
|
import { parse } from 'yaml';
|
|
5
5
|
import { getPathParts } from "./util.js";
|
|
6
6
|
import { getEndpointParameters } from "./parameters.js";
|
package/dist/crud/input.js
CHANGED
|
@@ -6,7 +6,7 @@ export function buildEndpointInput(endpoint, params) {
|
|
|
6
6
|
if (unknownParameterNames.length > 0) {
|
|
7
7
|
throw new Error(`Unknown parameter(s): ${unknownParameterNames.map((name) => `--${name}`).join(', ')}`);
|
|
8
8
|
}
|
|
9
|
-
const missingParameters = endpoint.parameters.filter((parameter) =>
|
|
9
|
+
const missingParameters = endpoint.parameters.filter((parameter) => parameter.required && !Object.hasOwn(parsedParams, parameter.name));
|
|
10
10
|
if (missingParameters.length > 0) {
|
|
11
11
|
throw new Error(`Missing required parameter(s): ${missingParameters.map((parameter) => `--${parameter.name}`).join(', ')}`);
|
|
12
12
|
}
|
|
@@ -47,7 +47,12 @@ function getHiddenWrapperPrefix(endpoint) {
|
|
|
47
47
|
if (propertyNames.length !== 1)
|
|
48
48
|
return [];
|
|
49
49
|
const wrapperName = propertyNames[0];
|
|
50
|
-
|
|
50
|
+
if (!wrapperName)
|
|
51
|
+
return [];
|
|
52
|
+
const wrapperSchema = schema.properties[wrapperName];
|
|
53
|
+
if (!wrapperSchema || !('type' in wrapperSchema) || wrapperSchema.type !== 'object')
|
|
54
|
+
return [];
|
|
55
|
+
return [wrapperName];
|
|
51
56
|
}
|
|
52
57
|
function setNestedValue(input, path, value) {
|
|
53
58
|
if (path.length === 0) {
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { expect } from 'vitest';
|
|
2
|
+
import { buildEndpointInput } from "./input.js";
|
|
3
|
+
describe('buildEndpointInput', () => {
|
|
4
|
+
it('should not add a hidden wrapper prefix for a single non-object property', () => {
|
|
5
|
+
const endpoint = {
|
|
6
|
+
path: '/user/profile',
|
|
7
|
+
parameters: [
|
|
8
|
+
{
|
|
9
|
+
name: 'userId',
|
|
10
|
+
type: 'string',
|
|
11
|
+
required: false,
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
properties: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
userId: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
const params = {
|
|
24
|
+
_: ['user', 'profile'],
|
|
25
|
+
userId: 'U:dj',
|
|
26
|
+
};
|
|
27
|
+
const expected = {
|
|
28
|
+
userId: 'U:dj',
|
|
29
|
+
};
|
|
30
|
+
const result = buildEndpointInput(endpoint, params);
|
|
31
|
+
expect(result).toEqual(expected);
|
|
32
|
+
});
|
|
33
|
+
it('should add a hidden wrapper prefix for a single object property', () => {
|
|
34
|
+
const endpoint = {
|
|
35
|
+
path: '/user/profile',
|
|
36
|
+
parameters: [
|
|
37
|
+
{
|
|
38
|
+
name: 'userId',
|
|
39
|
+
type: 'string',
|
|
40
|
+
required: false,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
properties: {
|
|
44
|
+
type: 'object',
|
|
45
|
+
properties: {
|
|
46
|
+
profile: {
|
|
47
|
+
type: 'object',
|
|
48
|
+
properties: {
|
|
49
|
+
userId: {
|
|
50
|
+
type: 'string',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
const params = {
|
|
58
|
+
_: ['user', 'profile'],
|
|
59
|
+
userId: 'U:dj',
|
|
60
|
+
};
|
|
61
|
+
const expected = {
|
|
62
|
+
profile: {
|
|
63
|
+
userId: 'U:dj',
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
const result = buildEndpointInput(endpoint, params);
|
|
67
|
+
expect(result).toEqual(expected);
|
|
68
|
+
});
|
|
69
|
+
});
|
package/dist/crud/parameters.js
CHANGED
|
@@ -37,9 +37,7 @@ function resolveSchema(schema, components, seen = new Set()) {
|
|
|
37
37
|
}
|
|
38
38
|
function flattenSchema(schema, context) {
|
|
39
39
|
const resolved = resolveSchema(schema, context.components);
|
|
40
|
-
if ('type' in resolved
|
|
41
|
-
&& resolved.type === 'object'
|
|
42
|
-
&& resolved.properties) {
|
|
40
|
+
if ('type' in resolved && resolved.type === 'object' && resolved.properties) {
|
|
43
41
|
return Object.entries(resolved.properties).flatMap(([name, childSchema]) => {
|
|
44
42
|
const required = resolved.required?.includes(name) ?? false;
|
|
45
43
|
return flattenSchema(childSchema, {
|
|
@@ -54,7 +52,7 @@ function flattenSchema(schema, context) {
|
|
|
54
52
|
name: context.path.join('.'),
|
|
55
53
|
type: getSchemaType(resolved, context.components),
|
|
56
54
|
required: context.required,
|
|
57
|
-
...(schema.description ?? resolved.description
|
|
55
|
+
...((schema.description ?? resolved.description)
|
|
58
56
|
? { description: schema.description ?? resolved.description }
|
|
59
57
|
: {}),
|
|
60
58
|
},
|
|
@@ -69,9 +67,7 @@ function hideSingleObjectWrapper(parameters) {
|
|
|
69
67
|
return parameters;
|
|
70
68
|
return parameters.map((parameter) => ({
|
|
71
69
|
...parameter,
|
|
72
|
-
name: parameter.name.startsWith(`${wrapperName}.`)
|
|
73
|
-
? parameter.name.slice(wrapperName.length + 1)
|
|
74
|
-
: parameter.name,
|
|
70
|
+
name: parameter.name.startsWith(`${wrapperName}.`) ? parameter.name.slice(wrapperName.length + 1) : parameter.name,
|
|
75
71
|
}));
|
|
76
72
|
}
|
|
77
73
|
export function getEndpointParameters(schema, components) {
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import minimist from 'minimist';
|
|
2
2
|
import { formatCommandsHelp, formatSubcommandParametersHelp, formatSubcommandsHelp, HELP_PARENT_MESSAGE, } from "./messages.js";
|
|
3
|
-
import { loadEndpoints } from "./crud/index.js";
|
|
4
3
|
import { buildEndpointInput } from "./crud/input.js";
|
|
4
|
+
import { loadEndpoints } from "./crud/index.js";
|
|
5
|
+
import { getCommandGroup, getCommandNames, getSubcommand, getSubcommandNames } from "./commands/index.js";
|
|
5
6
|
import { queryTerrosAPI } from "./api/query.js";
|
|
6
|
-
import { getCommandGroup, getCommandNames, getSubcommand, getSubcommandNames, } from "./commands/index.js";
|
|
7
7
|
async function main() {
|
|
8
8
|
const params = minimist(process.argv.slice(2));
|
|
9
9
|
const commands = params._;
|
package/dist/messages.js
CHANGED
|
@@ -29,11 +29,7 @@ export function formatSubcommandsHelp(command, subcommands) {
|
|
|
29
29
|
return lines.join('\n');
|
|
30
30
|
}
|
|
31
31
|
export function formatSubcommandParametersHelp(command, subcommand, parameters) {
|
|
32
|
-
const lines = [
|
|
33
|
-
`usage: terros ${command} ${subcommand} [parameters]`,
|
|
34
|
-
'',
|
|
35
|
-
'Parameters:',
|
|
36
|
-
];
|
|
32
|
+
const lines = [`usage: terros ${command} ${subcommand} [parameters]`, '', 'Parameters:'];
|
|
37
33
|
if (parameters.length === 0) {
|
|
38
34
|
lines.push(' none');
|
|
39
35
|
return lines.join('\n');
|
package/package.json
CHANGED
|
@@ -14,10 +14,13 @@
|
|
|
14
14
|
},
|
|
15
15
|
"description": "Command-line interface for Terros Sales platform",
|
|
16
16
|
"devDependencies": {
|
|
17
|
+
"@types/luxon": "^3.7.1",
|
|
17
18
|
"@types/minimist": "^1.2.5",
|
|
18
19
|
"@types/node": "^24.13.1",
|
|
20
|
+
"oxfmt": "^0.54.0",
|
|
21
|
+
"oxlint": "^1.69.0",
|
|
19
22
|
"typescript": "^6.0.3",
|
|
20
|
-
"
|
|
23
|
+
"vitest": "^4.1.8"
|
|
21
24
|
},
|
|
22
25
|
"engines": {
|
|
23
26
|
"node": ">=24"
|
|
@@ -44,10 +47,12 @@
|
|
|
44
47
|
"url": "git+https://github.com/terros-inc/cli.git"
|
|
45
48
|
},
|
|
46
49
|
"type": "module",
|
|
47
|
-
"version": "1.0.
|
|
50
|
+
"version": "1.0.6",
|
|
48
51
|
"scripts": {
|
|
49
52
|
"fetch-openapi": "wget https://docs.terros.com/openapi/terros.yml",
|
|
50
53
|
"build": "tsc",
|
|
54
|
+
"lint": "oxlint",
|
|
55
|
+
"test": "vitest run",
|
|
51
56
|
"start": "node src/index.ts"
|
|
52
57
|
}
|
|
53
58
|
}
|
package/terros.yml
CHANGED
|
@@ -2922,9 +2922,9 @@ paths:
|
|
|
2922
2922
|
evalDate: 9007199254740991
|
|
2923
2923
|
teamId: Team.123
|
|
2924
2924
|
categories: []
|
|
2925
|
-
createdAt:
|
|
2925
|
+
createdAt: 1781726665720
|
|
2926
2926
|
createdBy: U:123
|
|
2927
|
-
updatedAt:
|
|
2927
|
+
updatedAt: 1781726665720
|
|
2928
2928
|
updatedBy: U:123
|
|
2929
2929
|
user:
|
|
2930
2930
|
userId: U:123
|
|
@@ -2990,9 +2990,9 @@ paths:
|
|
|
2990
2990
|
evalDate: 9007199254740991
|
|
2991
2991
|
teamId: Team.123
|
|
2992
2992
|
categories: []
|
|
2993
|
-
createdAt:
|
|
2993
|
+
createdAt: 1781726665720
|
|
2994
2994
|
createdBy: U:123
|
|
2995
|
-
updatedAt:
|
|
2995
|
+
updatedAt: 1781726665720
|
|
2996
2996
|
updatedBy: U:123
|
|
2997
2997
|
user:
|
|
2998
2998
|
userId: U:123
|
|
@@ -3199,9 +3199,9 @@ paths:
|
|
|
3199
3199
|
evalDate: 9007199254740991
|
|
3200
3200
|
teamId: Team.123
|
|
3201
3201
|
categories: []
|
|
3202
|
-
createdAt:
|
|
3202
|
+
createdAt: 1781726665720
|
|
3203
3203
|
createdBy: U:123
|
|
3204
|
-
updatedAt:
|
|
3204
|
+
updatedAt: 1781726665720
|
|
3205
3205
|
updatedBy: U:123
|
|
3206
3206
|
user:
|
|
3207
3207
|
userId: U:123
|
|
@@ -4699,7 +4699,7 @@ paths:
|
|
|
4699
4699
|
task:
|
|
4700
4700
|
taskId: Task.123
|
|
4701
4701
|
status: Completed
|
|
4702
|
-
completedAt:
|
|
4702
|
+
completedAt: 1781726665719
|
|
4703
4703
|
schema:
|
|
4704
4704
|
type: object
|
|
4705
4705
|
properties:
|
|
@@ -6842,8 +6842,8 @@ webhooks:
|
|
|
6842
6842
|
email: jdoe@example.com
|
|
6843
6843
|
evalState: Pending
|
|
6844
6844
|
possible: 10
|
|
6845
|
-
createdAt: "
|
|
6846
|
-
updatedAt: "
|
|
6845
|
+
createdAt: "1781726665720"
|
|
6846
|
+
updatedAt: "1781726665720"
|
|
6847
6847
|
Evaluation Updated:
|
|
6848
6848
|
value:
|
|
6849
6849
|
entity: Evaluation
|
|
@@ -6858,8 +6858,8 @@ webhooks:
|
|
|
6858
6858
|
email: jdoe@example.com
|
|
6859
6859
|
evalState: Pending
|
|
6860
6860
|
possible: 10
|
|
6861
|
-
createdAt: "
|
|
6862
|
-
updatedAt: "
|
|
6861
|
+
createdAt: "1781726665720"
|
|
6862
|
+
updatedAt: "1781726665720"
|
|
6863
6863
|
Evaluation Removed:
|
|
6864
6864
|
value:
|
|
6865
6865
|
entity: Evaluation
|
|
@@ -6974,8 +6974,8 @@ webhooks:
|
|
|
6974
6974
|
longitude: -104.9942
|
|
6975
6975
|
parentId: Team.AFCWest
|
|
6976
6976
|
description: Professional American football team based in Denver, Colorado.
|
|
6977
|
-
createdAt: 2026-06-
|
|
6978
|
-
updatedAt: 2026-06-
|
|
6977
|
+
createdAt: 2026-06-17T20:04:25.717Z
|
|
6978
|
+
updatedAt: 2026-06-17T20:04:25.717Z
|
|
6979
6979
|
members: []
|
|
6980
6980
|
Team Updated:
|
|
6981
6981
|
value:
|
|
@@ -6991,8 +6991,8 @@ webhooks:
|
|
|
6991
6991
|
longitude: -104.9942
|
|
6992
6992
|
parentId: Team.AFCWest
|
|
6993
6993
|
description: Professional American football team based in Denver, Colorado.
|
|
6994
|
-
createdAt: 2026-06-
|
|
6995
|
-
updatedAt: 2026-06-
|
|
6994
|
+
createdAt: 2026-06-17T20:04:25.717Z
|
|
6995
|
+
updatedAt: 2026-06-17T20:04:25.717Z
|
|
6996
6996
|
members:
|
|
6997
6997
|
- userId: U:user123
|
|
6998
6998
|
lastName: Smith
|
|
@@ -7102,8 +7102,8 @@ webhooks:
|
|
|
7102
7102
|
email: john.smith@company.com
|
|
7103
7103
|
firstName: John
|
|
7104
7104
|
lastName: Smith
|
|
7105
|
-
createdAt: "
|
|
7106
|
-
updatedAt: "
|
|
7105
|
+
createdAt: "1781726665716"
|
|
7106
|
+
updatedAt: "1781726665716"
|
|
7107
7107
|
User Updated:
|
|
7108
7108
|
value:
|
|
7109
7109
|
entity: User
|
|
@@ -7113,8 +7113,8 @@ webhooks:
|
|
|
7113
7113
|
email: john.smith@company.com
|
|
7114
7114
|
firstName: John
|
|
7115
7115
|
lastName: Smith
|
|
7116
|
-
createdAt: "
|
|
7117
|
-
updatedAt: "
|
|
7116
|
+
createdAt: "1781726665716"
|
|
7117
|
+
updatedAt: "1781726665716"
|
|
7118
7118
|
User Removed:
|
|
7119
7119
|
value:
|
|
7120
7120
|
entity: User
|
|
@@ -7187,7 +7187,7 @@ components:
|
|
|
7187
7187
|
maximum: 8640000000000000
|
|
7188
7188
|
title: Timestamp
|
|
7189
7189
|
description: A timestamp in UTC milliseconds
|
|
7190
|
-
example:
|
|
7190
|
+
example: 1781726665493
|
|
7191
7191
|
latlng:
|
|
7192
7192
|
type: object
|
|
7193
7193
|
properties:
|