@backstage/cli-module-auth 0.0.0-nightly-20260317031259 → 0.1.0

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.
Files changed (32) hide show
  1. package/CHANGELOG.md +3 -3
  2. package/dist/cli-internal/src/InternalCliModule.cjs.js +9 -0
  3. package/dist/cli-internal/src/InternalCliModule.cjs.js.map +1 -0
  4. package/dist/cli-internal/src/InternalCommandNode.cjs.js +13 -0
  5. package/dist/cli-internal/src/InternalCommandNode.cjs.js.map +1 -0
  6. package/dist/cli-internal/src/authIdentifiers.cjs.js +8 -0
  7. package/dist/cli-internal/src/authIdentifiers.cjs.js.map +1 -0
  8. package/dist/cli-internal/src/knownPluginPackages.cjs.js +40 -0
  9. package/dist/cli-internal/src/knownPluginPackages.cjs.js.map +1 -0
  10. package/dist/{lib → cli-internal/src}/secretStore.cjs.js +22 -7
  11. package/dist/cli-internal/src/secretStore.cjs.js.map +1 -0
  12. package/dist/{package.json.cjs.js → cli-module-auth/package.json.cjs.js} +8 -9
  13. package/dist/{package.json.cjs.js.map → cli-module-auth/package.json.cjs.js.map} +1 -1
  14. package/dist/commands/login.cjs.js +6 -2
  15. package/dist/commands/login.cjs.js.map +1 -1
  16. package/dist/commands/logout.cjs.js +6 -2
  17. package/dist/commands/logout.cjs.js.map +1 -1
  18. package/dist/commands/printToken.cjs.js +3 -13
  19. package/dist/commands/printToken.cjs.js.map +1 -1
  20. package/dist/commands/show.cjs.js +4 -15
  21. package/dist/commands/show.cjs.js.map +1 -1
  22. package/dist/index.cjs.js +1 -1
  23. package/dist/lib/http.cjs.js +1 -6
  24. package/dist/lib/http.cjs.js.map +1 -1
  25. package/dist/lib/storage.cjs.js +14 -24
  26. package/dist/lib/storage.cjs.js.map +1 -1
  27. package/dist/opaque-internal/src/OpaqueType.cjs.js +105 -0
  28. package/dist/opaque-internal/src/OpaqueType.cjs.js.map +1 -0
  29. package/package.json +6 -7
  30. package/dist/lib/auth.cjs.js +0 -60
  31. package/dist/lib/auth.cjs.js.map +0 -1
  32. package/dist/lib/secretStore.cjs.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @backstage/cli-module-auth
2
2
 
3
- ## 0.0.0-nightly-20260317031259
3
+ ## 0.1.0
4
4
 
5
5
  ### Minor Changes
6
6
 
@@ -8,6 +8,6 @@
8
8
 
9
9
  ### Patch Changes
10
10
 
11
+ - a49a40d: Updated dependency `zod` to `^3.25.76 || ^4.0.0` & migrated to `/v3` or `/v4` imports.
11
12
  - Updated dependencies
12
- - @backstage/cli-node@0.0.0-nightly-20260317031259
13
- - @backstage/errors@1.2.7
13
+ - @backstage/cli-node@0.3.0
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ var OpaqueType = require('../../opaque-internal/src/OpaqueType.cjs.js');
4
+
5
+ OpaqueType.OpaqueType.create({
6
+ type: "@backstage/CliModule",
7
+ versions: ["v1"]
8
+ });
9
+ //# sourceMappingURL=InternalCliModule.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InternalCliModule.cjs.js","sources":["../../../../cli-internal/src/InternalCliModule.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CliCommand, CliModule } from '@backstage/cli-node';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueCliModule = OpaqueType.create<{\n public: CliModule;\n versions: {\n readonly version: 'v1';\n readonly packageName: string;\n readonly commands: Promise<ReadonlyArray<CliCommand>>;\n };\n}>({\n type: '@backstage/CliModule',\n versions: ['v1'],\n});\n"],"names":["OpaqueType"],"mappings":";;;;AAmB+BA,sBAAW,MAAA,CAOvC;AAAA,EACD,IAAA,EAAM,sBAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;"}
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ var OpaqueType = require('../../opaque-internal/src/OpaqueType.cjs.js');
4
+
5
+ OpaqueType.OpaqueType.create({
6
+ type: "@backstage/CommandTreeNode",
7
+ versions: ["v1"]
8
+ });
9
+ OpaqueType.OpaqueType.create({
10
+ type: "@backstage/CommandLeafNode",
11
+ versions: ["v1"]
12
+ });
13
+ //# sourceMappingURL=InternalCommandNode.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InternalCommandNode.cjs.js","sources":["../../../../cli-internal/src/InternalCommandNode.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CliCommand, CliModule } from '@backstage/cli-node';\nimport { OpaqueType } from '@internal/opaque';\n\n/** @internal */\nexport interface CommandTreeNode {\n readonly $$type: '@backstage/CommandTreeNode';\n}\n\n/** @internal */\nexport interface CommandLeafNode {\n readonly $$type: '@backstage/CommandLeafNode';\n}\n\nexport type CommandNode = CommandTreeNode | CommandLeafNode;\n\nexport const OpaqueCommandTreeNode = OpaqueType.create<{\n public: CommandTreeNode;\n versions: {\n readonly version: 'v1';\n readonly name: string;\n readonly children: CommandNode[];\n };\n}>({\n type: '@backstage/CommandTreeNode',\n versions: ['v1'],\n});\n\nexport const OpaqueCommandLeafNode = OpaqueType.create<{\n public: CommandLeafNode;\n versions: {\n readonly version: 'v1';\n readonly name: string;\n readonly command: CliCommand;\n readonly module?: CliModule;\n };\n}>({\n type: '@backstage/CommandLeafNode',\n versions: ['v1'],\n});\n\n/**\n * Checks whether a command node should be hidden from help output.\n * Leaf nodes are hidden if they are deprecated or experimental.\n * Tree nodes are hidden if all of their children are hidden.\n */\nexport function isCommandNodeHidden(node: CommandNode): boolean {\n if (OpaqueCommandLeafNode.isType(node)) {\n const { command } = OpaqueCommandLeafNode.toInternal(node);\n return !!command.deprecated || !!command.experimental;\n }\n const { children } = OpaqueCommandTreeNode.toInternal(node);\n return children.every(child => isCommandNodeHidden(child));\n}\n"],"names":["OpaqueType"],"mappings":";;;;AA+BqCA,sBAAW,MAAA,CAO7C;AAAA,EACD,IAAA,EAAM,4BAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;AAEoCA,sBAAW,MAAA,CAQ7C;AAAA,EACD,IAAA,EAAM,4BAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;"}
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+
3
+ function getAuthInstanceService(instanceName) {
4
+ return `backstage-cli:auth-instance:${instanceName}`;
5
+ }
6
+
7
+ exports.getAuthInstanceService = getAuthInstanceService;
8
+ //# sourceMappingURL=authIdentifiers.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authIdentifiers.cjs.js","sources":["../../../../cli-internal/src/authIdentifiers.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/** Returns the secret-store service key for a given auth instance. */\nexport function getAuthInstanceService(instanceName: string): string {\n return `backstage-cli:auth-instance:${instanceName}`;\n}\n"],"names":[],"mappings":";;AAiBO,SAAS,uBAAuB,YAAA,EAA8B;AACnE,EAAA,OAAO,+BAA+B,YAAY,CAAA,CAAA;AACpD;;;;"}
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ const knownBackendPluginIds = [
4
+ "app",
5
+ "auth",
6
+ "catalog",
7
+ "events",
8
+ "kubernetes",
9
+ "notifications",
10
+ "permission",
11
+ "proxy",
12
+ "scaffolder",
13
+ "search",
14
+ "signals",
15
+ "techdocs"
16
+ ];
17
+ const knownFrontendPluginIds = [
18
+ "app",
19
+ "auth",
20
+ "catalog",
21
+ "kubernetes",
22
+ "notifications",
23
+ "scaffolder",
24
+ "search",
25
+ "signals",
26
+ "techdocs"
27
+ ];
28
+ Object.fromEntries(
29
+ knownBackendPluginIds.map((pluginId) => [
30
+ pluginId,
31
+ `@backstage/plugin-${pluginId}-backend`
32
+ ])
33
+ );
34
+ Object.fromEntries(
35
+ knownFrontendPluginIds.map((pluginId) => [
36
+ pluginId,
37
+ `@backstage/plugin-${pluginId}`
38
+ ])
39
+ );
40
+ //# sourceMappingURL=knownPluginPackages.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knownPluginPackages.cjs.js","sources":["../../../../cli-internal/src/knownPluginPackages.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst knownBackendPluginIds = [\n 'app',\n 'auth',\n 'catalog',\n 'events',\n 'kubernetes',\n 'notifications',\n 'permission',\n 'proxy',\n 'scaffolder',\n 'search',\n 'signals',\n 'techdocs',\n];\n\n// Only includes plugin IDs that have a corresponding frontend package; some plugins are backend-only and not listed here.\nconst knownFrontendPluginIds = [\n 'app',\n 'auth',\n 'catalog',\n 'kubernetes',\n 'notifications',\n 'scaffolder',\n 'search',\n 'signals',\n 'techdocs',\n];\n\n/**\n * Maps known plugin IDs to their corresponding backend package names.\n */\nexport const knownBackendPluginPackageNameByPluginId: Record<string, string> =\n Object.fromEntries(\n knownBackendPluginIds.map(pluginId => [\n pluginId,\n `@backstage/plugin-${pluginId}-backend`,\n ]),\n );\n\n/**\n * Maps known plugin IDs to their corresponding frontend package names.\n */\nexport const knownFrontendPluginPackageNameByPluginId: Record<string, string> =\n Object.fromEntries(\n knownFrontendPluginIds.map(pluginId => [\n pluginId,\n `@backstage/plugin-${pluginId}`,\n ]),\n );\n"],"names":[],"mappings":";;AAgBA,MAAM,qBAAA,GAAwB;AAAA,EAC5B,KAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,YAAA;AAAA,EACA,eAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,YAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA;AAGA,MAAM,sBAAA,GAAyB;AAAA,EAC7B,KAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA;AAAA,EACA,eAAA;AAAA,EACA,YAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA;AAME,MAAA,CAAO,WAAA;AAAA,EACL,qBAAA,CAAsB,IAAI,CAAA,QAAA,KAAY;AAAA,IACpC,QAAA;AAAA,IACA,qBAAqB,QAAQ,CAAA,QAAA;AAAA,GAC9B;AACH;AAMA,MAAA,CAAO,WAAA;AAAA,EACL,sBAAA,CAAuB,IAAI,CAAA,QAAA,KAAY;AAAA,IACrC,QAAA;AAAA,IACA,qBAAqB,QAAQ,CAAA;AAAA,GAC9B;AACH;;"}
@@ -1,12 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var fs = require('fs-extra');
3
+ var node_fs = require('node:fs');
4
4
  var os = require('node:os');
5
5
  var path = require('node:path');
6
6
 
7
7
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
8
8
 
9
- var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
10
9
  var os__default = /*#__PURE__*/_interopDefaultCompat(os);
11
10
  var path__default = /*#__PURE__*/_interopDefaultCompat(path);
12
11
 
@@ -36,6 +35,14 @@ class KeytarSecretStore {
36
35
  await this.keytar.deletePassword(service, account);
37
36
  }
38
37
  }
38
+ async function pathExists(p) {
39
+ try {
40
+ await node_fs.promises.stat(p);
41
+ return true;
42
+ } catch {
43
+ return false;
44
+ }
45
+ }
39
46
  class FileSecretStore {
40
47
  baseDir;
41
48
  constructor() {
@@ -51,17 +58,25 @@ class FileSecretStore {
51
58
  }
52
59
  async get(service, account) {
53
60
  const file = this.filePath(service, account);
54
- if (!await fs__default.default.pathExists(file)) return void 0;
55
- return await fs__default.default.readFile(file, "utf8");
61
+ if (!await pathExists(file)) {
62
+ return void 0;
63
+ }
64
+ return await node_fs.promises.readFile(file, "utf8");
56
65
  }
57
66
  async set(service, account, secret) {
58
67
  const file = this.filePath(service, account);
59
- await fs__default.default.ensureDir(path__default.default.dirname(file));
60
- await fs__default.default.writeFile(file, secret, { encoding: "utf8", mode: 384 });
68
+ await node_fs.promises.mkdir(path__default.default.dirname(file), { recursive: true });
69
+ await node_fs.promises.writeFile(file, secret, { encoding: "utf8", mode: 384 });
61
70
  }
62
71
  async delete(service, account) {
63
72
  const file = this.filePath(service, account);
64
- await fs__default.default.remove(file);
73
+ try {
74
+ await node_fs.promises.unlink(file);
75
+ } catch (err) {
76
+ if (err.code !== "ENOENT") {
77
+ throw err;
78
+ }
79
+ }
65
80
  }
66
81
  }
67
82
  let singleton;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secretStore.cjs.js","sources":["../../../../cli-internal/src/secretStore.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nexport type SecretStore = {\n get(service: string, account: string): Promise<string | undefined>;\n set(service: string, account: string, secret: string): Promise<void>;\n delete(service: string, account: string): Promise<void>;\n};\n\nasync function loadKeytar(): Promise<typeof import('keytar') | undefined> {\n try {\n // eslint-disable-next-line import/no-extraneous-dependencies, @backstage/no-undeclared-imports\n const keytar = require('keytar') as typeof import('keytar');\n if (keytar && typeof keytar.getPassword === 'function') {\n return keytar;\n }\n } catch {\n // keytar not available\n }\n return undefined;\n}\n\nclass KeytarSecretStore implements SecretStore {\n private readonly keytar: typeof import('keytar');\n constructor(keytar: typeof import('keytar')) {\n this.keytar = keytar;\n }\n async get(service: string, account: string): Promise<string | undefined> {\n const result = await this.keytar.getPassword(service, account);\n return result ?? undefined;\n }\n async set(service: string, account: string, secret: string): Promise<void> {\n await this.keytar.setPassword(service, account, secret);\n }\n async delete(service: string, account: string): Promise<void> {\n await this.keytar.deletePassword(service, account);\n }\n}\n\nasync function pathExists(p: string): Promise<boolean> {\n try {\n await fs.stat(p);\n return true;\n } catch {\n return false;\n }\n}\n\nclass FileSecretStore implements SecretStore {\n private readonly baseDir: string;\n constructor() {\n const root =\n process.env.XDG_DATA_HOME ||\n (process.platform === 'win32'\n ? process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming')\n : path.join(os.homedir(), '.local', 'share'));\n this.baseDir = path.join(root, 'backstage-cli', 'auth-secrets');\n }\n private filePath(service: string, account: string): string {\n return path.join(\n this.baseDir,\n encodeURIComponent(service),\n `${encodeURIComponent(account)}.secret`,\n );\n }\n async get(service: string, account: string): Promise<string | undefined> {\n const file = this.filePath(service, account);\n if (!(await pathExists(file))) {\n return undefined;\n }\n return await fs.readFile(file, 'utf8');\n }\n async set(service: string, account: string, secret: string): Promise<void> {\n const file = this.filePath(service, account);\n await fs.mkdir(path.dirname(file), { recursive: true });\n await fs.writeFile(file, secret, { encoding: 'utf8', mode: 0o600 });\n }\n async delete(service: string, account: string): Promise<void> {\n const file = this.filePath(service, account);\n try {\n await fs.unlink(file);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw err;\n }\n }\n }\n}\n\nlet singleton: SecretStore | undefined;\n\nexport async function getSecretStore(): Promise<SecretStore> {\n if (!singleton) {\n const keytar = await loadKeytar();\n if (keytar) {\n singleton = new KeytarSecretStore(keytar);\n } else {\n singleton = new FileSecretStore();\n }\n }\n return singleton;\n}\n\n/**\n * Reset the singleton instance (for testing purposes only)\n * @internal\n */\nexport function resetSecretStore(): void {\n singleton = undefined;\n}\n"],"names":["fs","path","os"],"mappings":"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"}
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var name = "@backstage/cli-module-auth";
6
- var version = "0.0.0-nightly-20260317031259";
6
+ var version = "0.1.0";
7
7
  var description = "CLI module for Backstage CLI";
8
8
  var backstage = {
9
9
  role: "cli-module"
@@ -22,6 +22,7 @@ var repository = {
22
22
  var license = "Apache-2.0";
23
23
  var main = "src/index.ts";
24
24
  var types = "src/index.ts";
25
+ var bin = "bin/backstage-cli-module-auth";
25
26
  var files = [
26
27
  "dist",
27
28
  "bin"
@@ -35,10 +36,9 @@ var scripts = {
35
36
  test: "backstage-cli package test"
36
37
  };
37
38
  var dependencies = {
38
- "@backstage/cli-node": "workspace:*",
39
- "@backstage/errors": "workspace:*",
39
+ "@backstage/cli-node": "workspace:^",
40
+ "@backstage/errors": "workspace:^",
40
41
  cleye: "^2.3.0",
41
- "cross-fetch": "^4.0.0",
42
42
  "fs-extra": "^11.2.0",
43
43
  glob: "^7.1.7",
44
44
  inquirer: "^8.2.0",
@@ -47,15 +47,14 @@ var dependencies = {
47
47
  zod: "^3.25.76"
48
48
  };
49
49
  var devDependencies = {
50
- "@backstage/backend-test-utils": "workspace:*",
51
- "@backstage/cli": "workspace:*",
50
+ "@backstage/backend-test-utils": "workspace:^",
51
+ "@backstage/cli": "workspace:^",
52
52
  "@types/fs-extra": "^11.0.0",
53
53
  "@types/proper-lockfile": "^4"
54
54
  };
55
55
  var optionalDependencies = {
56
56
  keytar: "^7.9.0"
57
57
  };
58
- var bin = "bin/backstage-cli-module-auth";
59
58
  var packageJson = {
60
59
  name: name,
61
60
  version: version,
@@ -67,12 +66,12 @@ var packageJson = {
67
66
  license: license,
68
67
  main: main,
69
68
  types: types,
69
+ bin: bin,
70
70
  files: files,
71
71
  scripts: scripts,
72
72
  dependencies: dependencies,
73
73
  devDependencies: devDependencies,
74
- optionalDependencies: optionalDependencies,
75
- bin: bin
74
+ optionalDependencies: optionalDependencies
76
75
  };
77
76
 
78
77
  exports.backstage = backstage;
@@ -1 +1 @@
1
- {"version":3,"file":"package.json.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"package.json.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -8,7 +8,11 @@ var node_child_process = require('node:child_process');
8
8
  var pkce = require('../lib/pkce.cjs.js');
9
9
  var http = require('../lib/http.cjs.js');
10
10
  var storage = require('../lib/storage.cjs.js');
11
- var secretStore = require('../lib/secretStore.cjs.js');
11
+ require('../cli-internal/src/InternalCliModule.cjs.js');
12
+ require('../cli-internal/src/InternalCommandNode.cjs.js');
13
+ var authIdentifiers = require('../cli-internal/src/authIdentifiers.cjs.js');
14
+ var secretStore = require('../cli-internal/src/secretStore.cjs.js');
15
+ require('../cli-internal/src/knownPluginPackages.cjs.js');
12
16
  var crypto = require('node:crypto');
13
17
  var fs = require('fs-extra');
14
18
  var path = require('node:path');
@@ -253,7 +257,7 @@ async function persistInstance(options) {
253
257
  const { instanceName, backendBaseUrl, clientId, token } = options;
254
258
  const secretStore$1 = await secretStore.getSecretStore();
255
259
  await storage.withMetadataLock(async () => {
256
- const service = `backstage-cli:auth-instance:${instanceName}`;
260
+ const service = authIdentifiers.getAuthInstanceService(instanceName);
257
261
  await secretStore$1.set(service, "accessToken", token.access_token);
258
262
  if (token.refresh_token) {
259
263
  await secretStore$1.set(service, "refreshToken", token.refresh_token);
@@ -1 +1 @@
1
- {"version":3,"file":"login.cjs.js","sources":["../../src/commands/login.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { cli } from 'cleye';\nimport type { CliCommandContext } from '@backstage/cli-node';\nimport { startCallbackServer } from '../lib/localServer';\nimport { spawn } from 'node:child_process';\nimport { challengeFromVerifier, generateVerifier } from '../lib/pkce';\nimport { httpJson } from '../lib/http';\nimport {\n upsertInstance,\n withMetadataLock,\n getAllInstances,\n getInstanceByName,\n StoredInstance,\n} from '../lib/storage';\nimport { getSecretStore } from '../lib/secretStore';\nimport crypto from 'node:crypto';\nimport fs from 'fs-extra';\nimport path from 'node:path';\nimport glob from 'glob';\nimport YAML from 'yaml';\nimport inquirer from 'inquirer';\n\nconst TOKEN_EXCHANGE_TIMEOUT_MS = 30_000;\n\nexport default async ({ args, info }: CliCommandContext) => {\n const {\n flags: { backendUrl, noBrowser, instance: instanceFlag },\n } = cli(\n {\n help: info,\n flags: {\n backendUrl: { type: String, description: 'Backend base URL' },\n noBrowser: {\n type: Boolean,\n description: 'Do not open browser automatically',\n },\n instance: {\n type: String,\n description: 'Name for this instance (used by other auth commands)',\n },\n },\n },\n undefined,\n args,\n );\n\n const { instances, selected } = await getAllInstances();\n\n let backendBaseUrl: string;\n let instanceName: string;\n\n if (instanceFlag) {\n instanceName = instanceFlag;\n const targetInstance = instances.find(i => i.name === instanceFlag);\n if (targetInstance) {\n backendBaseUrl = normalizeUrl(backendUrl) ?? targetInstance.baseUrl;\n } else {\n backendBaseUrl = normalizeUrl(backendUrl) ?? (await pickBaseUrl());\n }\n } else if (backendUrl) {\n backendBaseUrl = normalizeUrl(backendUrl);\n instanceName = deriveInstanceName(backendBaseUrl);\n } else if (instances.length > 0) {\n const choice = await promptForInstance(instances, selected);\n if (choice === '__new__') {\n backendBaseUrl = await pickBaseUrl();\n instanceName = deriveInstanceName(backendBaseUrl);\n } else {\n const targetInstance = instances.find(i => i.name === choice);\n if (!targetInstance) {\n throw new Error('Instance not found');\n }\n backendBaseUrl = targetInstance.baseUrl;\n instanceName = targetInstance.name;\n }\n } else {\n backendBaseUrl = await pickBaseUrl();\n instanceName = deriveInstanceName(backendBaseUrl);\n }\n\n const authBaseUrl = `${backendBaseUrl}/api/auth`;\n const clientId = `${authBaseUrl}/.well-known/oauth-client/cli.json`;\n\n const metadataResponse = await fetch(clientId, {\n signal: AbortSignal.timeout(30_000),\n });\n if (!metadataResponse.ok) {\n throw new Error(\n `Server does not support CLI authentication. Ensure CIMD is enabled on the backend.`,\n );\n }\n\n const { verifier, challenge, state } = createPkceState();\n const callback = await startCallbackServer({ state });\n\n try {\n const authorizeUrl = buildAuthorizeUrl({\n authBaseUrl,\n clientId,\n redirectUri: callback.url,\n state,\n challenge,\n });\n\n await openBrowserOrPrint(authorizeUrl, noBrowser);\n\n const code = await waitForAuthorizationCode(callback, state);\n\n const token = await exchangeAuthorizationCode({\n authBaseUrl,\n code,\n redirectUri: callback.url,\n verifier,\n });\n\n await persistInstance({\n instanceName,\n backendBaseUrl,\n clientId,\n token,\n });\n\n process.stdout.write('Login successful\\n');\n } finally {\n await callback.close();\n }\n};\n\nasync function promptForInstance(\n instances: StoredInstance[],\n selected: StoredInstance | undefined,\n): Promise<string> {\n const choices = instances.map(i => ({\n name: `${i.name === selected?.name ? '* ' : ' '}${i.name} (${i.baseUrl})`,\n value: i.name,\n }));\n\n choices.push({\n name: 'Add new instance...',\n value: '__new__',\n });\n\n const { choice } = await inquirer.prompt<{ choice: string }>([\n {\n type: 'list',\n name: 'choice',\n message: 'Select instance to authenticate:',\n choices,\n default: selected?.name ?? '__new__',\n },\n ]);\n\n return choice;\n}\n\nasync function pickBaseUrl() {\n const cwd = process.cwd();\n const candidates: Array<{ url: string; file: string }> = [];\n\n const patterns = [\n 'app-config.yaml',\n 'app-config.*.yaml',\n 'packages/*/app-config.yaml',\n 'packages/*/app-config.*.yaml',\n ];\n const files = patterns.flatMap(p => glob.sync(p, { cwd, nodir: true }));\n for (const file of files) {\n try {\n const content = await fs.readFile(path.resolve(cwd, file), 'utf8');\n const doc = YAML.parse(content);\n const url = doc?.backend?.baseUrl as string | undefined;\n if (url) {\n candidates.push({ url: normalizeUrl(url), file });\n }\n } catch {\n // ignore parse errors\n }\n }\n\n const list = [...new Map(candidates.map(c => [c.url, c])).values()];\n if (list.length === 0) {\n const { manual } = await inquirer.prompt<{ manual: string }>([\n { type: 'input', name: 'manual', message: 'Enter backend base URL' },\n ]);\n return normalizeUrl(manual);\n }\n if (list.length === 1) {\n return list[0].url;\n }\n\n const { picked } = await inquirer.prompt<{ picked: string }>([\n {\n type: 'list',\n name: 'picked',\n message: 'Select backend base URL',\n choices: [\n ...list.map(e => ({ name: `${e.url} (${e.file})`, value: e.url })),\n { name: 'Enter manually', value: '__manual__' },\n ],\n },\n ]);\n if (picked === '__manual__') {\n const { manual } = await inquirer.prompt<{ manual: string }>([\n { type: 'input', name: 'manual', message: 'Enter backend base URL' },\n ]);\n return normalizeUrl(manual);\n }\n return picked;\n}\n\nfunction normalizeUrl(u: string): string;\nfunction normalizeUrl(u: string | undefined): string | undefined;\nfunction normalizeUrl(u: string | undefined): string | undefined {\n if (u === undefined) {\n return undefined;\n }\n try {\n const url = new URL(u);\n return url.toString().replace(/\\/$/, '');\n } catch {\n throw new Error(`'${u}' is not a valid URL`);\n }\n}\n\nfunction deriveInstanceName(url: string): string {\n return new URL(url).host;\n}\n\nfunction createPkceState() {\n const verifier = generateVerifier();\n const challenge = challengeFromVerifier(verifier);\n const state = cryptoRandom();\n return { verifier, challenge, state };\n}\n\nfunction buildAuthorizeUrl(options: {\n authBaseUrl: string;\n clientId: string;\n redirectUri: string;\n state: string;\n challenge: string;\n}): string {\n const { authBaseUrl, clientId, redirectUri, state, challenge } = options;\n const authorize = new URL(`${authBaseUrl}/v1/authorize`);\n authorize.searchParams.set('client_id', clientId);\n authorize.searchParams.set('redirect_uri', redirectUri);\n authorize.searchParams.set('response_type', 'code');\n authorize.searchParams.set('scope', 'openid offline_access');\n authorize.searchParams.set('state', state);\n authorize.searchParams.set('code_challenge', challenge);\n authorize.searchParams.set('code_challenge_method', 'S256');\n return authorize.toString();\n}\n\nasync function openBrowserOrPrint(url: string, noBrowser?: boolean) {\n if (noBrowser) {\n process.stdout.write(`Open this URL to continue: ${url}\\n`);\n } else {\n process.stdout.write(`Opening the following URL: ${url}\\n`);\n openInBrowser(url);\n }\n}\n\nasync function waitForAuthorizationCode(\n callback: Awaited<ReturnType<typeof startCallbackServer>>,\n expectedState: string,\n) {\n const { code, state } = await callback.waitForCode();\n if (state !== expectedState) {\n throw new Error('State mismatch');\n }\n return code;\n}\n\nasync function exchangeAuthorizationCode(options: {\n authBaseUrl: string;\n code: string;\n redirectUri: string;\n verifier: string;\n}) {\n const { authBaseUrl, code, redirectUri, verifier } = options;\n return await httpJson<{\n access_token: string;\n token_type: string;\n expires_in: number;\n id_token?: string;\n refresh_token?: string;\n }>(`${authBaseUrl}/v1/token`, {\n method: 'POST',\n body: {\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n code_verifier: verifier,\n },\n signal: AbortSignal.timeout(TOKEN_EXCHANGE_TIMEOUT_MS),\n });\n}\n\nasync function persistInstance(options: {\n instanceName: string;\n backendBaseUrl: string;\n clientId: string;\n token: { access_token: string; refresh_token?: string; expires_in: number };\n}) {\n const { instanceName, backendBaseUrl, clientId, token } = options;\n const secretStore = await getSecretStore();\n await withMetadataLock(async () => {\n const service = `backstage-cli:auth-instance:${instanceName}`;\n await secretStore.set(service, 'accessToken', token.access_token);\n if (token.refresh_token) {\n await secretStore.set(service, 'refreshToken', token.refresh_token);\n } else {\n process.stderr.write(\n 'Warning: No refresh token received. You will need to re-authenticate when the access token expires.\\n',\n );\n }\n let existing: StoredInstance | undefined;\n try {\n existing = await getInstanceByName(instanceName);\n } catch {\n // new instance\n }\n await upsertInstance({\n name: instanceName,\n baseUrl: backendBaseUrl,\n clientId,\n issuedAt: Date.now(),\n accessTokenExpiresAt: Date.now() + token.expires_in * 1000,\n selected: existing?.selected,\n });\n });\n}\n\nfunction cryptoRandom(): string {\n return crypto.randomBytes(32).toString('hex');\n}\n\n// The react-dev-utils/openBrowser breaks the login URL by encoding the URL parameters again\nexport function openInBrowser(url: string): void {\n const handleError = (error: unknown) => {\n const message = error instanceof Error ? error.message : 'Unknown error';\n process.stderr.write(\n `Warning: Failed to open browser automatically: ${message}\\n`,\n );\n process.stderr.write(`Please open this URL manually: ${url}\\n`);\n };\n\n const spawnOpts = { detached: true, stdio: 'ignore' } as const;\n let child;\n try {\n if (process.platform === 'darwin') {\n child = spawn('open', [url], spawnOpts);\n } else if (process.platform === 'win32') {\n child = spawn(\n 'powershell',\n ['-Command', `Start-Process '${url.replace(/'/g, \"''\")}'`],\n spawnOpts,\n );\n } else {\n child = spawn('xdg-open', [url], spawnOpts);\n }\n child.unref();\n child.on('error', handleError);\n } catch (error) {\n handleError(error);\n }\n}\n"],"names":["cli","getAllInstances","startCallbackServer","inquirer","glob","fs","path","YAML","generateVerifier","challengeFromVerifier","httpJson","secretStore","getSecretStore","withMetadataLock","getInstanceByName","upsertInstance","crypto","spawn"],"mappings":"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"}
1
+ {"version":3,"file":"login.cjs.js","sources":["../../src/commands/login.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { cli } from 'cleye';\nimport type { CliCommandContext } from '@backstage/cli-node';\nimport { startCallbackServer } from '../lib/localServer';\nimport { spawn } from 'node:child_process';\nimport { challengeFromVerifier, generateVerifier } from '../lib/pkce';\nimport { httpJson } from '../lib/http';\nimport {\n upsertInstance,\n withMetadataLock,\n getAllInstances,\n getInstanceByName,\n StoredInstance,\n} from '../lib/storage';\nimport { getSecretStore, getAuthInstanceService } from '@internal/cli';\nimport crypto from 'node:crypto';\nimport fs from 'fs-extra';\nimport path from 'node:path';\nimport glob from 'glob';\nimport YAML from 'yaml';\nimport inquirer from 'inquirer';\n\nconst TOKEN_EXCHANGE_TIMEOUT_MS = 30_000;\n\nexport default async ({ args, info }: CliCommandContext) => {\n const {\n flags: { backendUrl, noBrowser, instance: instanceFlag },\n } = cli(\n {\n help: info,\n flags: {\n backendUrl: { type: String, description: 'Backend base URL' },\n noBrowser: {\n type: Boolean,\n description: 'Do not open browser automatically',\n },\n instance: {\n type: String,\n description: 'Name for this instance (used by other auth commands)',\n },\n },\n },\n undefined,\n args,\n );\n\n const { instances, selected } = await getAllInstances();\n\n let backendBaseUrl: string;\n let instanceName: string;\n\n if (instanceFlag) {\n instanceName = instanceFlag;\n const targetInstance = instances.find(i => i.name === instanceFlag);\n if (targetInstance) {\n backendBaseUrl = normalizeUrl(backendUrl) ?? targetInstance.baseUrl;\n } else {\n backendBaseUrl = normalizeUrl(backendUrl) ?? (await pickBaseUrl());\n }\n } else if (backendUrl) {\n backendBaseUrl = normalizeUrl(backendUrl);\n instanceName = deriveInstanceName(backendBaseUrl);\n } else if (instances.length > 0) {\n const choice = await promptForInstance(instances, selected);\n if (choice === '__new__') {\n backendBaseUrl = await pickBaseUrl();\n instanceName = deriveInstanceName(backendBaseUrl);\n } else {\n const targetInstance = instances.find(i => i.name === choice);\n if (!targetInstance) {\n throw new Error('Instance not found');\n }\n backendBaseUrl = targetInstance.baseUrl;\n instanceName = targetInstance.name;\n }\n } else {\n backendBaseUrl = await pickBaseUrl();\n instanceName = deriveInstanceName(backendBaseUrl);\n }\n\n const authBaseUrl = `${backendBaseUrl}/api/auth`;\n const clientId = `${authBaseUrl}/.well-known/oauth-client/cli.json`;\n\n const metadataResponse = await fetch(clientId, {\n signal: AbortSignal.timeout(30_000),\n });\n if (!metadataResponse.ok) {\n throw new Error(\n `Server does not support CLI authentication. Ensure CIMD is enabled on the backend.`,\n );\n }\n\n const { verifier, challenge, state } = createPkceState();\n const callback = await startCallbackServer({ state });\n\n try {\n const authorizeUrl = buildAuthorizeUrl({\n authBaseUrl,\n clientId,\n redirectUri: callback.url,\n state,\n challenge,\n });\n\n await openBrowserOrPrint(authorizeUrl, noBrowser);\n\n const code = await waitForAuthorizationCode(callback, state);\n\n const token = await exchangeAuthorizationCode({\n authBaseUrl,\n code,\n redirectUri: callback.url,\n verifier,\n });\n\n await persistInstance({\n instanceName,\n backendBaseUrl,\n clientId,\n token,\n });\n\n process.stdout.write('Login successful\\n');\n } finally {\n await callback.close();\n }\n};\n\nasync function promptForInstance(\n instances: StoredInstance[],\n selected: StoredInstance | undefined,\n): Promise<string> {\n const choices = instances.map(i => ({\n name: `${i.name === selected?.name ? '* ' : ' '}${i.name} (${i.baseUrl})`,\n value: i.name,\n }));\n\n choices.push({\n name: 'Add new instance...',\n value: '__new__',\n });\n\n const { choice } = await inquirer.prompt<{ choice: string }>([\n {\n type: 'list',\n name: 'choice',\n message: 'Select instance to authenticate:',\n choices,\n default: selected?.name ?? '__new__',\n },\n ]);\n\n return choice;\n}\n\nasync function pickBaseUrl() {\n const cwd = process.cwd();\n const candidates: Array<{ url: string; file: string }> = [];\n\n const patterns = [\n 'app-config.yaml',\n 'app-config.*.yaml',\n 'packages/*/app-config.yaml',\n 'packages/*/app-config.*.yaml',\n ];\n const files = patterns.flatMap(p => glob.sync(p, { cwd, nodir: true }));\n for (const file of files) {\n try {\n const content = await fs.readFile(path.resolve(cwd, file), 'utf8');\n const doc = YAML.parse(content);\n const url = doc?.backend?.baseUrl as string | undefined;\n if (url) {\n candidates.push({ url: normalizeUrl(url), file });\n }\n } catch {\n // ignore parse errors\n }\n }\n\n const list = [...new Map(candidates.map(c => [c.url, c])).values()];\n if (list.length === 0) {\n const { manual } = await inquirer.prompt<{ manual: string }>([\n { type: 'input', name: 'manual', message: 'Enter backend base URL' },\n ]);\n return normalizeUrl(manual);\n }\n if (list.length === 1) {\n return list[0].url;\n }\n\n const { picked } = await inquirer.prompt<{ picked: string }>([\n {\n type: 'list',\n name: 'picked',\n message: 'Select backend base URL',\n choices: [\n ...list.map(e => ({ name: `${e.url} (${e.file})`, value: e.url })),\n { name: 'Enter manually', value: '__manual__' },\n ],\n },\n ]);\n if (picked === '__manual__') {\n const { manual } = await inquirer.prompt<{ manual: string }>([\n { type: 'input', name: 'manual', message: 'Enter backend base URL' },\n ]);\n return normalizeUrl(manual);\n }\n return picked;\n}\n\nfunction normalizeUrl(u: string): string;\nfunction normalizeUrl(u: string | undefined): string | undefined;\nfunction normalizeUrl(u: string | undefined): string | undefined {\n if (u === undefined) {\n return undefined;\n }\n try {\n const url = new URL(u);\n return url.toString().replace(/\\/$/, '');\n } catch {\n throw new Error(`'${u}' is not a valid URL`);\n }\n}\n\nfunction deriveInstanceName(url: string): string {\n return new URL(url).host;\n}\n\nfunction createPkceState() {\n const verifier = generateVerifier();\n const challenge = challengeFromVerifier(verifier);\n const state = cryptoRandom();\n return { verifier, challenge, state };\n}\n\nfunction buildAuthorizeUrl(options: {\n authBaseUrl: string;\n clientId: string;\n redirectUri: string;\n state: string;\n challenge: string;\n}): string {\n const { authBaseUrl, clientId, redirectUri, state, challenge } = options;\n const authorize = new URL(`${authBaseUrl}/v1/authorize`);\n authorize.searchParams.set('client_id', clientId);\n authorize.searchParams.set('redirect_uri', redirectUri);\n authorize.searchParams.set('response_type', 'code');\n authorize.searchParams.set('scope', 'openid offline_access');\n authorize.searchParams.set('state', state);\n authorize.searchParams.set('code_challenge', challenge);\n authorize.searchParams.set('code_challenge_method', 'S256');\n return authorize.toString();\n}\n\nasync function openBrowserOrPrint(url: string, noBrowser?: boolean) {\n if (noBrowser) {\n process.stdout.write(`Open this URL to continue: ${url}\\n`);\n } else {\n process.stdout.write(`Opening the following URL: ${url}\\n`);\n openInBrowser(url);\n }\n}\n\nasync function waitForAuthorizationCode(\n callback: Awaited<ReturnType<typeof startCallbackServer>>,\n expectedState: string,\n) {\n const { code, state } = await callback.waitForCode();\n if (state !== expectedState) {\n throw new Error('State mismatch');\n }\n return code;\n}\n\nasync function exchangeAuthorizationCode(options: {\n authBaseUrl: string;\n code: string;\n redirectUri: string;\n verifier: string;\n}) {\n const { authBaseUrl, code, redirectUri, verifier } = options;\n return await httpJson<{\n access_token: string;\n token_type: string;\n expires_in: number;\n id_token?: string;\n refresh_token?: string;\n }>(`${authBaseUrl}/v1/token`, {\n method: 'POST',\n body: {\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n code_verifier: verifier,\n },\n signal: AbortSignal.timeout(TOKEN_EXCHANGE_TIMEOUT_MS),\n });\n}\n\nasync function persistInstance(options: {\n instanceName: string;\n backendBaseUrl: string;\n clientId: string;\n token: { access_token: string; refresh_token?: string; expires_in: number };\n}) {\n const { instanceName, backendBaseUrl, clientId, token } = options;\n const secretStore = await getSecretStore();\n await withMetadataLock(async () => {\n const service = getAuthInstanceService(instanceName);\n await secretStore.set(service, 'accessToken', token.access_token);\n if (token.refresh_token) {\n await secretStore.set(service, 'refreshToken', token.refresh_token);\n } else {\n process.stderr.write(\n 'Warning: No refresh token received. You will need to re-authenticate when the access token expires.\\n',\n );\n }\n let existing: StoredInstance | undefined;\n try {\n existing = await getInstanceByName(instanceName);\n } catch {\n // new instance\n }\n await upsertInstance({\n name: instanceName,\n baseUrl: backendBaseUrl,\n clientId,\n issuedAt: Date.now(),\n accessTokenExpiresAt: Date.now() + token.expires_in * 1000,\n selected: existing?.selected,\n });\n });\n}\n\nfunction cryptoRandom(): string {\n return crypto.randomBytes(32).toString('hex');\n}\n\n// The react-dev-utils/openBrowser breaks the login URL by encoding the URL parameters again\nexport function openInBrowser(url: string): void {\n const handleError = (error: unknown) => {\n const message = error instanceof Error ? error.message : 'Unknown error';\n process.stderr.write(\n `Warning: Failed to open browser automatically: ${message}\\n`,\n );\n process.stderr.write(`Please open this URL manually: ${url}\\n`);\n };\n\n const spawnOpts = { detached: true, stdio: 'ignore' } as const;\n let child;\n try {\n if (process.platform === 'darwin') {\n child = spawn('open', [url], spawnOpts);\n } else if (process.platform === 'win32') {\n child = spawn(\n 'powershell',\n ['-Command', `Start-Process '${url.replace(/'/g, \"''\")}'`],\n spawnOpts,\n );\n } else {\n child = spawn('xdg-open', [url], spawnOpts);\n }\n child.unref();\n child.on('error', handleError);\n } catch (error) {\n handleError(error);\n }\n}\n"],"names":["cli","getAllInstances","startCallbackServer","inquirer","glob","fs","path","YAML","generateVerifier","challengeFromVerifier","httpJson","secretStore","getSecretStore","withMetadataLock","getAuthInstanceService","getInstanceByName","upsertInstance","crypto","spawn"],"mappings":"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"}
@@ -3,7 +3,11 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var cleye = require('cleye');
6
- var secretStore = require('../lib/secretStore.cjs.js');
6
+ require('../cli-internal/src/InternalCliModule.cjs.js');
7
+ require('../cli-internal/src/InternalCommandNode.cjs.js');
8
+ var authIdentifiers = require('../cli-internal/src/authIdentifiers.cjs.js');
9
+ var secretStore = require('../cli-internal/src/secretStore.cjs.js');
10
+ require('../cli-internal/src/knownPluginPackages.cjs.js');
7
11
  var storage = require('../lib/storage.cjs.js');
8
12
  var http = require('../lib/http.cjs.js');
9
13
  var prompt = require('../lib/prompt.cjs.js');
@@ -28,7 +32,7 @@ var logout = async ({ args, info }) => {
28
32
  await storage.withMetadataLock(async () => {
29
33
  const instance = await storage.getInstanceByName(instanceName);
30
34
  const secretStore$1 = await secretStore.getSecretStore();
31
- const service = `backstage-cli:auth-instance:${instanceName}`;
35
+ const service = authIdentifiers.getAuthInstanceService(instanceName);
32
36
  const refreshToken = await secretStore$1.get(service, "refreshToken") ?? "";
33
37
  if (refreshToken) {
34
38
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"logout.cjs.js","sources":["../../src/commands/logout.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { cli } from 'cleye';\nimport type { CliCommandContext } from '@backstage/cli-node';\nimport { getSecretStore } from '../lib/secretStore';\nimport {\n removeInstance,\n withMetadataLock,\n getInstanceByName,\n} from '../lib/storage';\nimport { httpJson } from '../lib/http';\nimport { pickInstance } from '../lib/prompt';\n\nexport default async ({ args, info }: CliCommandContext) => {\n const {\n flags: { instance: instanceFlag },\n } = cli(\n {\n help: info,\n flags: {\n instance: {\n type: String,\n description: 'Name of the instance to log out',\n },\n },\n },\n undefined,\n args,\n );\n\n const { name: instanceName } = await pickInstance(instanceFlag);\n\n await withMetadataLock(async () => {\n const instance = await getInstanceByName(instanceName);\n const secretStore = await getSecretStore();\n const service = `backstage-cli:auth-instance:${instanceName}`;\n const refreshToken = (await secretStore.get(service, 'refreshToken')) ?? '';\n\n if (refreshToken) {\n try {\n const authBaseUrl = new URL('/api/auth', instance.baseUrl)\n .toString()\n .replace(/\\/$/, '');\n await httpJson(`${authBaseUrl}/v1/revoke`, {\n method: 'POST',\n body: {\n token: refreshToken,\n token_type_hint: 'refresh_token',\n },\n signal: AbortSignal.timeout(30_000),\n });\n } catch {\n // ignore errors per RFC 7009\n }\n }\n\n await secretStore.delete(service, 'accessToken');\n await secretStore.delete(service, 'refreshToken');\n await removeInstance(instance.name);\n });\n\n process.stdout.write('Logged out\\n');\n};\n"],"names":["cli","pickInstance","withMetadataLock","getInstanceByName","secretStore","getSecretStore","httpJson","removeInstance"],"mappings":";;;;;;;;;;AA2BA,aAAe,OAAO,EAAE,IAAA,EAAM,IAAA,EAAK,KAAyB;AAC1D,EAAA,MAAM;AAAA,IACJ,KAAA,EAAO,EAAE,QAAA,EAAU,YAAA;AAAa,GAClC,GAAIA,SAAA;AAAA,IACF;AAAA,MACE,IAAA,EAAM,IAAA;AAAA,MACN,KAAA,EAAO;AAAA,QACL,QAAA,EAAU;AAAA,UACR,IAAA,EAAM,MAAA;AAAA,UACN,WAAA,EAAa;AAAA;AACf;AACF,KACF;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,MAAM,EAAE,IAAA,EAAM,YAAA,EAAa,GAAI,MAAMC,oBAAa,YAAY,CAAA;AAE9D,EAAA,MAAMC,yBAAiB,YAAY;AACjC,IAAA,MAAM,QAAA,GAAW,MAAMC,yBAAA,CAAkB,YAAY,CAAA;AACrD,IAAA,MAAMC,aAAA,GAAc,MAAMC,0BAAA,EAAe;AACzC,IAAA,MAAM,OAAA,GAAU,+BAA+B,YAAY,CAAA,CAAA;AAC3D,IAAA,MAAM,eAAgB,MAAMD,aAAA,CAAY,GAAA,CAAI,OAAA,EAAS,cAAc,CAAA,IAAM,EAAA;AAEzE,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,IAAI;AACF,QAAA,MAAM,WAAA,GAAc,IAAI,GAAA,CAAI,WAAA,EAAa,QAAA,CAAS,OAAO,CAAA,CACtD,QAAA,EAAS,CACT,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AACpB,QAAA,MAAME,aAAA,CAAS,CAAA,EAAG,WAAW,CAAA,UAAA,CAAA,EAAc;AAAA,UACzC,MAAA,EAAQ,MAAA;AAAA,UACR,IAAA,EAAM;AAAA,YACJ,KAAA,EAAO,YAAA;AAAA,YACP,eAAA,EAAiB;AAAA,WACnB;AAAA,UACA,MAAA,EAAQ,WAAA,CAAY,OAAA,CAAQ,GAAM;AAAA,SACnC,CAAA;AAAA,MACH,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AAEA,IAAA,MAAMF,aAAA,CAAY,MAAA,CAAO,OAAA,EAAS,aAAa,CAAA;AAC/C,IAAA,MAAMA,aAAA,CAAY,MAAA,CAAO,OAAA,EAAS,cAAc,CAAA;AAChD,IAAA,MAAMG,sBAAA,CAAe,SAAS,IAAI,CAAA;AAAA,EACpC,CAAC,CAAA;AAED,EAAA,OAAA,CAAQ,MAAA,CAAO,MAAM,cAAc,CAAA;AACrC,CAAA;;;;"}
1
+ {"version":3,"file":"logout.cjs.js","sources":["../../src/commands/logout.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { cli } from 'cleye';\nimport type { CliCommandContext } from '@backstage/cli-node';\nimport { getSecretStore, getAuthInstanceService } from '@internal/cli';\nimport {\n removeInstance,\n withMetadataLock,\n getInstanceByName,\n} from '../lib/storage';\nimport { httpJson } from '../lib/http';\nimport { pickInstance } from '../lib/prompt';\n\nexport default async ({ args, info }: CliCommandContext) => {\n const {\n flags: { instance: instanceFlag },\n } = cli(\n {\n help: info,\n flags: {\n instance: {\n type: String,\n description: 'Name of the instance to log out',\n },\n },\n },\n undefined,\n args,\n );\n\n const { name: instanceName } = await pickInstance(instanceFlag);\n\n await withMetadataLock(async () => {\n const instance = await getInstanceByName(instanceName);\n const secretStore = await getSecretStore();\n const service = getAuthInstanceService(instanceName);\n const refreshToken = (await secretStore.get(service, 'refreshToken')) ?? '';\n\n if (refreshToken) {\n try {\n const authBaseUrl = new URL('/api/auth', instance.baseUrl)\n .toString()\n .replace(/\\/$/, '');\n await httpJson(`${authBaseUrl}/v1/revoke`, {\n method: 'POST',\n body: {\n token: refreshToken,\n token_type_hint: 'refresh_token',\n },\n signal: AbortSignal.timeout(30_000),\n });\n } catch {\n // ignore errors per RFC 7009\n }\n }\n\n await secretStore.delete(service, 'accessToken');\n await secretStore.delete(service, 'refreshToken');\n await removeInstance(instance.name);\n });\n\n process.stdout.write('Logged out\\n');\n};\n"],"names":["cli","pickInstance","withMetadataLock","getInstanceByName","secretStore","getSecretStore","getAuthInstanceService","httpJson","removeInstance"],"mappings":";;;;;;;;;;;;;;AA2BA,aAAe,OAAO,EAAE,IAAA,EAAM,IAAA,EAAK,KAAyB;AAC1D,EAAA,MAAM;AAAA,IACJ,KAAA,EAAO,EAAE,QAAA,EAAU,YAAA;AAAa,GAClC,GAAIA,SAAA;AAAA,IACF;AAAA,MACE,IAAA,EAAM,IAAA;AAAA,MACN,KAAA,EAAO;AAAA,QACL,QAAA,EAAU;AAAA,UACR,IAAA,EAAM,MAAA;AAAA,UACN,WAAA,EAAa;AAAA;AACf;AACF,KACF;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,MAAM,EAAE,IAAA,EAAM,YAAA,EAAa,GAAI,MAAMC,oBAAa,YAAY,CAAA;AAE9D,EAAA,MAAMC,yBAAiB,YAAY;AACjC,IAAA,MAAM,QAAA,GAAW,MAAMC,yBAAA,CAAkB,YAAY,CAAA;AACrD,IAAA,MAAMC,aAAA,GAAc,MAAMC,0BAAA,EAAe;AACzC,IAAA,MAAM,OAAA,GAAUC,uCAAuB,YAAY,CAAA;AACnD,IAAA,MAAM,eAAgB,MAAMF,aAAA,CAAY,GAAA,CAAI,OAAA,EAAS,cAAc,CAAA,IAAM,EAAA;AAEzE,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,IAAI;AACF,QAAA,MAAM,WAAA,GAAc,IAAI,GAAA,CAAI,WAAA,EAAa,QAAA,CAAS,OAAO,CAAA,CACtD,QAAA,EAAS,CACT,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AACpB,QAAA,MAAMG,aAAA,CAAS,CAAA,EAAG,WAAW,CAAA,UAAA,CAAA,EAAc;AAAA,UACzC,MAAA,EAAQ,MAAA;AAAA,UACR,IAAA,EAAM;AAAA,YACJ,KAAA,EAAO,YAAA;AAAA,YACP,eAAA,EAAiB;AAAA,WACnB;AAAA,UACA,MAAA,EAAQ,WAAA,CAAY,OAAA,CAAQ,GAAM;AAAA,SACnC,CAAA;AAAA,MACH,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AAEA,IAAA,MAAMH,aAAA,CAAY,MAAA,CAAO,OAAA,EAAS,aAAa,CAAA;AAC/C,IAAA,MAAMA,aAAA,CAAY,MAAA,CAAO,OAAA,EAAS,cAAc,CAAA;AAChD,IAAA,MAAMI,sBAAA,CAAe,SAAS,IAAI,CAAA;AAAA,EACpC,CAAC,CAAA;AAED,EAAA,OAAA,CAAQ,MAAA,CAAO,MAAM,cAAc,CAAA;AACrC,CAAA;;;;"}
@@ -3,9 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var cleye = require('cleye');
6
- var auth = require('../lib/auth.cjs.js');
7
- var storage = require('../lib/storage.cjs.js');
8
- var secretStore = require('../lib/secretStore.cjs.js');
6
+ var cliNode = require('@backstage/cli-node');
9
7
 
10
8
  var printToken = async ({ args, info }) => {
11
9
  const {
@@ -23,16 +21,8 @@ var printToken = async ({ args, info }) => {
23
21
  void 0,
24
22
  args
25
23
  );
26
- let instance = await storage.getSelectedInstance(instanceFlag);
27
- if (auth.accessTokenNeedsRefresh(instance)) {
28
- instance = await auth.refreshAccessToken(instance.name);
29
- }
30
- const secretStore$1 = await secretStore.getSecretStore();
31
- const service = `backstage-cli:auth-instance:${instance.name}`;
32
- const accessToken = await secretStore$1.get(service, "accessToken");
33
- if (!accessToken) {
34
- throw new Error('No access token found. Run "auth login" to authenticate.');
35
- }
24
+ const auth = await cliNode.CliAuth.create({ instanceName: instanceFlag });
25
+ const accessToken = await auth.getAccessToken();
36
26
  process.stdout.write(`${accessToken}
37
27
  `);
38
28
  };
@@ -1 +1 @@
1
- {"version":3,"file":"printToken.cjs.js","sources":["../../src/commands/printToken.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { cli } from 'cleye';\nimport type { CliCommandContext } from '@backstage/cli-node';\nimport { accessTokenNeedsRefresh, refreshAccessToken } from '../lib/auth';\nimport { getSelectedInstance } from '../lib/storage';\nimport { getSecretStore } from '../lib/secretStore';\n\nexport default async ({ args, info }: CliCommandContext) => {\n const {\n flags: { instance: instanceFlag },\n } = cli(\n {\n help: info,\n flags: {\n instance: {\n type: String,\n description: 'Name of the instance to use',\n },\n },\n },\n undefined,\n args,\n );\n\n let instance = await getSelectedInstance(instanceFlag);\n\n if (accessTokenNeedsRefresh(instance)) {\n instance = await refreshAccessToken(instance.name);\n }\n\n const secretStore = await getSecretStore();\n const service = `backstage-cli:auth-instance:${instance.name}`;\n const accessToken = await secretStore.get(service, 'accessToken');\n if (!accessToken) {\n throw new Error('No access token found. Run \"auth login\" to authenticate.');\n }\n\n process.stdout.write(`${accessToken}\\n`);\n};\n"],"names":["cli","getSelectedInstance","accessTokenNeedsRefresh","refreshAccessToken","secretStore","getSecretStore"],"mappings":";;;;;;;;;AAsBA,iBAAe,OAAO,EAAE,IAAA,EAAM,IAAA,EAAK,KAAyB;AAC1D,EAAA,MAAM;AAAA,IACJ,KAAA,EAAO,EAAE,QAAA,EAAU,YAAA;AAAa,GAClC,GAAIA,SAAA;AAAA,IACF;AAAA,MACE,IAAA,EAAM,IAAA;AAAA,MACN,KAAA,EAAO;AAAA,QACL,QAAA,EAAU;AAAA,UACR,IAAA,EAAM,MAAA;AAAA,UACN,WAAA,EAAa;AAAA;AACf;AACF,KACF;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,IAAI,QAAA,GAAW,MAAMC,2BAAA,CAAoB,YAAY,CAAA;AAErD,EAAA,IAAIC,4BAAA,CAAwB,QAAQ,CAAA,EAAG;AACrC,IAAA,QAAA,GAAW,MAAMC,uBAAA,CAAmB,QAAA,CAAS,IAAI,CAAA;AAAA,EACnD;AAEA,EAAA,MAAMC,aAAA,GAAc,MAAMC,0BAAA,EAAe;AACzC,EAAA,MAAM,OAAA,GAAU,CAAA,4BAAA,EAA+B,QAAA,CAAS,IAAI,CAAA,CAAA;AAC5D,EAAA,MAAM,WAAA,GAAc,MAAMD,aAAA,CAAY,GAAA,CAAI,SAAS,aAAa,CAAA;AAChE,EAAA,IAAI,CAAC,WAAA,EAAa;AAChB,IAAA,MAAM,IAAI,MAAM,0DAA0D,CAAA;AAAA,EAC5E;AAEA,EAAA,OAAA,CAAQ,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,WAAW;AAAA,CAAI,CAAA;AACzC,CAAA;;;;"}
1
+ {"version":3,"file":"printToken.cjs.js","sources":["../../src/commands/printToken.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { cli } from 'cleye';\nimport { CliAuth, type CliCommandContext } from '@backstage/cli-node';\n\nexport default async ({ args, info }: CliCommandContext) => {\n const {\n flags: { instance: instanceFlag },\n } = cli(\n {\n help: info,\n flags: {\n instance: {\n type: String,\n description: 'Name of the instance to use',\n },\n },\n },\n undefined,\n args,\n );\n\n const auth = await CliAuth.create({ instanceName: instanceFlag });\n const accessToken = await auth.getAccessToken();\n\n process.stdout.write(`${accessToken}\\n`);\n};\n"],"names":["cli","CliAuth"],"mappings":";;;;;;;AAmBA,iBAAe,OAAO,EAAE,IAAA,EAAM,IAAA,EAAK,KAAyB;AAC1D,EAAA,MAAM;AAAA,IACJ,KAAA,EAAO,EAAE,QAAA,EAAU,YAAA;AAAa,GAClC,GAAIA,SAAA;AAAA,IACF;AAAA,MACE,IAAA,EAAM,IAAA;AAAA,MACN,KAAA,EAAO;AAAA,QACL,QAAA,EAAU;AAAA,UACR,IAAA,EAAM,MAAA;AAAA,UACN,WAAA,EAAa;AAAA;AACf;AACF,KACF;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,MAAM,OAAO,MAAMC,eAAA,CAAQ,OAAO,EAAE,YAAA,EAAc,cAAc,CAAA;AAChE,EAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,cAAA,EAAe;AAE9C,EAAA,OAAA,CAAQ,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,WAAW;AAAA,CAAI,CAAA;AACzC,CAAA;;;;"}
@@ -3,10 +3,8 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var cleye = require('cleye');
6
+ var cliNode = require('@backstage/cli-node');
6
7
  var http = require('../lib/http.cjs.js');
7
- var storage = require('../lib/storage.cjs.js');
8
- var auth = require('../lib/auth.cjs.js');
9
- var secretStore = require('../lib/secretStore.cjs.js');
10
8
 
11
9
  var show = async ({ args, info }) => {
12
10
  const {
@@ -24,18 +22,9 @@ var show = async ({ args, info }) => {
24
22
  void 0,
25
23
  args
26
24
  );
27
- let instance = await storage.getSelectedInstance(instanceFlag);
28
- if (auth.accessTokenNeedsRefresh(instance)) {
29
- process.stdout.write("Refreshing access token...\n");
30
- instance = await auth.refreshAccessToken(instance.name);
31
- }
32
- const authBase = new URL("/api/auth", instance.baseUrl).toString().replace(/\/$/, "");
33
- const secretStore$1 = await secretStore.getSecretStore();
34
- const service = `backstage-cli:auth-instance:${instance.name}`;
35
- const accessToken = await secretStore$1.get(service, "accessToken");
36
- if (!accessToken) {
37
- throw new Error('No access token found. Run "auth login" to authenticate.');
38
- }
25
+ const auth = await cliNode.CliAuth.create({ instanceName: instanceFlag });
26
+ const accessToken = await auth.getAccessToken();
27
+ const authBase = new URL("/api/auth", auth.getBaseUrl()).toString().replace(/\/$/, "");
39
28
  const userinfo = await http.httpJson(
40
29
  `${authBase}/v1/userinfo`,
41
30
  {
@@ -1 +1 @@
1
- {"version":3,"file":"show.cjs.js","sources":["../../src/commands/show.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { cli } from 'cleye';\nimport type { CliCommandContext } from '@backstage/cli-node';\nimport { httpJson } from '../lib/http';\nimport { getSelectedInstance } from '../lib/storage';\nimport { accessTokenNeedsRefresh, refreshAccessToken } from '../lib/auth';\nimport { getSecretStore } from '../lib/secretStore';\n\nexport default async ({ args, info }: CliCommandContext) => {\n const {\n flags: { instance: instanceFlag },\n } = cli(\n {\n help: info,\n flags: {\n instance: {\n type: String,\n description: 'Name of the instance to show',\n },\n },\n },\n undefined,\n args,\n );\n\n let instance = await getSelectedInstance(instanceFlag);\n\n if (accessTokenNeedsRefresh(instance)) {\n process.stdout.write('Refreshing access token...\\n');\n instance = await refreshAccessToken(instance.name);\n }\n const authBase = new URL('/api/auth', instance.baseUrl)\n .toString()\n .replace(/\\/$/, '');\n\n const secretStore = await getSecretStore();\n const service = `backstage-cli:auth-instance:${instance.name}`;\n const accessToken = await secretStore.get(service, 'accessToken');\n if (!accessToken) {\n throw new Error('No access token found. Run \"auth login\" to authenticate.');\n }\n\n const userinfo = await httpJson<{ claims: { sub: string; ent: string[] } }>(\n `${authBase}/v1/userinfo`,\n {\n headers: { Authorization: `Bearer ${accessToken}` },\n signal: AbortSignal.timeout(30_000),\n },\n );\n\n process.stdout.write(`User: ${userinfo.claims.sub}\\n`);\n process.stdout.write(`\\n`);\n process.stdout.write(`Ownership:\\n`);\n for (const ent of userinfo.claims.ent ?? []) {\n process.stdout.write(` - ${ent}\\n`);\n }\n};\n"],"names":["cli","getSelectedInstance","accessTokenNeedsRefresh","refreshAccessToken","secretStore","getSecretStore","httpJson"],"mappings":";;;;;;;;;;AAuBA,WAAe,OAAO,EAAE,IAAA,EAAM,IAAA,EAAK,KAAyB;AAC1D,EAAA,MAAM;AAAA,IACJ,KAAA,EAAO,EAAE,QAAA,EAAU,YAAA;AAAa,GAClC,GAAIA,SAAA;AAAA,IACF;AAAA,MACE,IAAA,EAAM,IAAA;AAAA,MACN,KAAA,EAAO;AAAA,QACL,QAAA,EAAU;AAAA,UACR,IAAA,EAAM,MAAA;AAAA,UACN,WAAA,EAAa;AAAA;AACf;AACF,KACF;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,IAAI,QAAA,GAAW,MAAMC,2BAAA,CAAoB,YAAY,CAAA;AAErD,EAAA,IAAIC,4BAAA,CAAwB,QAAQ,CAAA,EAAG;AACrC,IAAA,OAAA,CAAQ,MAAA,CAAO,MAAM,8BAA8B,CAAA;AACnD,IAAA,QAAA,GAAW,MAAMC,uBAAA,CAAmB,QAAA,CAAS,IAAI,CAAA;AAAA,EACnD;AACA,EAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,WAAA,EAAa,QAAA,CAAS,OAAO,CAAA,CACnD,QAAA,EAAS,CACT,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AAEpB,EAAA,MAAMC,aAAA,GAAc,MAAMC,0BAAA,EAAe;AACzC,EAAA,MAAM,OAAA,GAAU,CAAA,4BAAA,EAA+B,QAAA,CAAS,IAAI,CAAA,CAAA;AAC5D,EAAA,MAAM,WAAA,GAAc,MAAMD,aAAA,CAAY,GAAA,CAAI,SAAS,aAAa,CAAA;AAChE,EAAA,IAAI,CAAC,WAAA,EAAa;AAChB,IAAA,MAAM,IAAI,MAAM,0DAA0D,CAAA;AAAA,EAC5E;AAEA,EAAA,MAAM,WAAW,MAAME,aAAA;AAAA,IACrB,GAAG,QAAQ,CAAA,YAAA,CAAA;AAAA,IACX;AAAA,MACE,OAAA,EAAS,EAAE,aAAA,EAAe,CAAA,OAAA,EAAU,WAAW,CAAA,CAAA,EAAG;AAAA,MAClD,MAAA,EAAQ,WAAA,CAAY,OAAA,CAAQ,GAAM;AAAA;AACpC,GACF;AAEA,EAAA,OAAA,CAAQ,MAAA,CAAO,KAAA,CAAM,CAAA,MAAA,EAAS,QAAA,CAAS,OAAO,GAAG;AAAA,CAAI,CAAA;AACrD,EAAA,OAAA,CAAQ,OAAO,KAAA,CAAM;AAAA,CAAI,CAAA;AACzB,EAAA,OAAA,CAAQ,OAAO,KAAA,CAAM,CAAA;AAAA,CAAc,CAAA;AACnC,EAAA,KAAA,MAAW,GAAA,IAAO,QAAA,CAAS,MAAA,CAAO,GAAA,IAAO,EAAC,EAAG;AAC3C,IAAA,OAAA,CAAQ,MAAA,CAAO,KAAA,CAAM,CAAA,IAAA,EAAO,GAAG;AAAA,CAAI,CAAA;AAAA,EACrC;AACF,CAAA;;;;"}
1
+ {"version":3,"file":"show.cjs.js","sources":["../../src/commands/show.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { cli } from 'cleye';\nimport { CliAuth, type CliCommandContext } from '@backstage/cli-node';\nimport { httpJson } from '../lib/http';\n\nexport default async ({ args, info }: CliCommandContext) => {\n const {\n flags: { instance: instanceFlag },\n } = cli(\n {\n help: info,\n flags: {\n instance: {\n type: String,\n description: 'Name of the instance to show',\n },\n },\n },\n undefined,\n args,\n );\n\n const auth = await CliAuth.create({ instanceName: instanceFlag });\n const accessToken = await auth.getAccessToken();\n\n const authBase = new URL('/api/auth', auth.getBaseUrl())\n .toString()\n .replace(/\\/$/, '');\n\n const userinfo = await httpJson<{ claims: { sub: string; ent: string[] } }>(\n `${authBase}/v1/userinfo`,\n {\n headers: { Authorization: `Bearer ${accessToken}` },\n signal: AbortSignal.timeout(30_000),\n },\n );\n\n process.stdout.write(`User: ${userinfo.claims.sub}\\n`);\n process.stdout.write(`\\n`);\n process.stdout.write(`Ownership:\\n`);\n for (const ent of userinfo.claims.ent ?? []) {\n process.stdout.write(` - ${ent}\\n`);\n }\n};\n"],"names":["cli","CliAuth","httpJson"],"mappings":";;;;;;;;AAoBA,WAAe,OAAO,EAAE,IAAA,EAAM,IAAA,EAAK,KAAyB;AAC1D,EAAA,MAAM;AAAA,IACJ,KAAA,EAAO,EAAE,QAAA,EAAU,YAAA;AAAa,GAClC,GAAIA,SAAA;AAAA,IACF;AAAA,MACE,IAAA,EAAM,IAAA;AAAA,MACN,KAAA,EAAO;AAAA,QACL,QAAA,EAAU;AAAA,UACR,IAAA,EAAM,MAAA;AAAA,UACN,WAAA,EAAa;AAAA;AACf;AACF,KACF;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,MAAM,OAAO,MAAMC,eAAA,CAAQ,OAAO,EAAE,YAAA,EAAc,cAAc,CAAA;AAChE,EAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,cAAA,EAAe;AAE9C,EAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,WAAA,EAAa,IAAA,CAAK,UAAA,EAAY,CAAA,CACpD,QAAA,EAAS,CACT,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AAEpB,EAAA,MAAM,WAAW,MAAMC,aAAA;AAAA,IACrB,GAAG,QAAQ,CAAA,YAAA,CAAA;AAAA,IACX;AAAA,MACE,OAAA,EAAS,EAAE,aAAA,EAAe,CAAA,OAAA,EAAU,WAAW,CAAA,CAAA,EAAG;AAAA,MAClD,MAAA,EAAQ,WAAA,CAAY,OAAA,CAAQ,GAAM;AAAA;AACpC,GACF;AAEA,EAAA,OAAA,CAAQ,MAAA,CAAO,KAAA,CAAM,CAAA,MAAA,EAAS,QAAA,CAAS,OAAO,GAAG;AAAA,CAAI,CAAA;AACrD,EAAA,OAAA,CAAQ,OAAO,KAAA,CAAM;AAAA,CAAI,CAAA;AACzB,EAAA,OAAA,CAAQ,OAAO,KAAA,CAAM,CAAA;AAAA,CAAc,CAAA;AACnC,EAAA,KAAA,MAAW,GAAA,IAAO,QAAA,CAAS,MAAA,CAAO,GAAA,IAAO,EAAC,EAAG;AAC3C,IAAA,OAAA,CAAQ,MAAA,CAAO,KAAA,CAAM,CAAA,IAAA,EAAO,GAAG;AAAA,CAAI,CAAA;AAAA,EACrC;AACF,CAAA;;;;"}
package/dist/index.cjs.js CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var cliNode = require('@backstage/cli-node');
6
- var _package = require('./package.json.cjs.js');
6
+ var _package = require('./cli-module-auth/package.json.cjs.js');
7
7
 
8
8
  var index = cliNode.createCliModule({
9
9
  packageJson: _package.default,
@@ -1,14 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var fetch = require('cross-fetch');
4
3
  var errors = require('@backstage/errors');
5
4
 
6
- function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
7
-
8
- var fetch__default = /*#__PURE__*/_interopDefaultCompat(fetch);
9
-
10
5
  async function httpJson(url, init) {
11
- const res = await fetch__default.default(url, {
6
+ const res = await fetch(url, {
12
7
  ...init,
13
8
  body: init?.body ? JSON.stringify(init.body) : void 0,
14
9
  headers: {
@@ -1 +1 @@
1
- {"version":3,"file":"http.cjs.js","sources":["../../src/lib/http.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fetch from 'cross-fetch';\nimport { ResponseError } from '@backstage/errors';\n\ntype HttpInit = {\n headers?: Record<string, string>;\n method?: string;\n body?: any;\n signal?: AbortSignal;\n};\n\nexport async function httpJson<T>(url: string, init?: HttpInit): Promise<T> {\n const res = await fetch(url, {\n ...init,\n body: init?.body ? JSON.stringify(init.body) : undefined,\n headers: {\n ...(init?.body ? { 'Content-Type': 'application/json' } : {}),\n ...init?.headers,\n },\n });\n if (!res.ok) {\n throw await ResponseError.fromResponse(res);\n }\n return (await res.json()) as T;\n}\n"],"names":["fetch","ResponseError"],"mappings":";;;;;;;;;AA0BA,eAAsB,QAAA,CAAY,KAAa,IAAA,EAA6B;AAC1E,EAAA,MAAM,GAAA,GAAM,MAAMA,sBAAA,CAAM,GAAA,EAAK;AAAA,IAC3B,GAAG,IAAA;AAAA,IACH,MAAM,IAAA,EAAM,IAAA,GAAO,KAAK,SAAA,CAAU,IAAA,CAAK,IAAI,CAAA,GAAI,MAAA;AAAA,IAC/C,OAAA,EAAS;AAAA,MACP,GAAI,IAAA,EAAM,IAAA,GAAO,EAAE,cAAA,EAAgB,kBAAA,KAAuB,EAAC;AAAA,MAC3D,GAAG,IAAA,EAAM;AAAA;AACX,GACD,CAAA;AACD,EAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,IAAA,MAAM,MAAMC,oBAAA,CAAc,YAAA,CAAa,GAAG,CAAA;AAAA,EAC5C;AACA,EAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AACzB;;;;"}
1
+ {"version":3,"file":"http.cjs.js","sources":["../../src/lib/http.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ResponseError } from '@backstage/errors';\n\nexport type HttpInit = {\n headers?: Record<string, string>;\n method?: string;\n body?: any;\n signal?: AbortSignal;\n};\n\nexport async function httpJson<T>(url: string, init?: HttpInit): Promise<T> {\n const res = await fetch(url, {\n ...init,\n body: init?.body ? JSON.stringify(init.body) : undefined,\n headers: {\n ...(init?.body ? { 'Content-Type': 'application/json' } : {}),\n ...init?.headers,\n },\n });\n if (!res.ok) {\n throw await ResponseError.fromResponse(res);\n }\n return (await res.json()) as T;\n}\n"],"names":["ResponseError"],"mappings":";;;;AAyBA,eAAsB,QAAA,CAAY,KAAa,IAAA,EAA6B;AAC1E,EAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,IAC3B,GAAG,IAAA;AAAA,IACH,MAAM,IAAA,EAAM,IAAA,GAAO,KAAK,SAAA,CAAU,IAAA,CAAK,IAAI,CAAA,GAAI,MAAA;AAAA,IAC/C,OAAA,EAAS;AAAA,MACP,GAAI,IAAA,EAAM,IAAA,GAAO,EAAE,cAAA,EAAgB,kBAAA,KAAuB,EAAC;AAAA,MAC3D,GAAG,IAAA,EAAM;AAAA;AACX,GACD,CAAA;AACD,EAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,IAAA,MAAM,MAAMA,oBAAA,CAAc,YAAA,CAAa,GAAG,CAAA;AAAA,EAC5C;AACA,EAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AACzB;;;;"}
@@ -6,7 +6,7 @@ var os = require('node:os');
6
6
  var path = require('node:path');
7
7
  var lockfile = require('proper-lockfile');
8
8
  var YAML = require('yaml');
9
- var zod = require('zod');
9
+ var v3 = require('zod/v3');
10
10
 
11
11
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
12
12
 
@@ -18,16 +18,17 @@ var YAML__default = /*#__PURE__*/_interopDefaultCompat(YAML);
18
18
 
19
19
  const METADATA_FILE = "auth-instances.yaml";
20
20
  const INSTANCE_NAME_PATTERN = /^[a-zA-Z0-9._:@-]+$/;
21
- const storedInstanceSchema = zod.z.object({
22
- name: zod.z.string().min(1).regex(INSTANCE_NAME_PATTERN, "Instance name contains invalid characters"),
23
- baseUrl: zod.z.string().url(),
24
- clientId: zod.z.string().min(1),
25
- issuedAt: zod.z.number().int().nonnegative(),
26
- accessTokenExpiresAt: zod.z.number().int().nonnegative(),
27
- selected: zod.z.boolean().optional()
21
+ const storedInstanceSchema = v3.z.object({
22
+ name: v3.z.string().min(1).regex(INSTANCE_NAME_PATTERN, "Instance name contains invalid characters"),
23
+ baseUrl: v3.z.string().url(),
24
+ clientId: v3.z.string().min(1),
25
+ issuedAt: v3.z.number().int().nonnegative(),
26
+ accessTokenExpiresAt: v3.z.number().int().nonnegative(),
27
+ selected: v3.z.boolean().optional(),
28
+ metadata: v3.z.record(v3.z.string(), v3.z.unknown()).optional()
28
29
  });
29
- const authYamlSchema = zod.z.object({
30
- instances: zod.z.array(storedInstanceSchema).default([])
30
+ const authYamlSchema = v3.z.object({
31
+ instances: v3.z.array(storedInstanceSchema).default([])
31
32
  });
32
33
  function getMetadataFilePath() {
33
34
  const root = process.env.XDG_CONFIG_HOME || (process.platform === "win32" ? process.env.APPDATA || path__default.default.join(os__default.default.homedir(), "AppData", "Roaming") : path__default.default.join(os__default.default.homedir(), ".config"));
@@ -61,9 +62,11 @@ async function writeAll(data) {
61
62
  }
62
63
  async function getAllInstances() {
63
64
  const { instances } = await readAll();
65
+ if (instances.length === 0) {
66
+ return { instances: [], selected: void 0 };
67
+ }
64
68
  const selected = instances.find((i) => i.selected) ?? instances[0];
65
69
  return {
66
- // Normalize selection prop
67
70
  instances: instances.map((i) => ({
68
71
  ...i,
69
72
  selected: i.name === selected.name
@@ -71,18 +74,6 @@ async function getAllInstances() {
71
74
  selected
72
75
  };
73
76
  }
74
- async function getSelectedInstance(instanceName) {
75
- if (instanceName) {
76
- return await getInstanceByName(instanceName);
77
- }
78
- const { selected } = await getAllInstances();
79
- if (!selected) {
80
- throw new Error(
81
- 'No instances found. Run "auth login" to authenticate first.'
82
- );
83
- }
84
- return selected;
85
- }
86
77
  async function getInstanceByName(name) {
87
78
  const { instances } = await readAll();
88
79
  const instance = instances.find((i) => i.name === name);
@@ -144,7 +135,6 @@ async function withMetadataLock(fn) {
144
135
 
145
136
  exports.getAllInstances = getAllInstances;
146
137
  exports.getInstanceByName = getInstanceByName;
147
- exports.getSelectedInstance = getSelectedInstance;
148
138
  exports.removeInstance = removeInstance;
149
139
  exports.setSelectedInstance = setSelectedInstance;
150
140
  exports.upsertInstance = upsertInstance;
@@ -1 +1 @@
1
- {"version":3,"file":"storage.cjs.js","sources":["../../src/lib/storage.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { NotFoundError } from '@backstage/errors';\nimport fs from 'fs-extra';\nimport os from 'node:os';\nimport path from 'node:path';\nimport lockfile from 'proper-lockfile';\nimport YAML from 'yaml';\nimport { z } from 'zod';\n\nconst METADATA_FILE = 'auth-instances.yaml';\n\nconst INSTANCE_NAME_PATTERN = /^[a-zA-Z0-9._:@-]+$/;\n\nconst storedInstanceSchema = z.object({\n name: z\n .string()\n .min(1)\n .regex(INSTANCE_NAME_PATTERN, 'Instance name contains invalid characters'),\n baseUrl: z.string().url(),\n clientId: z.string().min(1),\n issuedAt: z.number().int().nonnegative(),\n accessTokenExpiresAt: z.number().int().nonnegative(),\n selected: z.boolean().optional(),\n});\n\nexport type StoredInstance = z.infer<typeof storedInstanceSchema>;\n\nconst authYamlSchema = z.object({\n instances: z.array(storedInstanceSchema).default([]),\n});\n\nfunction getMetadataFilePath(): string {\n const root =\n process.env.XDG_CONFIG_HOME ||\n (process.platform === 'win32'\n ? process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming')\n : path.join(os.homedir(), '.config'));\n\n return path.join(root, 'backstage-cli', METADATA_FILE);\n}\n\nasync function readAll(): Promise<{ instances: StoredInstance[] }> {\n const file = getMetadataFilePath();\n if (!(await fs.pathExists(file))) {\n return { instances: [] };\n }\n const text = await fs.readFile(file, 'utf8');\n if (!text.trim()) {\n return { instances: [] };\n }\n try {\n const doc = YAML.parse(text);\n const parsed = authYamlSchema.safeParse(doc);\n if (parsed.success) {\n return parsed.data;\n }\n return { instances: [] };\n } catch {\n return { instances: [] };\n }\n}\n\nasync function writeAll(data: { instances: StoredInstance[] }): Promise<void> {\n const file = getMetadataFilePath();\n await fs.ensureDir(path.dirname(file));\n const yaml = YAML.stringify(authYamlSchema.parse(data), { indentSeq: false });\n await fs.writeFile(file, yaml, { encoding: 'utf8', mode: 0o600 });\n}\n\nexport async function getAllInstances(): Promise<{\n instances: StoredInstance[];\n selected: StoredInstance | undefined;\n}> {\n const { instances } = await readAll();\n const selected = instances.find(i => i.selected) ?? instances[0];\n return {\n // Normalize selection prop\n instances: instances.map(i => ({\n ...i,\n selected: i.name === selected.name,\n })),\n selected,\n };\n}\n\nexport async function getSelectedInstance(\n instanceName?: string,\n): Promise<StoredInstance> {\n if (instanceName) {\n return await getInstanceByName(instanceName);\n }\n const { selected } = await getAllInstances();\n if (!selected) {\n throw new Error(\n 'No instances found. Run \"auth login\" to authenticate first.',\n );\n }\n return selected;\n}\n\nexport async function getInstanceByName(name: string): Promise<StoredInstance> {\n const { instances } = await readAll();\n const instance = instances.find(i => i.name === name);\n if (!instance) {\n throw new NotFoundError(`Instance '${name}' not found`);\n }\n return instance;\n}\n\nexport async function upsertInstance(instance: StoredInstance): Promise<void> {\n const data = await readAll();\n const idx = data.instances.findIndex(i => i.name === instance.name);\n if (idx === -1) {\n data.instances.push(instance);\n } else {\n data.instances[idx] = instance;\n }\n await writeAll(data);\n}\n\nexport async function removeInstance(name: string): Promise<void> {\n const data = await readAll();\n const next = data.instances.filter(i => i.name !== name);\n if (next.length !== data.instances.length) {\n await writeAll({ instances: next });\n }\n}\n\nexport async function setSelectedInstance(name: string): Promise<void> {\n return withMetadataLock(async () => {\n const data = await readAll();\n let found = false;\n data.instances = data.instances.map(i => {\n if (i.name === name) {\n found = true;\n return { ...i, selected: true };\n }\n const { selected, ...rest } = i;\n return { ...rest, selected: false };\n });\n if (!found) {\n throw new Error(`Unknown instance '${name}'`);\n }\n await writeAll(data);\n });\n}\n\nexport async function withMetadataLock<T>(fn: () => Promise<T>): Promise<T> {\n const file = getMetadataFilePath();\n await fs.ensureDir(path.dirname(file));\n if (!(await fs.pathExists(file))) {\n await fs.writeFile(file, '', { encoding: 'utf8', mode: 0o600 });\n }\n const release = await lockfile.lock(file, {\n retries: { retries: 5, factor: 1.5, minTimeout: 100, maxTimeout: 1000 },\n });\n try {\n return await fn();\n } finally {\n await release();\n }\n}\n"],"names":["z","path","os","fs","YAML","NotFoundError","lockfile"],"mappings":"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"}
1
+ {"version":3,"file":"storage.cjs.js","sources":["../../src/lib/storage.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { NotFoundError } from '@backstage/errors';\nimport fs from 'fs-extra';\nimport os from 'node:os';\nimport path from 'node:path';\nimport lockfile from 'proper-lockfile';\nimport YAML from 'yaml';\nimport { z } from 'zod/v3';\n\nexport type StoredInstance = {\n name: string;\n baseUrl: string;\n clientId: string;\n issuedAt: number;\n accessTokenExpiresAt: number;\n selected?: boolean;\n metadata?: Record<string, unknown>;\n};\n\nconst METADATA_FILE = 'auth-instances.yaml';\n\nconst INSTANCE_NAME_PATTERN = /^[a-zA-Z0-9._:@-]+$/;\n\nconst storedInstanceSchema = z.object({\n name: z\n .string()\n .min(1)\n .regex(INSTANCE_NAME_PATTERN, 'Instance name contains invalid characters'),\n baseUrl: z.string().url(),\n clientId: z.string().min(1),\n issuedAt: z.number().int().nonnegative(),\n accessTokenExpiresAt: z.number().int().nonnegative(),\n selected: z.boolean().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n});\n\nconst authYamlSchema = z.object({\n instances: z.array(storedInstanceSchema).default([]),\n});\n\nfunction getMetadataFilePath(): string {\n const root =\n process.env.XDG_CONFIG_HOME ||\n (process.platform === 'win32'\n ? process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming')\n : path.join(os.homedir(), '.config'));\n\n return path.join(root, 'backstage-cli', METADATA_FILE);\n}\n\nasync function readAll(): Promise<{ instances: StoredInstance[] }> {\n const file = getMetadataFilePath();\n if (!(await fs.pathExists(file))) {\n return { instances: [] };\n }\n const text = await fs.readFile(file, 'utf8');\n if (!text.trim()) {\n return { instances: [] };\n }\n try {\n const doc = YAML.parse(text);\n const parsed = authYamlSchema.safeParse(doc);\n if (parsed.success) {\n return parsed.data;\n }\n return { instances: [] };\n } catch {\n return { instances: [] };\n }\n}\n\nasync function writeAll(data: { instances: StoredInstance[] }): Promise<void> {\n const file = getMetadataFilePath();\n await fs.ensureDir(path.dirname(file));\n const yaml = YAML.stringify(authYamlSchema.parse(data), { indentSeq: false });\n await fs.writeFile(file, yaml, { encoding: 'utf8', mode: 0o600 });\n}\n\nexport async function getAllInstances(): Promise<{\n instances: StoredInstance[];\n selected: StoredInstance | undefined;\n}> {\n const { instances } = await readAll();\n if (instances.length === 0) {\n return { instances: [], selected: undefined };\n }\n const selected = instances.find(i => i.selected) ?? instances[0];\n return {\n instances: instances.map(i => ({\n ...i,\n selected: i.name === selected.name,\n })),\n selected,\n };\n}\n\nexport async function getSelectedInstance(\n instanceName?: string,\n): Promise<StoredInstance> {\n if (instanceName) {\n return await getInstanceByName(instanceName);\n }\n const { selected } = await getAllInstances();\n if (!selected) {\n throw new Error(\n 'No instances found. Run \"auth login\" to authenticate first.',\n );\n }\n return selected;\n}\n\nexport async function getInstanceByName(name: string): Promise<StoredInstance> {\n const { instances } = await readAll();\n const instance = instances.find(i => i.name === name);\n if (!instance) {\n throw new NotFoundError(`Instance '${name}' not found`);\n }\n return instance;\n}\n\nexport async function upsertInstance(instance: StoredInstance): Promise<void> {\n const data = await readAll();\n const idx = data.instances.findIndex(i => i.name === instance.name);\n if (idx === -1) {\n data.instances.push(instance);\n } else {\n data.instances[idx] = instance;\n }\n await writeAll(data);\n}\n\nexport async function removeInstance(name: string): Promise<void> {\n const data = await readAll();\n const next = data.instances.filter(i => i.name !== name);\n if (next.length !== data.instances.length) {\n await writeAll({ instances: next });\n }\n}\n\nexport async function setSelectedInstance(name: string): Promise<void> {\n return withMetadataLock(async () => {\n const data = await readAll();\n let found = false;\n data.instances = data.instances.map(i => {\n if (i.name === name) {\n found = true;\n return { ...i, selected: true };\n }\n const { selected, ...rest } = i;\n return { ...rest, selected: false };\n });\n if (!found) {\n throw new Error(`Unknown instance '${name}'`);\n }\n await writeAll(data);\n });\n}\n\nexport async function getInstanceMetadata(\n instanceName: string,\n key: string,\n): Promise<unknown> {\n const instance = await getInstanceByName(instanceName);\n return instance.metadata?.[key];\n}\n\nexport async function updateInstanceMetadata(\n instanceName: string,\n key: string,\n value: unknown,\n): Promise<void> {\n return withMetadataLock(async () => {\n const data = await readAll();\n const idx = data.instances.findIndex(i => i.name === instanceName);\n if (idx === -1) {\n throw new NotFoundError(`Instance '${instanceName}' not found`);\n }\n data.instances[idx] = {\n ...data.instances[idx],\n metadata: { ...data.instances[idx].metadata, [key]: value },\n };\n await writeAll(data);\n });\n}\n\nexport async function withMetadataLock<T>(fn: () => Promise<T>): Promise<T> {\n const file = getMetadataFilePath();\n await fs.ensureDir(path.dirname(file));\n if (!(await fs.pathExists(file))) {\n await fs.writeFile(file, '', { encoding: 'utf8', mode: 0o600 });\n }\n const release = await lockfile.lock(file, {\n retries: { retries: 5, factor: 1.5, minTimeout: 100, maxTimeout: 1000 },\n });\n try {\n return await fn();\n } finally {\n await release();\n }\n}\n"],"names":["z","path","os","fs","YAML","NotFoundError","lockfile"],"mappings":"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"}
@@ -0,0 +1,105 @@
1
+ 'use strict';
2
+
3
+ class OpaqueType {
4
+ /**
5
+ * Creates a new opaque type.
6
+ *
7
+ * @param options.type The type identifier of the opaque type
8
+ * @param options.versions The available versions of the opaque type
9
+ * @returns A new opaque type helper
10
+ */
11
+ static create(options) {
12
+ return new OpaqueType(options.type, new Set(options.versions));
13
+ }
14
+ #type;
15
+ #versions;
16
+ constructor(type, versions) {
17
+ this.#type = type;
18
+ this.#versions = versions;
19
+ }
20
+ /**
21
+ * The internal version of the opaque type, used like this: `typeof MyOpaqueType.TPublic`
22
+ *
23
+ * @remarks
24
+ *
25
+ * This property is only useful for type checking, its runtime value is `undefined`.
26
+ */
27
+ TPublic = void 0;
28
+ /**
29
+ * The internal version of the opaque type, used like this: `typeof MyOpaqueType.TInternal`
30
+ *
31
+ * @remarks
32
+ *
33
+ * This property is only useful for type checking, its runtime value is `undefined`.
34
+ */
35
+ TInternal = void 0;
36
+ /**
37
+ * @param value Input value expected to be an instance of this opaque type
38
+ * @returns True if the value matches this opaque type
39
+ */
40
+ isType = (value) => {
41
+ return this.#isThisInternalType(value);
42
+ };
43
+ /**
44
+ * @param value Input value expected to be an instance of this opaque type
45
+ * @throws If the value is not an instance of this opaque type or is of an unsupported version
46
+ * @returns The internal version of the opaque type
47
+ */
48
+ toInternal = (value) => {
49
+ if (!this.#isThisInternalType(value)) {
50
+ throw new TypeError(
51
+ `Invalid opaque type, expected '${this.#type}', but got '${this.#stringifyUnknown(value)}'`
52
+ );
53
+ }
54
+ if (!this.#versions.has(value.version)) {
55
+ const versions = Array.from(this.#versions).map(this.#stringifyVersion);
56
+ if (versions.length > 1) {
57
+ versions[versions.length - 1] = `or ${versions[versions.length - 1]}`;
58
+ }
59
+ const expected = versions.length > 2 ? versions.join(", ") : versions.join(" ");
60
+ throw new TypeError(
61
+ `Invalid opaque type instance, got version ${this.#stringifyVersion(
62
+ value.version
63
+ )}, expected ${expected}`
64
+ );
65
+ }
66
+ return value;
67
+ };
68
+ /**
69
+ * Creates an instance of the opaque type, returning the public type.
70
+ *
71
+ * @param version The version of the instance to create
72
+ * @param value The remaining public and internal properties of the instance
73
+ * @returns An instance of the opaque type
74
+ */
75
+ createInstance(version, props) {
76
+ return Object.assign(props, {
77
+ $$type: this.#type,
78
+ ...version && { version }
79
+ });
80
+ }
81
+ #isThisInternalType(value) {
82
+ if (value === null || typeof value !== "object") {
83
+ return false;
84
+ }
85
+ return value.$$type === this.#type;
86
+ }
87
+ #stringifyUnknown(value) {
88
+ if (typeof value !== "object") {
89
+ return `<${typeof value}>`;
90
+ }
91
+ if (value === null) {
92
+ return "<null>";
93
+ }
94
+ if ("$$type" in value) {
95
+ return String(value.$$type);
96
+ }
97
+ return String(value);
98
+ }
99
+ #stringifyVersion = (version) => {
100
+ return version ? `'${version}'` : "undefined";
101
+ };
102
+ }
103
+
104
+ exports.OpaqueType = OpaqueType;
105
+ //# sourceMappingURL=OpaqueType.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OpaqueType.cjs.js","sources":["../../../../opaque-internal/src/OpaqueType.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// TODO(Rugvip): This lives here temporarily, but should be moved to a more\n// central location. It's useful for backend packages too so we'll need to have\n// it in a common package, but it might also be that we want to make it\n// available publicly too in which case it would make sense to have this be part\n// of @backstage/version-bridge. The problem with exporting it from there is\n// that it would need to be very stable at that point, so it might be a bit\n// early to put it there already.\n\n/**\n * A helper for working with opaque types.\n */\nexport class OpaqueType<\n T extends {\n public: { $$type: string };\n versions: { version: string | undefined };\n },\n> {\n /**\n * Creates a new opaque type.\n *\n * @param options.type The type identifier of the opaque type\n * @param options.versions The available versions of the opaque type\n * @returns A new opaque type helper\n */\n static create<\n T extends {\n public: { $$type: string };\n versions: { version: string | undefined };\n },\n >(options: {\n type: T['public']['$$type'];\n versions: Array<T['versions']['version']>;\n }) {\n return new OpaqueType<T>(options.type, new Set(options.versions));\n }\n\n #type: string;\n #versions: Set<string | undefined>;\n\n private constructor(type: string, versions: Set<string | undefined>) {\n this.#type = type;\n this.#versions = versions;\n }\n\n /**\n * The internal version of the opaque type, used like this: `typeof MyOpaqueType.TPublic`\n *\n * @remarks\n *\n * This property is only useful for type checking, its runtime value is `undefined`.\n */\n TPublic: T['public'] = undefined as any;\n\n /**\n * The internal version of the opaque type, used like this: `typeof MyOpaqueType.TInternal`\n *\n * @remarks\n *\n * This property is only useful for type checking, its runtime value is `undefined`.\n */\n TInternal: T['public'] & T['versions'] = undefined as any;\n\n /**\n * @param value Input value expected to be an instance of this opaque type\n * @returns True if the value matches this opaque type\n */\n isType = (value: unknown): value is T['public'] => {\n return this.#isThisInternalType(value);\n };\n\n /**\n * @param value Input value expected to be an instance of this opaque type\n * @throws If the value is not an instance of this opaque type or is of an unsupported version\n * @returns The internal version of the opaque type\n */\n toInternal = (value: unknown): T['public'] & T['versions'] => {\n if (!this.#isThisInternalType(value)) {\n throw new TypeError(\n `Invalid opaque type, expected '${\n this.#type\n }', but got '${this.#stringifyUnknown(value)}'`,\n );\n }\n\n if (!this.#versions.has(value.version)) {\n const versions = Array.from(this.#versions).map(this.#stringifyVersion);\n if (versions.length > 1) {\n versions[versions.length - 1] = `or ${versions[versions.length - 1]}`;\n }\n const expected =\n versions.length > 2 ? versions.join(', ') : versions.join(' ');\n throw new TypeError(\n `Invalid opaque type instance, got version ${this.#stringifyVersion(\n value.version,\n )}, expected ${expected}`,\n );\n }\n\n return value;\n };\n\n /**\n * Creates an instance of the opaque type, returning the public type.\n *\n * @param version The version of the instance to create\n * @param value The remaining public and internal properties of the instance\n * @returns An instance of the opaque type\n */\n createInstance<\n TVersion extends T['versions']['version'],\n TPublic extends T['public'],\n >(\n version: TVersion,\n props: Omit<T['public'], '$$type'> &\n (T['versions'] extends infer UVersion\n ? UVersion extends { version: TVersion }\n ? Omit<UVersion, 'version'>\n : never\n : never) &\n Object, // & Object to allow for object properties too, e.g. toString()\n ): TPublic {\n return Object.assign(props as object, {\n $$type: this.#type,\n ...(version && { version }),\n }) as unknown as TPublic;\n }\n\n #isThisInternalType(value: unknown): value is T['public'] & T['versions'] {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n return (value as T['public']).$$type === this.#type;\n }\n\n #stringifyUnknown(value: unknown) {\n if (typeof value !== 'object') {\n return `<${typeof value}>`;\n }\n if (value === null) {\n return '<null>';\n }\n if ('$$type' in value) {\n return String(value.$$type);\n }\n return String(value);\n }\n\n #stringifyVersion = (version: string | undefined) => {\n return version ? `'${version}'` : 'undefined';\n };\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/cli-module-auth",
3
- "version": "0.0.0-nightly-20260317031259",
3
+ "version": "0.1.0",
4
4
  "description": "CLI module for Backstage CLI",
5
5
  "backstage": {
6
6
  "role": "cli-module"
@@ -19,6 +19,7 @@
19
19
  "license": "Apache-2.0",
20
20
  "main": "dist/index.cjs.js",
21
21
  "types": "dist/index.d.ts",
22
+ "bin": "bin/backstage-cli-module-auth",
22
23
  "files": [
23
24
  "dist",
24
25
  "bin"
@@ -32,10 +33,9 @@
32
33
  "test": "backstage-cli package test"
33
34
  },
34
35
  "dependencies": {
35
- "@backstage/cli-node": "0.0.0-nightly-20260317031259",
36
- "@backstage/errors": "1.2.7",
36
+ "@backstage/cli-node": "^0.3.0",
37
+ "@backstage/errors": "^1.2.7",
37
38
  "cleye": "^2.3.0",
38
- "cross-fetch": "^4.0.0",
39
39
  "fs-extra": "^11.2.0",
40
40
  "glob": "^7.1.7",
41
41
  "inquirer": "^8.2.0",
@@ -44,15 +44,14 @@
44
44
  "zod": "^3.25.76"
45
45
  },
46
46
  "devDependencies": {
47
- "@backstage/backend-test-utils": "0.0.0-nightly-20260317031259",
48
- "@backstage/cli": "0.0.0-nightly-20260317031259",
47
+ "@backstage/backend-test-utils": "^1.11.1",
48
+ "@backstage/cli": "^0.36.0",
49
49
  "@types/fs-extra": "^11.0.0",
50
50
  "@types/proper-lockfile": "^4"
51
51
  },
52
52
  "optionalDependencies": {
53
53
  "keytar": "^7.9.0"
54
54
  },
55
- "bin": "bin/backstage-cli-module-auth",
56
55
  "typesVersions": {
57
56
  "*": {
58
57
  "package.json": [
@@ -1,60 +0,0 @@
1
- 'use strict';
2
-
3
- var zod = require('zod');
4
- var storage = require('./storage.cjs.js');
5
- var secretStore = require('./secretStore.cjs.js');
6
- var http = require('./http.cjs.js');
7
-
8
- const TokenResponseSchema = zod.z.object({
9
- access_token: zod.z.string().min(1),
10
- token_type: zod.z.string().min(1),
11
- expires_in: zod.z.number().positive().finite(),
12
- refresh_token: zod.z.string().min(1).optional()
13
- });
14
- function accessTokenNeedsRefresh(instance) {
15
- return instance.accessTokenExpiresAt <= Date.now() + 2 * 6e4;
16
- }
17
- async function refreshAccessToken(instanceName) {
18
- const secretStore$1 = await secretStore.getSecretStore();
19
- return storage.withMetadataLock(async () => {
20
- const instance = await storage.getInstanceByName(instanceName);
21
- const service = `backstage-cli:auth-instance:${instanceName}`;
22
- const refreshToken = await secretStore$1.get(service, "refreshToken") ?? "";
23
- if (!refreshToken) {
24
- throw new Error(
25
- "Access token is expired and no refresh token is available"
26
- );
27
- }
28
- const response = await http.httpJson(
29
- `${instance.baseUrl}/api/auth/v1/token`,
30
- {
31
- method: "POST",
32
- body: {
33
- grant_type: "refresh_token",
34
- refresh_token: refreshToken
35
- },
36
- signal: AbortSignal.timeout(3e4)
37
- }
38
- );
39
- const parsed = TokenResponseSchema.safeParse(response);
40
- if (!parsed.success) {
41
- throw new Error(`Invalid token response: ${parsed.error.message}`);
42
- }
43
- const token = parsed.data;
44
- await secretStore$1.set(service, "accessToken", token.access_token);
45
- if (token.refresh_token) {
46
- await secretStore$1.set(service, "refreshToken", token.refresh_token);
47
- }
48
- const newInstance = {
49
- ...instance,
50
- issuedAt: Date.now(),
51
- accessTokenExpiresAt: Date.now() + token.expires_in * 1e3
52
- };
53
- await storage.upsertInstance(newInstance);
54
- return newInstance;
55
- });
56
- }
57
-
58
- exports.accessTokenNeedsRefresh = accessTokenNeedsRefresh;
59
- exports.refreshAccessToken = refreshAccessToken;
60
- //# sourceMappingURL=auth.cjs.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth.cjs.js","sources":["../../src/lib/auth.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { z } from 'zod';\nimport {\n StoredInstance,\n upsertInstance,\n withMetadataLock,\n getInstanceByName,\n} from './storage';\nimport { getSecretStore } from './secretStore';\nimport { httpJson } from './http';\n\nconst TokenResponseSchema = z.object({\n access_token: z.string().min(1),\n token_type: z.string().min(1),\n expires_in: z.number().positive().finite(),\n refresh_token: z.string().min(1).optional(),\n});\n\nexport function accessTokenNeedsRefresh(instance: StoredInstance): boolean {\n return instance.accessTokenExpiresAt <= Date.now() + 2 * 60_000; // 2 minutes before expiration\n}\n\nexport async function refreshAccessToken(\n instanceName: string,\n): Promise<StoredInstance> {\n const secretStore = await getSecretStore();\n\n return withMetadataLock(async () => {\n const instance = await getInstanceByName(instanceName);\n\n const service = `backstage-cli:auth-instance:${instanceName}`;\n const refreshToken = (await secretStore.get(service, 'refreshToken')) ?? '';\n if (!refreshToken) {\n throw new Error(\n 'Access token is expired and no refresh token is available',\n );\n }\n\n const response = await httpJson<unknown>(\n `${instance.baseUrl}/api/auth/v1/token`,\n {\n method: 'POST',\n body: {\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n },\n signal: AbortSignal.timeout(30_000),\n },\n );\n\n const parsed = TokenResponseSchema.safeParse(response);\n if (!parsed.success) {\n throw new Error(`Invalid token response: ${parsed.error.message}`);\n }\n const token = parsed.data;\n\n await secretStore.set(service, 'accessToken', token.access_token);\n if (token.refresh_token) {\n await secretStore.set(service, 'refreshToken', token.refresh_token);\n }\n const newInstance = {\n ...instance,\n issuedAt: Date.now(),\n accessTokenExpiresAt: Date.now() + token.expires_in * 1000,\n };\n await upsertInstance(newInstance);\n return newInstance;\n });\n}\n"],"names":["z","secretStore","getSecretStore","withMetadataLock","getInstanceByName","httpJson","upsertInstance"],"mappings":";;;;;;;AA0BA,MAAM,mBAAA,GAAsBA,MAAE,MAAA,CAAO;AAAA,EACnC,YAAA,EAAcA,KAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,EAC9B,UAAA,EAAYA,KAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,EAC5B,YAAYA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,GAAW,MAAA,EAAO;AAAA,EACzC,eAAeA,KAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA;AACnC,CAAC,CAAA;AAEM,SAAS,wBAAwB,QAAA,EAAmC;AACzE,EAAA,OAAO,QAAA,CAAS,oBAAA,IAAwB,IAAA,CAAK,GAAA,KAAQ,CAAA,GAAI,GAAA;AAC3D;AAEA,eAAsB,mBACpB,YAAA,EACyB;AACzB,EAAA,MAAMC,aAAA,GAAc,MAAMC,0BAAA,EAAe;AAEzC,EAAA,OAAOC,yBAAiB,YAAY;AAClC,IAAA,MAAM,QAAA,GAAW,MAAMC,yBAAA,CAAkB,YAAY,CAAA;AAErD,IAAA,MAAM,OAAA,GAAU,+BAA+B,YAAY,CAAA,CAAA;AAC3D,IAAA,MAAM,eAAgB,MAAMH,aAAA,CAAY,GAAA,CAAI,OAAA,EAAS,cAAc,CAAA,IAAM,EAAA;AACzE,IAAA,IAAI,CAAC,YAAA,EAAc;AACjB,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AAEA,IAAA,MAAM,WAAW,MAAMI,aAAA;AAAA,MACrB,CAAA,EAAG,SAAS,OAAO,CAAA,kBAAA,CAAA;AAAA,MACnB;AAAA,QACE,MAAA,EAAQ,MAAA;AAAA,QACR,IAAA,EAAM;AAAA,UACJ,UAAA,EAAY,eAAA;AAAA,UACZ,aAAA,EAAe;AAAA,SACjB;AAAA,QACA,MAAA,EAAQ,WAAA,CAAY,OAAA,CAAQ,GAAM;AAAA;AACpC,KACF;AAEA,IAAA,MAAM,MAAA,GAAS,mBAAA,CAAoB,SAAA,CAAU,QAAQ,CAAA;AACrD,IAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,MAAA,CAAO,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AAAA,IACnE;AACA,IAAA,MAAM,QAAQ,MAAA,CAAO,IAAA;AAErB,IAAA,MAAMJ,aAAA,CAAY,GAAA,CAAI,OAAA,EAAS,aAAA,EAAe,MAAM,YAAY,CAAA;AAChE,IAAA,IAAI,MAAM,aAAA,EAAe;AACvB,MAAA,MAAMA,aAAA,CAAY,GAAA,CAAI,OAAA,EAAS,cAAA,EAAgB,MAAM,aAAa,CAAA;AAAA,IACpE;AACA,IAAA,MAAM,WAAA,GAAc;AAAA,MAClB,GAAG,QAAA;AAAA,MACH,QAAA,EAAU,KAAK,GAAA,EAAI;AAAA,MACnB,oBAAA,EAAsB,IAAA,CAAK,GAAA,EAAI,GAAI,MAAM,UAAA,GAAa;AAAA,KACxD;AACA,IAAA,MAAMK,uBAAe,WAAW,CAAA;AAChC,IAAA,OAAO,WAAA;AAAA,EACT,CAAC,CAAA;AACH;;;;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"secretStore.cjs.js","sources":["../../src/lib/secretStore.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs-extra';\nimport os from 'node:os';\nimport path from 'node:path';\n\ntype SecretStore = {\n get(service: string, account: string): Promise<string | undefined>;\n set(service: string, account: string, secret: string): Promise<void>;\n delete(service: string, account: string): Promise<void>;\n};\n\nasync function loadKeytar(): Promise<typeof import('keytar') | undefined> {\n try {\n // eslint-disable-next-line import/no-extraneous-dependencies, @backstage/no-undeclared-imports\n const keytar = require('keytar') as typeof import('keytar');\n if (keytar && typeof keytar.getPassword === 'function') {\n return keytar;\n }\n } catch {\n // keytar not available\n }\n return undefined;\n}\n\nclass KeytarSecretStore implements SecretStore {\n private readonly keytar: typeof import('keytar');\n constructor(keytar: typeof import('keytar')) {\n this.keytar = keytar;\n }\n async get(service: string, account: string): Promise<string | undefined> {\n const result = await this.keytar.getPassword(service, account);\n return result ?? undefined;\n }\n async set(service: string, account: string, secret: string): Promise<void> {\n await this.keytar.setPassword(service, account, secret);\n }\n async delete(service: string, account: string): Promise<void> {\n await this.keytar.deletePassword(service, account);\n }\n}\n\nclass FileSecretStore implements SecretStore {\n private readonly baseDir: string;\n constructor() {\n const root =\n process.env.XDG_DATA_HOME ||\n (process.platform === 'win32'\n ? process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming')\n : path.join(os.homedir(), '.local', 'share'));\n this.baseDir = path.join(root, 'backstage-cli', 'auth-secrets');\n }\n private filePath(service: string, account: string): string {\n return path.join(\n this.baseDir,\n encodeURIComponent(service),\n `${encodeURIComponent(account)}.secret`,\n );\n }\n async get(service: string, account: string): Promise<string | undefined> {\n const file = this.filePath(service, account);\n if (!(await fs.pathExists(file))) return undefined;\n return await fs.readFile(file, 'utf8');\n }\n async set(service: string, account: string, secret: string): Promise<void> {\n const file = this.filePath(service, account);\n await fs.ensureDir(path.dirname(file));\n await fs.writeFile(file, secret, { encoding: 'utf8', mode: 0o600 });\n }\n async delete(service: string, account: string): Promise<void> {\n const file = this.filePath(service, account);\n await fs.remove(file);\n }\n}\n\nlet singleton: SecretStore | undefined;\n\nexport async function getSecretStore(): Promise<SecretStore> {\n if (!singleton) {\n const keytar = await loadKeytar();\n if (keytar) {\n singleton = new KeytarSecretStore(keytar);\n } else {\n singleton = new FileSecretStore();\n }\n }\n return singleton;\n}\n\n/**\n * Reset the singleton instance (for testing purposes only)\n * @internal\n */\nexport function resetSecretStore(): void {\n singleton = undefined;\n}\n"],"names":["path","os","fs"],"mappings":"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"}