@jacebenson/jsn 4.3.13-dev.74.1 → 4.3.13-dev.75.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jacebenson/jsn",
3
- "version": "4.3.13-dev.74.1",
3
+ "version": "4.3.13-dev.75.1",
4
4
  "description": "A command-line interface for ServiceNow that follows the Unix philosophy: simple, composable, and scriptable.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,7 +14,7 @@ compatibility: |
14
14
  Works with Claude Code, OpenCode, Cursor, and agentskills-compatible tools.
15
15
  metadata:
16
16
  author: jacebenson
17
- version: "4.3.10"
17
+ version: "4.3.11"
18
18
  repository: https://github.com/jacebenson/jsn
19
19
  ---
20
20
 
@@ -42,10 +42,9 @@ All `list` subcommands use a paginated interactive picker in TTY mode:
42
42
 
43
43
  1. **Output modes** — `--json` when parsing data; text when presenting to humans
44
44
  2. **Use sys_id for updates** — All update/delete operations require sys_id
45
- 3. **Check auth first** — Run `jsn auth status` before operations
46
- 4. **Verify the intended instance** — Use `--profile <name>` for explicit targeting; never assume the default is right. `jsn auth switch <name>` changes the default.
47
- 5. **Eval safety** — Prefer purpose-built or `records` commands. Never use `eval` to bypass a blocked business rule, ACL, or other ServiceNow protection. If eval is genuinely needed, explain why and obtain explicit user approval.
48
- 6. **CONFIRM before destructive operations** — Show what will be created/updated/deleted and ask for approval.
45
+ 3. **Verify the intended instance** — Use `--profile <name>` for explicit targeting; never assume the default is right. `jsn auth switch <name>` changes the default.
46
+ 4. **Eval safety** — Prefer purpose-built or `records` commands. Never use `eval` to bypass a blocked business rule, ACL, or other ServiceNow protection. If eval is genuinely needed, explain why and obtain explicit user approval.
47
+ 5. **CONFIRM before destructive operations** — Show what will be created/updated/deleted and ask for approval.
49
48
 
50
49
  ## Command Hierarchy
51
50
 
@@ -1,4 +1,4 @@
1
- import { errAPI } from './errors.js';
1
+ import { errAPI, errAuth } from './errors.js';
2
2
  import { canUsePicker, quoteShellArg } from './helpers.js';
3
3
  import { confirm } from './prompts.js';
4
4
 
@@ -34,6 +34,15 @@ export function createAuthRecovery({ app, session, argv = () => app._authArgv ||
34
34
  let recoveryAttempt;
35
35
  const provider = {
36
36
  error: failure(),
37
+ credentialError(cause) {
38
+ // Local validation can fail before any HTTP response. Keep its precise
39
+ // reason, but target recovery to this invocation rather than the default.
40
+ const error = errAuth(`${cause.message} (${label}).`);
41
+ error.profile = profileName || null;
42
+ error.recovery = `jsn auth login ${target}`;
43
+ error.hint = `Run: ${error.recovery}`;
44
+ return error;
45
+ },
37
46
  async recover({ status }) {
38
47
  if (status !== 401) return false;
39
48
  return recoveryAttempt ??= recoverOnce();
package/src/sdk.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // ServiceNow REST API client
2
2
 
3
3
  import { gunzipSync } from 'node:zlib';
4
- import { errAuth, errAPI, errNetwork } from './errors.js';
4
+ import { CodeAuth, errAuth, errAPI, errNetwork } from './errors.js';
5
5
  import { getStringField } from './helpers.js';
6
6
  import { getAction, getStepTypes, createAction, updateAction, testAction } from './processflow-actions.js';
7
7
  import { readSkippedBaseline, revertSkippedUpdate } from './skipped-update-provider.js';
@@ -59,7 +59,13 @@ export class SDKClient {
59
59
  if (!this.authProvider) {
60
60
  throw errAuth('No authentication configured');
61
61
  }
62
- const creds = await this.authProvider.getCredentials();
62
+ let creds;
63
+ try {
64
+ creds = await this.authProvider.getCredentials();
65
+ } catch (error) {
66
+ if (error.code === CodeAuth && this.recovery?.credentialError) throw this.recovery.credentialError(error);
67
+ throw error;
68
+ }
63
69
  if (!creds) {
64
70
  throw errAuth('No valid credentials');
65
71
  }