@jacebenson/jsn 0.1.0 → 0.1.1
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/README.md +3 -7
- package/package.json +1 -1
- package/src/commands/records.js +31 -15
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ jsn version --check
|
|
|
32
32
|
|
|
33
33
|
## What's New in v0.1.0
|
|
34
34
|
|
|
35
|
-
Full feature parity
|
|
35
|
+
Full feature parity — 128 tests, lint clean:
|
|
36
36
|
|
|
37
37
|
| Feature | Status |
|
|
38
38
|
|---------|--------|
|
|
@@ -44,7 +44,7 @@ Full feature parity with the original Go implementation — 128 tests, lint clea
|
|
|
44
44
|
| Group management (CRUD) | ✅ |
|
|
45
45
|
| Group memberships and roles | ✅ |
|
|
46
46
|
| Generic Table API (`jsn records`) | ✅ |
|
|
47
|
-
| OAuth PKCE with keychain (
|
|
47
|
+
| OAuth PKCE with keychain (shared auth store) | ✅ |
|
|
48
48
|
| Bot/CI/CD auth flags (`--code`, `--print-url`) | ✅ |
|
|
49
49
|
| Dev commands: flows, actions, includes, rules, ACLs, etc. | ✅ |
|
|
50
50
|
| Script execution (`jsn dev eval`) via OAuth session flow | ✅ |
|
|
@@ -211,7 +211,7 @@ jsn incidents -q | jq '.[].number'
|
|
|
211
211
|
|
|
212
212
|
## Authentication
|
|
213
213
|
|
|
214
|
-
OAuth 2.0 with PKCE. Credentials stored in `~/.config/servicenow/credentials
|
|
214
|
+
OAuth 2.0 with PKCE. Credentials stored in `~/.config/servicenow/credentials/`.
|
|
215
215
|
|
|
216
216
|
```bash
|
|
217
217
|
jsn auth login https://dev12345.service-now.com
|
|
@@ -335,10 +335,6 @@ jsn version --check
|
|
|
335
335
|
npm install -g @jacebenson/jsn
|
|
336
336
|
```
|
|
337
337
|
|
|
338
|
-
## Historical Note
|
|
339
|
-
|
|
340
|
-
JSN was originally implemented in Go (on the `main` branch) and migrated to Node.js for broader cross-platform support and simpler installation. As of v0.1.0, the Node.js version has full feature parity. The Go source remains available on the `main` branch for reference.
|
|
341
|
-
|
|
342
338
|
## License
|
|
343
339
|
|
|
344
340
|
MIT License — see LICENSE file for details
|
package/package.json
CHANGED
package/src/commands/records.js
CHANGED
|
@@ -30,6 +30,7 @@ export function recordsCmd(wrap) {
|
|
|
30
30
|
describe: 'List records from a table',
|
|
31
31
|
builder: (y) => y
|
|
32
32
|
.option('table', { type: 'string', demandOption: true, describe: 'Table name' })
|
|
33
|
+
.option('sys-id', { type: 'string', describe: 'Record sys_id (filters to a single record)' })
|
|
33
34
|
.option('query', { type: 'string', describe: 'Encoded query (e.g. "nameLIKEincident" or "active=true")' })
|
|
34
35
|
.option('columns', { alias: 'c', type: 'string', describe: 'Comma-separated columns (e.g. "number,short_description")' })
|
|
35
36
|
.option('limit', { type: 'number', default: 20, describe: 'Max records' })
|
|
@@ -37,28 +38,36 @@ export function recordsCmd(wrap) {
|
|
|
37
38
|
handler: wrap(async (argv, app) => {
|
|
38
39
|
const table = argv.table;
|
|
39
40
|
const columns = argv.columns ? argv.columns.split(',') : getDefaultColumns(table);
|
|
40
|
-
|
|
41
|
+
let query = argv.query || '';
|
|
41
42
|
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const cols = getDefaultColumns(table);
|
|
47
|
-
return cols.map(c => `${c}: ${getStringField(r, c) || '-'}`).join(' | ');
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
if (picked) {
|
|
51
|
-
picked._context = { instance_url: app.getEffectiveInstance(), table };
|
|
52
|
-
return app.ok(picked, { summary: `Record from ${table}` });
|
|
43
|
+
// If --sys-id is provided, append it to the query
|
|
44
|
+
if (argv['sys-id']) {
|
|
45
|
+
if (query) query += '^';
|
|
46
|
+
query += `sys_id=${argv['sys-id']}`;
|
|
53
47
|
}
|
|
54
48
|
|
|
55
|
-
//
|
|
49
|
+
// Interactive picker (only when no --sys-id filter, otherwise go straight to results)
|
|
50
|
+
if (!argv['sys-id']) {
|
|
51
|
+
const picked = await interactiveList({
|
|
52
|
+
app, table, singular: 'record', columns, limit: argv.limit, query, labelField: 'sys_id',
|
|
53
|
+
formatLabel: r => {
|
|
54
|
+
const cols = getDefaultColumns(table);
|
|
55
|
+
return cols.map(c => `${c}: ${getStringField(r, c) || '-'}`).join(' | ');
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
if (picked) {
|
|
59
|
+
picked._context = { instance_url: app.getEffectiveInstance(), table };
|
|
60
|
+
return app.ok(picked, { summary: `Record from ${table}` });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Text/table fallback (or sys-id direct lookup)
|
|
56
65
|
const params = new URLSearchParams();
|
|
57
|
-
params.set('sysparm_limit', String(argv.limit));
|
|
66
|
+
params.set('sysparm_limit', argv['sys-id'] ? '1' : String(argv.limit));
|
|
58
67
|
params.set('sysparm_offset', String(argv.offset));
|
|
59
68
|
params.set('sysparm_display_value', 'all');
|
|
60
69
|
params.set('sysparm_fields', ['sys_id', ...columns].join(','));
|
|
61
|
-
if (
|
|
70
|
+
if (query) params.set('sysparm_query', query);
|
|
62
71
|
const records = await app.sdk.list(table, params);
|
|
63
72
|
const displayRecords = records.map(r => formatRecordForDisplay(r, columns));
|
|
64
73
|
const breadcrumbs = [
|
|
@@ -66,6 +75,13 @@ export function recordsCmd(wrap) {
|
|
|
66
75
|
{ action: 'filter', cmd: `jsn records list --table ${table} --query "priority=1"`, description: 'Filter: priority 1 only' },
|
|
67
76
|
{ action: 'columns', cmd: `jsn dev columns --table ${table}`, description: 'View available columns' },
|
|
68
77
|
];
|
|
78
|
+
if (argv['sys-id']) {
|
|
79
|
+
breadcrumbs.unshift({
|
|
80
|
+
action: 'get',
|
|
81
|
+
cmd: `jsn records get --table ${table} --sys-id ${argv['sys-id']}`,
|
|
82
|
+
description: 'Get full record details',
|
|
83
|
+
});
|
|
84
|
+
}
|
|
69
85
|
if (records.length === argv.limit) {
|
|
70
86
|
breadcrumbs.push({
|
|
71
87
|
action: 'next',
|