@jacebenson/jsn 4.0.2 → 4.0.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.
- package/README.md +29 -7
- package/package.json +3 -4
- package/src/app.js +25 -3
- package/src/cli.js +3 -1
- package/src/commands/auth.js +222 -46
- package/src/commands/dev/domains.js +292 -0
- package/src/commands/dev/scopes.js +88 -36
- package/src/commands/dev/updatesets.js +297 -106
- package/src/commands/dev.js +16 -1
- package/src/commands/records.js +4 -3
- package/src/commands/setup.js +53 -17
- package/src/context.js +52 -5
- package/src/help.js +18 -3
- package/src/mutations.js +10 -1
- package/src/sdk.js +4 -0
- package/suppress-warnings.cjs +0 -13
package/src/context.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// ServiceNow runtime context: current user, scope, update set
|
|
2
2
|
|
|
3
|
+
import { getStringField } from './helpers.js';
|
|
4
|
+
|
|
3
5
|
export async function getCurrentUser(sdk) {
|
|
4
6
|
const params = new URLSearchParams();
|
|
5
7
|
params.set('sysparm_query', 'user_name=javascript:gs.getUserName()');
|
|
@@ -22,24 +24,24 @@ export async function getCurrentApplication(sdk, userSysID) {
|
|
|
22
24
|
params.set('sysparm_limit', '1');
|
|
23
25
|
params.set('sysparm_fields', 'value');
|
|
24
26
|
const records = await sdk.list('sys_user_preference', params);
|
|
25
|
-
if (records.length === 0) return { scope: 'global' };
|
|
27
|
+
if (records.length === 0) return { scope: 'global', appSysId: '' };
|
|
26
28
|
const val = records[0].value?.value || records[0].value;
|
|
27
|
-
if (!val) return { scope: 'global' };
|
|
29
|
+
if (!val) return { scope: 'global', appSysId: '' };
|
|
28
30
|
|
|
29
31
|
// Try to resolve sys_id to scope name
|
|
30
32
|
try {
|
|
31
33
|
const app = await sdk.get('sys_scope', val);
|
|
32
|
-
if (app) return { scope: app.scope || 'global' };
|
|
34
|
+
if (app) return { scope: app.scope || 'global', appSysId: val };
|
|
33
35
|
} catch {
|
|
34
36
|
// fallback
|
|
35
37
|
}
|
|
36
38
|
try {
|
|
37
39
|
const app2 = await sdk.get('sys_app', val);
|
|
38
|
-
if (app2) return { scope: app2.scope || 'global' };
|
|
40
|
+
if (app2) return { scope: app2.scope || 'global', appSysId: val };
|
|
39
41
|
} catch {
|
|
40
42
|
// fallback
|
|
41
43
|
}
|
|
42
|
-
return { scope: val };
|
|
44
|
+
return { scope: val, appSysId: val };
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
export async function getCurrentUpdateSet(sdk, userSysID) {
|
|
@@ -60,3 +62,48 @@ export async function getCurrentUpdateSet(sdk, userSysID) {
|
|
|
60
62
|
}
|
|
61
63
|
return { name: val, sys_id: val };
|
|
62
64
|
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Find-or-create a sys_user_preference and set its value. Shared by the
|
|
68
|
+
* scope/update-set "set" commands and create auto-set (was copy-pasted 3x).
|
|
69
|
+
*/
|
|
70
|
+
async function setUserPreference(sdk, userSysID, name, value) {
|
|
71
|
+
const params = new URLSearchParams();
|
|
72
|
+
params.set('sysparm_query', `user=${userSysID}^name=${name}`);
|
|
73
|
+
params.set('sysparm_limit', '1');
|
|
74
|
+
params.set('sysparm_fields', 'sys_id');
|
|
75
|
+
const prefs = await sdk.list('sys_user_preference', params);
|
|
76
|
+
if (prefs.length > 0) {
|
|
77
|
+
await sdk.update('sys_user_preference', getStringField(prefs[0], 'sys_id'), { value });
|
|
78
|
+
} else {
|
|
79
|
+
await sdk.create('sys_user_preference', {
|
|
80
|
+
user: userSysID,
|
|
81
|
+
name,
|
|
82
|
+
value,
|
|
83
|
+
type: 'string',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Resolve the current user's sys_id (throws if it can't be determined). */
|
|
89
|
+
export async function requireCurrentUserSysId(sdk) {
|
|
90
|
+
const user = await sdk.list('sys_user', new URLSearchParams({
|
|
91
|
+
sysparm_query: 'user_name=javascript:gs.getUserName()',
|
|
92
|
+
sysparm_limit: '1',
|
|
93
|
+
sysparm_fields: 'sys_id',
|
|
94
|
+
}));
|
|
95
|
+
if (user.length === 0) {
|
|
96
|
+
throw new Error('Could not determine current user');
|
|
97
|
+
}
|
|
98
|
+
return getStringField(user[0], 'sys_id');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Set the current application scope via the apps.current_app preference. */
|
|
102
|
+
export async function setCurrentApplication(sdk, userSysID, scopeSysID) {
|
|
103
|
+
await setUserPreference(sdk, userSysID, 'apps.current_app', scopeSysID);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Set the current update set via the sys_update_set preference. */
|
|
107
|
+
export async function setCurrentUpdateSet(sdk, userSysID, updateSetSysID) {
|
|
108
|
+
await setUserPreference(sdk, userSysID, 'sys_update_set', updateSetSysID);
|
|
109
|
+
}
|
package/src/help.js
CHANGED
|
@@ -107,9 +107,11 @@ const DATA_COMMANDS = [
|
|
|
107
107
|
];
|
|
108
108
|
|
|
109
109
|
const CONFIG_COMMANDS = [
|
|
110
|
-
{ name: '
|
|
110
|
+
{ name: 'setup', desc: 'Set up and manage instances (interactive: add, switch, remove, modify)' },
|
|
111
|
+
{ name: 'auth', desc: 'Authentication (login, refresh, status)' },
|
|
111
112
|
{ name: 'updatesets', desc: 'Update sets (set, create, export)' },
|
|
112
113
|
{ name: 'scopes', desc: 'Application scopes' },
|
|
114
|
+
{ name: 'domains', desc: 'Domains (domain separation)' },
|
|
113
115
|
];
|
|
114
116
|
|
|
115
117
|
const DEVELOPER_COMMANDS = [
|
|
@@ -152,8 +154,21 @@ LEARN MORE
|
|
|
152
154
|
Use "jsn <command> --help" for more information about a command.`;
|
|
153
155
|
}
|
|
154
156
|
|
|
155
|
-
export function renderHelp() {
|
|
156
|
-
|
|
157
|
+
export function renderHelp(config) {
|
|
158
|
+
// Domain separation is an optional plugin — only advertise `domains`
|
|
159
|
+
// when the active profile's capability probe found it installed.
|
|
160
|
+
const activeName = config?.activeProfile || config?.defaultProfile;
|
|
161
|
+
const hasDS = !!(activeName && config?.profiles?.[activeName]?.domain_separation);
|
|
162
|
+
const configCmds = hasDS
|
|
163
|
+
? CONFIG_COMMANDS
|
|
164
|
+
: CONFIG_COMMANDS.filter((c) => !c.name || c.name !== 'domains');
|
|
165
|
+
|
|
166
|
+
const COMMAND_GROUPS_LOCAL = {
|
|
167
|
+
...COMMAND_GROUPS,
|
|
168
|
+
'CONFIGURATION': configCmds,
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const sections = Object.entries(COMMAND_GROUPS_LOCAL).map(([name, cmds]) => renderGroup(name, cmds));
|
|
157
172
|
|
|
158
173
|
return [
|
|
159
174
|
'Usage: jsn <command> [options]',
|
package/src/mutations.js
CHANGED
|
@@ -75,11 +75,20 @@ export const MUTATION_COMMANDS = [
|
|
|
75
75
|
['scopes', 'set'],
|
|
76
76
|
['dev', 'scopes', 'create'],
|
|
77
77
|
['dev', 'scopes', 'set'],
|
|
78
|
-
//
|
|
78
|
+
// Domains: set writes the profile config (root + dev forms)
|
|
79
|
+
['domains', 'set'],
|
|
80
|
+
['dev', 'domains', 'set'],
|
|
81
|
+
// Update sets: create, set, complete, ignore, parent (root + dev forms)
|
|
79
82
|
['updatesets', 'create'],
|
|
80
83
|
['updatesets', 'set'],
|
|
84
|
+
['updatesets', 'complete'],
|
|
85
|
+
['updatesets', 'ignore'],
|
|
86
|
+
['updatesets', 'parent'],
|
|
81
87
|
['dev', 'updatesets', 'create'],
|
|
82
88
|
['dev', 'updatesets', 'set'],
|
|
89
|
+
['dev', 'updatesets', 'complete'],
|
|
90
|
+
['dev', 'updatesets', 'ignore'],
|
|
91
|
+
['dev', 'updatesets', 'parent'],
|
|
83
92
|
];
|
|
84
93
|
|
|
85
94
|
/**
|
package/src/sdk.js
CHANGED
|
@@ -11,6 +11,7 @@ export class SDKClient {
|
|
|
11
11
|
this.baseURL = baseURL.replace(/\/$/, '');
|
|
12
12
|
this.authProvider = authProvider;
|
|
13
13
|
this.timeout = opts.timeout || DEFAULT_TIMEOUT;
|
|
14
|
+
this.domain = opts.domain || '';
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
async _setAuth(req) {
|
|
@@ -53,6 +54,9 @@ export class SDKClient {
|
|
|
53
54
|
if (opts.body && typeof opts.body === 'string') {
|
|
54
55
|
req.headers.set('Content-Type', 'application/json');
|
|
55
56
|
}
|
|
57
|
+
if (this.domain) {
|
|
58
|
+
req.headers.set('X-Now-Domain', this.domain);
|
|
59
|
+
}
|
|
56
60
|
await this._setAuth(req);
|
|
57
61
|
|
|
58
62
|
const resp = await fetch(req);
|
package/suppress-warnings.cjs
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// Suppresses the node:sqlite ExperimentalWarning on Node 22.x.
|
|
2
|
-
// Loaded via NODE_OPTIONS=--require before the main ESM entry point.
|
|
3
|
-
|
|
4
|
-
const original = process.emitWarning;
|
|
5
|
-
process.emitWarning = function emitWarning(warning, ...args) {
|
|
6
|
-
const message = typeof warning === 'string'
|
|
7
|
-
? warning
|
|
8
|
-
: (warning?.message || '');
|
|
9
|
-
if (message.includes('SQLite')) {
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
return original.apply(this, [warning, ...args]);
|
|
13
|
-
};
|