oorja 2.5.2 → 2.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -71,7 +71,7 @@ Launch a terminal streaming session in SupaKit.
71
71
 
72
72
  ```
73
73
  USAGE
74
- $ oorja teletype [STREAMKEY] [-h] [-s <value>] [-m] [-n]
74
+ $ oorja teletype [STREAMKEY] [-h] [-s <value>] [-m] [-n] [--anonymous] [--ci-debug]
75
75
 
76
76
  FLAGS
77
77
  -h, --help Show CLI help.
@@ -79,6 +79,8 @@ FLAGS
79
79
  participants. Off by default
80
80
  -n, --new Create a new space
81
81
  -s, --shell=<value> shell to use. e.g. bash, fish
82
+ --anonymous Create an anonymous session without prompting for sign-in.
83
+ --ci-debug Create a new anonymous writable bash stream for CI debugging.
82
84
 
83
85
  DESCRIPTION
84
86
  Launch a terminal streaming session in SupaKit.
@@ -96,6 +98,9 @@ EXAMPLES
96
98
 
97
99
  $ teletype -m
98
100
  Will also allow participants to write to your terminal! Collaboration mode must be explicitly enabled.
101
+
102
+ $ teletype --ci-debug
103
+ Creates a new anonymous stream without prompting for sign-in. Useful for CI debug sessions you want to control from the link.
99
104
  ```
100
105
 
101
106
  ## `oorja signout`
@@ -9,6 +9,8 @@ export default class TeleTypeCommand extends Command {
9
9
  shell: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
10
  multiplex: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
11
  new: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
+ anonymous: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ 'ci-debug': import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
14
  };
13
15
  static args: {
14
16
  streamKey: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
@@ -26,6 +26,10 @@ you share your stream-keys with others.
26
26
  `${chalk.blueBright('$ teletype -m')}
27
27
  Will also allow participants to write to your terminal! Collaboration mode must be explicitly enabled.
28
28
 
29
+ `,
30
+ `${chalk.blueBright('$ teletype --ci-debug')}
31
+ Creates a new anonymous stream without prompting for sign-in. Useful for CI debug sessions you want to control from the link.
32
+
29
33
  `,
30
34
  ];
31
35
  static flags = {
@@ -46,21 +50,33 @@ Will also allow participants to write to your terminal! Collaboration mode must
46
50
  description: 'Create a new space',
47
51
  default: false,
48
52
  }),
53
+ anonymous: Flags.boolean({
54
+ description: 'Create an anonymous session without prompting for sign-in.',
55
+ default: false,
56
+ }),
57
+ 'ci-debug': Flags.boolean({
58
+ aliases: ['ci'],
59
+ description: 'Create a new anonymous writable bash stream for CI debugging.',
60
+ default: false,
61
+ }),
49
62
  };
50
63
  static args = {
51
64
  streamKey: Args.string({}),
52
65
  };
53
66
  async run() {
54
- const { args, flags: { shell: selectedShell, multiplex, new: createNewSpace }, } = await this.parse(TeleTypeCommand);
55
- const shell = selectedShell || DEFAULT_SHELL;
67
+ const { args, flags: { shell: selectedShell, multiplex, new: createNewSpace, anonymous, 'ci-debug': ciDebug }, } = await this.parse(TeleTypeCommand);
68
+ const shell = selectedShell || (ciDebug ? 'bash' : DEFAULT_SHELL);
69
+ const shouldCreateNewSpace = createNewSpace || ciDebug;
70
+ const shouldUseAnonymousAuth = anonymous || ciDebug;
71
+ const shouldMultiplex = multiplex || ciDebug;
56
72
  const config = new Config(this.config.configDir);
57
73
  const app = new App(config);
58
74
  if (args.streamKey) {
59
- await this.streamUsingStreamKey(app, { shell, multiplex, streamKey: args.streamKey });
75
+ await this.streamUsingStreamKey(app, { shell, multiplex: shouldMultiplex, streamKey: args.streamKey });
60
76
  exit(0);
61
77
  }
62
- if (createNewSpace) {
63
- await this.createRoomAndStream(app, { shell, multiplex });
78
+ if (shouldCreateNewSpace) {
79
+ await this.createRoomAndStream(app, { shell, multiplex: shouldMultiplex, anonymous: shouldUseAnonymousAuth });
64
80
  exit(0);
65
81
  }
66
82
  console.log('(use -h for description and options) \n');
@@ -77,10 +93,10 @@ Will also allow participants to write to your terminal! Collaboration mode must
77
93
  ]);
78
94
  switch (answer) {
79
95
  case STREAM_USING_STREAM_KEY:
80
- await this.streamUsingStreamKey(app, { shell, multiplex });
96
+ await this.streamUsingStreamKey(app, { shell, multiplex: shouldMultiplex });
81
97
  break;
82
98
  case STREAM_TO_NEW_SPACE:
83
- await this.createRoomAndStream(app, { shell, multiplex });
99
+ await this.createRoomAndStream(app, { shell, multiplex: shouldMultiplex, anonymous: shouldUseAnonymousAuth });
84
100
  break;
85
101
  }
86
102
  exit(0);
@@ -92,13 +108,13 @@ Will also allow participants to write to your terminal! Collaboration mode must
92
108
  exit();
93
109
  }
94
110
  const streamKeyStruct = parseStreamKey(streamKey);
95
- const oorja = await app.init(streamKeyStruct);
111
+ const oorja = await app.init({ streamKey: streamKeyStruct });
96
112
  const roomKey = oorja.getRoomKey(streamKeyStruct);
97
113
  this.clearstdin();
98
114
  await oorja.teletype({ roomKey, ...options, process });
99
115
  }
100
- async createRoomAndStream(app, { shell, multiplex }) {
101
- const oorja = await app.init();
116
+ async createRoomAndStream(app, { shell, multiplex, anonymous }) {
117
+ const oorja = await app.init({ authMode: anonymous ? 'anonymous' : 'prompt' });
102
118
  const spinner = ora({
103
119
  text: chalk.bold('Creating space with TeleType app'),
104
120
  discardStdin: false,
@@ -131,6 +147,9 @@ Will also allow participants to write to your terminal! Collaboration mode must
131
147
  spinner.succeed(chalk.bold('Space created')).clear();
132
148
  const link = oorja.linkForRoom(roomKey, inviteCode);
133
149
  console.log(`\n${chalk.bold(chalk.blueBright(link))}\n`);
150
+ if (anonymous && multiplex) {
151
+ console.log(chalk.yellowBright('Anyone with this link can access and write to this shell. Share it carefully.'));
152
+ }
134
153
  console.log(chalk.bold("^^ You'll be streaming here ^^"));
135
154
  this.clearstdin();
136
155
  return await oorja.teletype({ roomKey, shell, multiplex, process });
@@ -5,6 +5,11 @@ import { CreateRoomOptions, ConnectClient } from 'oorja/lib/connect/index';
5
5
  import { Future } from 'oorja/lib/utils';
6
6
  export declare class InvalidRoomLink extends Error {
7
7
  }
8
+ export type AuthMode = 'prompt' | 'anonymous';
9
+ type AppInitOptions = {
10
+ streamKey?: StreamKey;
11
+ authMode?: AuthMode;
12
+ };
8
13
  export declare class OORJA {
9
14
  private config;
10
15
  private connectClient;
@@ -31,7 +36,7 @@ export declare class App {
31
36
  connectionCheckFuture: Future<void>;
32
37
  private connectClient;
33
38
  constructor(config: Config);
34
- init: (streamKey?: StreamKey) => Promise<OORJA>;
39
+ init: (options?: AppInitOptions) => Promise<OORJA>;
35
40
  private establishConnection;
36
41
  private tryResumeSession;
37
42
  private socketConnect;
@@ -2,7 +2,7 @@ import { getoorjaConfig, INVALID_STREAM_KEY_MESSAGE } from 'oorja/lib/config';
2
2
  import { TeletypeSession } from 'oorja/lib/teletype/index';
3
3
  import { ConnectClient } from 'oorja/lib/connect/index';
4
4
  import { importKey, createRoomKey, exportKey } from 'oorja/lib/encryption';
5
- import { promptAuth, validateCliVersion } from 'oorja/lib/oorja/preflight';
5
+ import { createAnonymousSession, promptAuth, validateCliVersion } from 'oorja/lib/oorja/preflight';
6
6
  import { getRegion } from 'oorja/lib/oorja/client';
7
7
  import ora from 'ora';
8
8
  import { Future, printExitMessage } from 'oorja/lib/utils';
@@ -85,7 +85,8 @@ export class App {
85
85
  this.establishConnection();
86
86
  this.connectionCheckFuture = new Future();
87
87
  }
88
- init = async (streamKey) => {
88
+ init = async (options = {}) => {
89
+ const { streamKey } = options;
89
90
  let spinner = ora({
90
91
  text: 'Checking connectivity..',
91
92
  discardStdin: true,
@@ -98,13 +99,16 @@ export class App {
98
99
  }
99
100
  spinner.succeed('Online');
100
101
  const oorjaConfig = getoorjaConfig(this.config.getEnv());
101
- const isControlledMode = this.config.hasInjectedAccessToken();
102
+ const authMode = options.authMode || 'prompt';
103
+ const isControlledMode = authMode !== 'anonymous' && this.config.hasInjectedAccessToken();
102
104
  let user = undefined;
103
105
  try {
104
106
  if (!streamKey) {
105
- user = await this.tryResumeSession(isControlledMode);
107
+ user = authMode === 'anonymous' ? undefined : await this.tryResumeSession(isControlledMode);
106
108
  if (!user) {
107
- const token = await promptAuth(this.connectClient, linkForTokenGen(oorjaConfig));
109
+ const token = authMode === 'anonymous'
110
+ ? await createAnonymousSession(this.connectClient)
111
+ : await promptAuth(this.connectClient, linkForTokenGen(oorjaConfig));
108
112
  if (!token) {
109
113
  printExitMessage('Token not provided :(');
110
114
  exit(12);
@@ -1,3 +1,4 @@
1
1
  import { ConnectClient } from 'oorja/lib/connect/index';
2
+ export declare const createAnonymousSession: (connectClient: ConnectClient) => Promise<string>;
2
3
  export declare const promptAuth: (connectClient: ConnectClient, generateTokenLink: string) => Promise<string>;
3
4
  export declare const validateCliVersion: (connectClient: ConnectClient) => Promise<void>;
@@ -12,6 +12,11 @@ const promptToken = () => inquirer
12
12
  },
13
13
  ])
14
14
  .then((answers) => answers.accessToken);
15
+ export const createAnonymousSession = async (connectClient) => {
16
+ console.log('Creating anonymous user...');
17
+ connectClient.setAccessToken('');
18
+ return connectClient.createAnonymousUser();
19
+ };
15
20
  export const promptAuth = async (connectClient, generateTokenLink) => {
16
21
  const ANON = 'Proceed as an anonymous user';
17
22
  const SIGN_IN = 'Sign in with SupaKit';
@@ -26,8 +31,7 @@ export const promptAuth = async (connectClient, generateTokenLink) => {
26
31
  ]);
27
32
  switch (answer) {
28
33
  case ANON:
29
- console.log('Creating anonymous user...');
30
- return connectClient.createAnonymousUser();
34
+ return createAnonymousSession(connectClient);
31
35
  case SIGN_IN:
32
36
  console.log(`You can sign-in and generate your token here: ${chalk.blue(generateTokenLink)}`);
33
37
  return promptToken();
@@ -1,4 +1,5 @@
1
1
  import { IPty } from 'node-pty';
2
+ export declare const DEFAULT_DIMENSIONS: dimensions;
2
3
  export declare const initScreen: (username: string, hostname: string, shell: string, multiplexed: boolean) => void;
3
4
  export type dimensions = {
4
5
  rows: number;
@@ -1,5 +1,6 @@
1
1
  import chalk from 'chalk';
2
2
  import termSize from 'terminal-size';
3
+ export const DEFAULT_DIMENSIONS = { rows: 24, cols: 80 };
3
4
  export const initScreen = (username, hostname, shell, multiplexed) => {
4
5
  console.log(chalk.bold(chalk.blueBright('TeleType')));
5
6
  if (multiplexed) {
@@ -11,6 +12,9 @@ To terminate stream run ${chalk.yellowBright('exit')} or press ${chalk.yellowBri
11
12
  };
12
13
  export const getDimensions = () => {
13
14
  const { rows, columns } = termSize();
15
+ if (!Number.isFinite(rows) || !Number.isFinite(columns) || rows < 1 || columns < 1) {
16
+ return DEFAULT_DIMENSIONS;
17
+ }
14
18
  return { rows, cols: columns };
15
19
  };
16
20
  export const areDimensionEqual = (a, b) => {
@@ -18,6 +22,9 @@ export const areDimensionEqual = (a, b) => {
18
22
  };
19
23
  export const resizeBestFit = (term, userDimensions, shouldClearScreen = false) => {
20
24
  const allViewports = Object.values(userDimensions);
25
+ if (allViewports.length === 0) {
26
+ return;
27
+ }
21
28
  const minrows = Math.min(...allViewports.map((d) => d.rows));
22
29
  const mincols = Math.min(...allViewports.map((d) => d.cols));
23
30
  term.resize(mincols, minrows);
@@ -1,6 +1,6 @@
1
1
  import { spawn } from 'node-pty';
2
2
  import * as os from 'os';
3
- import { getDimensions, initScreen, areDimensionEqual, resizeBestFit } from 'oorja/lib/teletype/auxiliary';
3
+ import { DEFAULT_DIMENSIONS, getDimensions, initScreen, areDimensionEqual, resizeBestFit, } from 'oorja/lib/teletype/auxiliary';
4
4
  import chalk from 'chalk';
5
5
  import { Unauthorized } from 'oorja/lib/connect/errors';
6
6
  import { encrypt, decrypt } from 'oorja/lib/encryption';
@@ -17,9 +17,7 @@ export class TeletypeSession {
17
17
  options;
18
18
  username = os.userInfo().username;
19
19
  hostname = os.hostname();
20
- userDimensions = {
21
- [SELF]: getDimensions(),
22
- };
20
+ userDimensions = {};
23
21
  channel;
24
22
  term;
25
23
  sessionCount = 0;
@@ -50,7 +48,11 @@ export class TeletypeSession {
50
48
  });
51
49
  startTerm = () => {
52
50
  const { stdin, stdout } = this.options.process;
53
- const dimensions = this.userDimensions[SELF];
51
+ const shouldReadLocalStdin = stdin.isTTY && typeof stdin.setRawMode === 'function';
52
+ const dimensions = shouldReadLocalStdin ? getDimensions() : DEFAULT_DIMENSIONS;
53
+ if (shouldReadLocalStdin) {
54
+ this.userDimensions[SELF] = dimensions;
55
+ }
54
56
  console.log(chalk.blue(`${chalk.bold(`${this.username}@${this.hostname}`)} Spawning streaming shell: ${chalk.bold(`${this.options.shell}`)}`));
55
57
  this.term = spawn(this.options.shell, [], {
56
58
  name: 'xterm-256color',
@@ -61,6 +63,9 @@ export class TeletypeSession {
61
63
  });
62
64
  this.ptyFuture.promise.then(() => {
63
65
  initScreen(this.username, this.hostname, this.options.shell, this.options.multiplex);
66
+ if (!shouldReadLocalStdin) {
67
+ return;
68
+ }
64
69
  if (this.options.shell.endsWith('bash')) {
65
70
  stdout.write('Adjusting shell prompt to show streaming indicator\n');
66
71
  this.term.write("export PS1='📡 [streaming] '$PS1\n");
@@ -102,22 +107,29 @@ export class TeletypeSession {
102
107
  this.stop({ killTerm: false });
103
108
  this.resolve?.(null);
104
109
  });
105
- stdin.setEncoding('utf8');
106
- stdin.setRawMode(true);
107
110
  const stdinDataHandler = (d) => this.term.write(d.toString('utf8'));
108
- stdin.on('data', stdinDataHandler);
111
+ if (shouldReadLocalStdin) {
112
+ stdin.setEncoding('utf8');
113
+ stdin.setRawMode(true);
114
+ stdin.on('data', stdinDataHandler);
115
+ }
109
116
  this.cleanupShell = ({ killTerm = true } = {}) => {
110
117
  clearInterval(dimensionPoll);
111
118
  ptyDataSubscription.dispose();
112
119
  ptyExitSubscription.dispose();
113
- stdin.off('data', stdinDataHandler);
114
- stdin.setRawMode(false);
120
+ if (shouldReadLocalStdin) {
121
+ stdin.off('data', stdinDataHandler);
122
+ stdin.setRawMode(false);
123
+ }
115
124
  if (killTerm) {
116
125
  this.term.kill();
117
126
  }
118
127
  };
119
128
  };
120
129
  reEvaluateOwnDimensions = () => {
130
+ if (!this.userDimensions[SELF]) {
131
+ return;
132
+ }
121
133
  const lastKnown = this.userDimensions[SELF];
122
134
  const latest = getDimensions();
123
135
  if (areDimensionEqual(lastKnown, latest)) {
@@ -33,7 +33,8 @@
33
33
  "examples": [
34
34
  "\u001b[94m$ teletype\u001b[39m\nWill prompt to choose streaming destination - either enter a stream key for an existing space or create a new space.\n\n",
35
35
  "\u001b[94m$ teletype 'sk-xxxx:space-id#encryption-secret'\u001b[39m\nWill stream to the space using the secret stream-key. NOTE: stream-keys are personal (generated for you in the teletype app at supakit.app), do not accept them from other people, nor should\nyou share your stream-keys with others.\n\n",
36
- "\u001b[94m$ teletype -m\u001b[39m\nWill also allow participants to write to your terminal! Collaboration mode must be explicitly enabled.\n\n"
36
+ "\u001b[94m$ teletype -m\u001b[39m\nWill also allow participants to write to your terminal! Collaboration mode must be explicitly enabled.\n\n",
37
+ "\u001b[94m$ teletype --ci-debug\u001b[39m\nCreates a new anonymous stream without prompting for sign-in. Useful for CI debug sessions you want to control from the link.\n\n"
37
38
  ],
38
39
  "flags": {
39
40
  "help": {
@@ -69,6 +70,21 @@
69
70
  "name": "new",
70
71
  "allowNo": false,
71
72
  "type": "boolean"
73
+ },
74
+ "anonymous": {
75
+ "description": "Create an anonymous session without prompting for sign-in.",
76
+ "name": "anonymous",
77
+ "allowNo": false,
78
+ "type": "boolean"
79
+ },
80
+ "ci-debug": {
81
+ "aliases": [
82
+ "ci"
83
+ ],
84
+ "description": "Create a new anonymous writable bash stream for CI debugging.",
85
+ "name": "ci-debug",
86
+ "allowNo": false,
87
+ "type": "boolean"
72
88
  }
73
89
  },
74
90
  "hasDynamicHelp": false,
@@ -89,5 +105,5 @@
89
105
  ]
90
106
  }
91
107
  },
92
- "version": "2.5.2"
108
+ "version": "2.5.4"
93
109
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "oorja",
3
3
  "description": "stream terminals to the web and more.",
4
- "version": "2.5.2",
4
+ "version": "2.5.4",
5
5
  "packageManager": "pnpm@11.5.2",
6
6
  "keywords": [
7
7
  "teletype",