@yahoo/uds 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. package/cli/README.md +21 -0
  2. package/cli/cli.ts +27 -4
  3. package/cli/commands/login.ts +28 -0
  4. package/cli/commands/logout.ts +24 -0
  5. package/cli/commands/uds.ts +4 -1
  6. package/cli/env.d.ts +5 -0
  7. package/cli/exec.ts +1 -1
  8. package/cli/preload.ts +16 -0
  9. package/cli/uds-cli +3 -3
  10. package/cli/utils/auth.test.ts +107 -0
  11. package/cli/utils/auth.ts +158 -0
  12. package/cli/utils/client_secrets.json.enc +0 -0
  13. package/cli/utils/secrets.ts +40 -0
  14. package/cli/utils/types.ts +8 -0
  15. package/package.json +163 -155
  16. package/cli/bin/uds-darwin-arm64-baseline +0 -0
  17. package/cli/bin/uds-linux-x64-baseline +0 -0
  18. package/dist/chunk-2JIYRTEY.js +0 -3
  19. package/dist/chunk-3VTRSTDI.cjs +0 -2
  20. package/dist/chunk-4J7ZJHCN.js +0 -2
  21. package/dist/chunk-5X3JN6IH.cjs +0 -3
  22. package/dist/chunk-6K5IORZA.cjs +0 -2
  23. package/dist/chunk-AIRVDEVS.cjs +0 -3
  24. package/dist/chunk-BQTYVXIC.js +0 -3
  25. package/dist/chunk-CE5NDFHI.js +0 -2
  26. package/dist/chunk-E3Z3A4MR.cjs +0 -2
  27. package/dist/chunk-OJR4RBBW.js +0 -3
  28. package/dist/chunk-PCSDVJE6.js +0 -2
  29. package/dist/chunk-SLCISFAV.cjs +0 -3
  30. package/dist/chunk-TWTUXY76.cjs +0 -2
  31. package/dist/chunk-TYKFUQUM.cjs +0 -1
  32. package/dist/chunk-W5AGPUNC.cjs +0 -4
  33. package/dist/chunk-XFTF7IHG.js +0 -2
  34. package/dist/chunk-Y2TGGXMH.js +0 -3
  35. package/dist/chunk-ZJE5XRN2.js +0 -4
  36. package/dist/client/index.cjs +0 -4
  37. package/dist/client/index.d.cts +0 -97
  38. package/dist/client/index.d.ts +0 -97
  39. package/dist/client/index.js +0 -6
  40. package/dist/experimental/index.cjs +0 -3
  41. package/dist/experimental/index.d.cts +0 -451
  42. package/dist/experimental/index.d.ts +0 -451
  43. package/dist/experimental/index.js +0 -3
  44. package/dist/fixtures.cjs +0 -1506
  45. package/dist/fixtures.d.cts +0 -94
  46. package/dist/fixtures.d.ts +0 -94
  47. package/dist/fixtures.js +0 -1449
  48. package/dist/index.cjs +0 -1
  49. package/dist/index.d.cts +0 -300
  50. package/dist/index.d.ts +0 -300
  51. package/dist/index.js +0 -2
  52. package/dist/metafile-cjs.json +0 -1
  53. package/dist/metafile-esm.json +0 -1
  54. package/dist/motionFeatures-M3DOZMRC.cjs +0 -1
  55. package/dist/motionFeatures-QDISAARM.js +0 -1
  56. package/dist/styles/toast.css +0 -3
  57. package/dist/styles/toast.d.cts +0 -2
  58. package/dist/styles/toast.d.ts +0 -2
  59. package/dist/tailwind/plugin.cjs +0 -3
  60. package/dist/tailwind/plugin.d.cts +0 -60
  61. package/dist/tailwind/plugin.d.ts +0 -60
  62. package/dist/tailwind/plugin.js +0 -3
  63. package/dist/tailwind/purger.cjs +0 -6
  64. package/dist/tailwind/purger.d.cts +0 -17
  65. package/dist/tailwind/purger.d.ts +0 -17
  66. package/dist/tailwind/purger.js +0 -6
  67. package/dist/tailwind/tsMorph.cjs +0 -3
  68. package/dist/tailwind/tsMorph.d.cts +0 -31
  69. package/dist/tailwind/tsMorph.d.ts +0 -31
  70. package/dist/tailwind/tsMorph.js +0 -2
  71. package/dist/tailwind/utils.cjs +0 -1
  72. package/dist/tailwind/utils.d.cts +0 -99
  73. package/dist/tailwind/utils.d.ts +0 -99
  74. package/dist/tailwind/utils.js +0 -1
  75. package/dist/tokens/index.cjs +0 -1
  76. package/dist/tokens/index.d.cts +0 -1127
  77. package/dist/tokens/index.d.ts +0 -1127
  78. package/dist/tokens/index.js +0 -1
  79. package/dist/tokens/parseTokens.cjs +0 -1
  80. package/dist/tokens/parseTokens.d.cts +0 -59
  81. package/dist/tokens/parseTokens.d.ts +0 -59
  82. package/dist/tokens/parseTokens.js +0 -1
  83. package/dist/types-CpZ2ERLZ.d.cts +0 -949
  84. package/dist/types-CpZ2ERLZ.d.ts +0 -949
package/cli/README.md CHANGED
@@ -128,6 +128,27 @@ Any file added to commands/codemod will be available in prompt land.
128
128
  uds codemod
129
129
  ```
130
130
 
131
+ ### Login
132
+
133
+ The `uds login` command is used to authenticate the user to the CLI. We use
134
+ Google's OAuth2 flow, which is the same login flow used by the [Configurator](/docs/getting-started/using-configurator) and the documentation site. Logging in to the CLI helps us identify and track CLI usage and metrics.
135
+
136
+ #### Flags
137
+
138
+ | Flag | Description | Default | Required |
139
+ | ---------- | ----------------------------------------- | ------- | -------- |
140
+ | `skipAuth` | Skip auth checks (for CI/CD environments) | `false` | |
141
+
142
+ **Example:**
143
+
144
+ ```shell
145
+ uds login
146
+ uds login --skipAuth
147
+
148
+ # Sign out current user.
149
+ uds logout
150
+ ```
151
+
131
152
  ### Expo (WIP)
132
153
 
133
154
  The `uds expo` command is for building and launching React Native apps using Expo.
package/cli/cli.ts CHANGED
@@ -2,25 +2,48 @@
2
2
  // Start bluebun to run the correct CLI command
3
3
  import { parseArgs } from 'node:util';
4
4
 
5
- import { run } from 'bluebun';
5
+ import { getFeatureFlags } from '@yahoo/uds/flags';
6
+ import { print, red, run } from 'bluebun';
6
7
 
7
- function main() {
8
+ import { getAuthenticatedUser } from './utils/auth';
9
+
10
+ async function main() {
8
11
  // We need to pass the path from Node to the Bun binaries
9
12
  // because there's an issue where the Bun binaries struggle to resolve
10
- const { values } = parseArgs({
13
+ const { values, positionals } = parseArgs({
11
14
  args: Bun.argv,
12
15
  options: {
13
16
  commandsPath: {
14
17
  type: 'string',
15
18
  },
19
+ skipAuth: {
20
+ type: 'boolean',
21
+ default: false,
22
+ },
16
23
  },
17
24
  strict: false,
18
25
  allowPositionals: true,
19
26
  });
20
27
 
28
+ const cliPath = values.commandsPath!.toString();
29
+ const isLoginCmd = positionals.includes('login');
30
+ const { useCLIAuth } = getFeatureFlags();
31
+
32
+ if (useCLIAuth && !values.skipAuth && !isLoginCmd) {
33
+ const user = await getAuthenticatedUser(cliPath);
34
+ if (!user) {
35
+ print(
36
+ red(
37
+ '🚨 Sign-in required. Please run `uds login` and use a @yahooinc.com email during sign-in.',
38
+ ),
39
+ );
40
+ return;
41
+ }
42
+ }
43
+
21
44
  run({
22
45
  name: 'uds',
23
- cliPath: values.commandsPath!.toString(),
46
+ cliPath,
24
47
  });
25
48
  }
26
49
 
@@ -0,0 +1,28 @@
1
+ import { magenta, print, red } from 'bluebun';
2
+
3
+ import { login } from '../utils/auth';
4
+
5
+ export default {
6
+ name: 'login',
7
+ description: '👤 Log in to UDS CLI',
8
+ alias: ['auth'],
9
+ run: async () => {
10
+ try {
11
+ const user = await login();
12
+ if (user) {
13
+ print(magenta(`🔒 Logged in as ${user.email}`));
14
+ }
15
+ } catch (error) {
16
+ if (error instanceof Error) {
17
+ print(red(error.message));
18
+ } else {
19
+ print(
20
+ red(
21
+ `❌ An error occurred while logging in. Please ask in the #uds-ask channel for support.`,
22
+ ),
23
+ );
24
+ process.exitCode = 1;
25
+ }
26
+ }
27
+ },
28
+ };
@@ -0,0 +1,24 @@
1
+ import { magenta, print, red } from 'bluebun';
2
+
3
+ import { logout } from '../utils/auth';
4
+
5
+ export default {
6
+ name: 'logout',
7
+ description: '👤 Sign out of UDS CLI',
8
+ run: async () => {
9
+ try {
10
+ await logout();
11
+ print(magenta('👋 You have been logged out.'));
12
+ } catch (error) {
13
+ if (error instanceof Error) {
14
+ print(red(error.message));
15
+ } else {
16
+ print(
17
+ red(
18
+ `❌ An error occurred while logging out. Please ask in the #uds-ask channel for support.`,
19
+ ),
20
+ );
21
+ }
22
+ }
23
+ },
24
+ };
@@ -1,5 +1,6 @@
1
1
  import { print, type Props, red } from 'bluebun';
2
2
 
3
+ import { getAuthenticatedUser } from '../utils/auth';
3
4
  import { getCommandHelp } from '../utils/getCommandHelp';
4
5
 
5
6
  export default {
@@ -9,6 +10,8 @@ export default {
9
10
  if (props.first) {
10
11
  print(red(`Unknown command: ${props.first}`));
11
12
  }
12
- await getCommandHelp(props);
13
+ const user = await getAuthenticatedUser();
14
+ const notes = user ? `🔒 Logged in as ${user.email}` : undefined;
15
+ await getCommandHelp({ ...props, notes });
13
16
  },
14
17
  };
package/cli/env.d.ts CHANGED
@@ -14,6 +14,11 @@ declare module 'bun' {
14
14
  EXPO_USE_METRO_WORKSPACE_ROOT?: string;
15
15
  EXPO_BUNDLE_APP?: string;
16
16
  ESLINT_USE_FLAT_CONFIG?: string;
17
+ /** UDS purge command - which color and scale modes to keep */
17
18
  ENABLED_SCALE_AND_COLOR_MODES?: string;
19
+ /** UDS config id */
20
+ UDS_ID?: string;
21
+ /** UDS sync command - filename to write the config output */
22
+ UDS_OUT_FILE?: string;
18
23
  }
19
24
  }
package/cli/exec.ts CHANGED
@@ -28,7 +28,7 @@ const detectPlatform = () => {
28
28
  });
29
29
  } else {
30
30
  throw new Error(
31
- 'Unsupported platform 😢, pleaes reach out to the UDS team for support #uds-ask.',
31
+ 'Unsupported platform 😢, please reach out to the UDS team for support #uds-ask.',
32
32
  );
33
33
  }
34
34
  };
package/cli/preload.ts CHANGED
@@ -44,3 +44,19 @@ mock.module('@yahoo/uds/tailwind/purger', () => ({
44
44
  Button: '',
45
45
  },
46
46
  }));
47
+
48
+ mock.module('googleapis', () => ({
49
+ google: {
50
+ auth: {
51
+ OAuth2: mock(() => {}).mockImplementation(() => ({
52
+ getToken: () => Promise.resolve({ tokens: 'test' }),
53
+ setCredentials: mock(() => {}),
54
+ })),
55
+ },
56
+ oauth2: () => ({
57
+ userinfo: {
58
+ get: () => Promise.resolve({ data: { email: 'foo@yahooinc.com' } }),
59
+ },
60
+ }),
61
+ },
62
+ }));
package/cli/uds-cli CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  // Note: This file is generated, do not edit directly! Edit exec.ts instead.
4
4
  // cli/exec.ts
5
- import {execFileSync} from "child_process";
5
+ import { execFileSync } from "child_process";
6
6
  import path from "path";
7
- import {fileURLToPath} from "url";
7
+ import { fileURLToPath } from "url";
8
8
 
9
9
  // cli/consts.ts
10
10
  var SUPPORTED_BUN_PLATFORMS = ["linux-x64-baseline", "darwin-arm64-baseline"];
@@ -23,7 +23,7 @@ var detectPlatform = () => {
23
23
  stdio: "inherit"
24
24
  });
25
25
  } else {
26
- throw new Error("Unsupported platform \uD83D\uDE22, pleaes reach out to the UDS team for support #uds-ask.");
26
+ throw new Error("Unsupported platform \uD83D\uDE22, please reach out to the UDS team for support #uds-ask.");
27
27
  }
28
28
  };
29
29
  detectPlatform();
@@ -0,0 +1,107 @@
1
+ import path from 'node:path';
2
+
3
+ import { afterAll, describe, expect, it, mock } from 'bun:test';
4
+ import http from 'http';
5
+ // eslint-disable-next-line n/no-unpublished-import
6
+ import httpMocks from 'node-mocks-http';
7
+
8
+ import {
9
+ getAuthenticatedUser,
10
+ isYahooEmployee,
11
+ login,
12
+ logout,
13
+ onRequestHandler,
14
+ type User,
15
+ } from './auth';
16
+
17
+ const __dirname = path.resolve(import.meta.dir);
18
+ const filepath = path.resolve(__dirname, '.uds/user.json');
19
+
20
+ const writeCache = async (filePath: string, user: User) => {
21
+ return Bun.write(filePath, JSON.stringify(user));
22
+ };
23
+
24
+ describe('auth', () => {
25
+ describe('isYahooEmployee', () => {
26
+ it('does not return a user on first use', async () => {
27
+ expect(isYahooEmployee({ email: 'user@yahooinc.com' })).toBe(true);
28
+ expect(isYahooEmployee({ email: 'user@test.com' })).toBe(false);
29
+ });
30
+ });
31
+
32
+ describe('getAuthenticatedUser', () => {
33
+ it('does not return a user on first use', async () => {
34
+ expect(await getAuthenticatedUser(__dirname)).toBeUndefined();
35
+ });
36
+
37
+ it('reads user info from cache when one exists', async () => {
38
+ const user: User = { email: 'user@yahooinc.com', name: 'User' };
39
+ await writeCache(filepath, user);
40
+ const userInfo = await getAuthenticatedUser(__dirname);
41
+ expect(userInfo).toEqual(user);
42
+ });
43
+
44
+ it('resets user when non @yahooinc.com email is used', async () => {
45
+ await writeCache(filepath, { email: 'user@test.com', name: 'User' });
46
+ expect(await Bun.file(filepath).exists()).toBeTrue();
47
+ const userInfo = await getAuthenticatedUser(__dirname);
48
+ expect(userInfo).toBeUndefined();
49
+ expect(await Bun.file(filepath).exists()).toBeFalse();
50
+ });
51
+ });
52
+
53
+ describe('getAuthenticatedClient', () => {
54
+ // mock.module('open', () => ({}));
55
+ const mockServer = Object.assign(Object.create(http.Server.prototype), {
56
+ listen: mock(),
57
+ on: mock(),
58
+ close: mock(),
59
+ });
60
+ const resolve = mock();
61
+ const reject = mock();
62
+
63
+ it('returns error when no code is on callback url', async () => {
64
+ const request = httpMocks.createRequest({ method: 'GET', url: '/oauth2callback' });
65
+ const response = httpMocks.createResponse();
66
+ await onRequestHandler.bind(mockServer)(request, response, resolve, reject);
67
+ expect(response._getData()).toInclude('no code parameter');
68
+ });
69
+
70
+ it('can successfully login in user', async () => {
71
+ const request = httpMocks.createRequest({ method: 'GET', url: '/oauth2callback?code=123' });
72
+ const response = httpMocks.createResponse();
73
+ await onRequestHandler.bind(mockServer)(request, response, resolve, reject);
74
+ expect(response._getData()).toInclude('Authentication successful!');
75
+ expect(resolve).toHaveBeenCalled();
76
+ });
77
+ });
78
+
79
+ describe('logout', () => {
80
+ it('removes the user cache', async () => {
81
+ await writeCache(filepath, { email: 'user@yahooinc.com', name: 'User' });
82
+ expect(await Bun.file(filepath).exists()).toBeTrue();
83
+ await logout(filepath);
84
+ expect(await Bun.file(filepath).exists()).toBeFalse();
85
+ });
86
+ });
87
+
88
+ describe('login', () => {
89
+ afterAll(async () => {
90
+ await logout(); // cleanup
91
+ });
92
+
93
+ const mockFunc = mock(() => Promise.resolve({ email: 'foo@yahooinc.com' }));
94
+
95
+ mock.module('./auth', () => ({
96
+ getAuthenticatedClient: mockFunc,
97
+ }));
98
+
99
+ it('uses cache when user previously logged in', async () => {
100
+ // Test multiple calls to login
101
+ await login();
102
+ await login();
103
+ await login();
104
+ expect(mockFunc).toHaveBeenCalledTimes(1);
105
+ });
106
+ });
107
+ });
@@ -0,0 +1,158 @@
1
+ import { unlink } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
4
+ import { print, red } from 'bluebun';
5
+ import Bun from 'bun';
6
+ import { Auth, google, oauth2_v2 } from 'googleapis';
7
+ import http from 'http';
8
+ import open from 'open';
9
+
10
+ import clientSecrets from './client_secrets.json';
11
+
12
+ const { redirect_uris, client_id, client_secret } = clientSecrets.web;
13
+ const REDIRECT_URL = redirect_uris[0];
14
+ const { port: PORT, origin: BASE_URL } = new URL(REDIRECT_URL);
15
+
16
+ const cacheFilePath = '.uds/user.json';
17
+ const DEFAULT_CLI_PATH = path.resolve(import.meta.dir, '..');
18
+ const CACHED_USER_FILE = path.resolve(DEFAULT_CLI_PATH, cacheFilePath);
19
+
20
+ // Credentials can be found in https://console.cloud.google.com/apis/credentials/oauthclient/700524957090-6uju02gp6i0rlm3p17nt1v6vbrretfka.apps.googleusercontent.com?project=uds-poc.
21
+ const oauth2Client = new google.auth.OAuth2(client_id, client_secret, REDIRECT_URL);
22
+
23
+ type User = oauth2_v2.Schema$Userinfo;
24
+
25
+ function isYahooEmployee(user?: User) {
26
+ return user?.email?.endsWith('@yahooinc.com');
27
+ }
28
+
29
+ async function onRequestHandler(
30
+ this: http.Server,
31
+ req: http.IncomingMessage,
32
+ res: http.ServerResponse,
33
+ resolve: (value: typeof oauth2Client) => void,
34
+ reject: (reason?: unknown) => void,
35
+ ) {
36
+ try {
37
+ const code = new URL(req.url || '', BASE_URL).searchParams.get('code');
38
+ if (!code) {
39
+ res.end('There was no code parameter on the url.');
40
+ this.close();
41
+ return;
42
+ }
43
+
44
+ res.end('Authentication successful! You can close this window.');
45
+
46
+ this.close();
47
+
48
+ const { tokens } = await oauth2Client.getToken(code);
49
+ oauth2Client.setCredentials(tokens);
50
+
51
+ resolve(oauth2Client);
52
+ } catch (e) {
53
+ reject(e);
54
+ }
55
+ }
56
+
57
+ async function getAuthenticatedClient(): Promise<Auth.OAuth2Client> {
58
+ return new Promise((resolve, reject) => {
59
+ const authorizeUrl = oauth2Client.generateAuthUrl({
60
+ access_type: 'offline',
61
+ scope: [
62
+ 'https://www.googleapis.com/auth/userinfo.profile',
63
+ 'https://www.googleapis.com/auth/userinfo.email',
64
+ ].join(' '),
65
+ hd: 'yahooinc.com',
66
+ include_granted_scopes: true,
67
+ });
68
+
69
+ // TODO: If port (3000) is already in use, this will fail.
70
+ // Setup https://www.npmjs.com/package/find-free-ports, but that won't
71
+ // play well with the pre-configured redirect_uris in the Google Cloud Console.
72
+ const server = http
73
+ .createServer()
74
+ .listen(PORT, async () => {
75
+ const childProcess = await open(authorizeUrl, { wait: false });
76
+ childProcess.unref();
77
+ })
78
+ .on('request', (req, res) => onRequestHandler.call(server, req, res, resolve, reject))
79
+ .on('error', (err: NodeJS.ErrnoException) => {
80
+ if (err.code && err.code.includes('EADDRINUSE')) {
81
+ print(
82
+ red(`🚨 Port ${PORT} already in use. Cannot start local server to handle OAuth flow.`),
83
+ );
84
+ server.close();
85
+ }
86
+ });
87
+ });
88
+ }
89
+
90
+ async function logout(cachePath?: string) {
91
+ // 1. TODO: Revoke token access
92
+ try {
93
+ // 2. Remove cached user data.
94
+ return await unlink(cachePath ?? CACHED_USER_FILE);
95
+ } catch {
96
+ // noop
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Takes the user through the OAuth2 flow, creating a server for the oauth callback.
102
+ * If the user has previously authenticated, it returns the cached user.
103
+ * @returns
104
+ */
105
+ async function login() {
106
+ let user = await getAuthenticatedUser();
107
+ // Authenticate if there's no user cached.
108
+ if (!user) {
109
+ try {
110
+ const auth = await getAuthenticatedClient();
111
+ const oauth2 = google.oauth2({ version: 'v2', auth });
112
+ user = (await oauth2.userinfo.get()).data;
113
+ await Bun.write(CACHED_USER_FILE, JSON.stringify(user, null, 2));
114
+ } catch (err) {
115
+ console.error('Error:', err);
116
+ }
117
+ }
118
+
119
+ return user;
120
+ }
121
+
122
+ /**
123
+ * The authenticated user or undefined if the user is not authenticated.
124
+ * @param cliPath Root folder of cli commands. Defaults to 'packages/uds/cli'.
125
+ * Note: this is only needed when calling this method in cli.ts. The compiled
126
+ * platform-specific binaries create a virtual file system and we need
127
+ * to forward the package libPath from exec.ts.
128
+ * @returns user info
129
+ */
130
+ async function getAuthenticatedUser(cliPath = DEFAULT_CLI_PATH): Promise<User | undefined> {
131
+ try {
132
+ const cachePath = path.resolve(cliPath, cacheFilePath);
133
+ const file = Bun.file(cachePath);
134
+ const user = await file.json();
135
+
136
+ if (isYahooEmployee(user)) {
137
+ return user;
138
+ }
139
+
140
+ await logout(cachePath); // remove cached user.
141
+ } catch (err) {
142
+ if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {
143
+ console.error(err);
144
+ }
145
+ }
146
+
147
+ return undefined;
148
+ }
149
+
150
+ export {
151
+ getAuthenticatedClient,
152
+ getAuthenticatedUser,
153
+ isYahooEmployee,
154
+ login,
155
+ logout,
156
+ onRequestHandler,
157
+ type User,
158
+ };
@@ -0,0 +1,40 @@
1
+ import path from 'node:path';
2
+
3
+ // eslint-disable-next-line n/no-unpublished-import
4
+ import { loadEnvConfig } from '@next/env';
5
+ import { $ } from 'bun';
6
+
7
+ loadEnvConfig(process.cwd());
8
+
9
+ const secretsFile = path.resolve(import.meta.dir, 'client_secrets.json');
10
+ const encryptedFilename = `${secretsFile}.enc`;
11
+
12
+ async function encrypt() {
13
+ await $`openssl enc -aes-256-cbc -in ${secretsFile} -out ${encryptedFilename}`;
14
+ }
15
+
16
+ async function decrypt() {
17
+ const f = Bun.file(secretsFile);
18
+ if (!(await f.exists())) {
19
+ await $`openssl enc -aes-256-cbc -in ${encryptedFilename} -out ${secretsFile} -d -pass env:UDS_CLI_SECRETS_PW`;
20
+ }
21
+ }
22
+
23
+ async function main() {
24
+ if (!process.env.UDS_CLI_SECRETS_PW) {
25
+ console.error('Please set UDS_CLI_SECRETS_PW env variable. The password is in LastPass.');
26
+ process.exitCode = 1;
27
+ return;
28
+ }
29
+
30
+ const cmd = Bun.argv[2];
31
+ if (cmd === 'encrypt') {
32
+ await encrypt();
33
+ console.log(`Secrets file encrypted to ${encryptedFilename}`);
34
+ } else if (cmd === 'decrypt') {
35
+ await decrypt();
36
+ console.log(`Secrets file saved to ${secretsFile}`);
37
+ }
38
+ }
39
+
40
+ main();
@@ -17,3 +17,11 @@ export type SyncOptions = {
17
17
  /** Enable watch mode? */
18
18
  watch?: boolean;
19
19
  };
20
+
21
+ export type LoginOptions = {
22
+ /**
23
+ * Opt-out of authentication. Typically used in a CI/CD environment.
24
+ * @default false
25
+ */
26
+ skipAuth?: boolean;
27
+ };