@jupyterlite/terminal 0.1.6 → 0.2.0-a0

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/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { JupyterLiteServerPlugin } from '@jupyterlite/server';
2
- import { ITerminalManager } from './tokens';
3
- declare const _default: (JupyterLiteServerPlugin<ITerminalManager> | JupyterLiteServerPlugin<void>)[];
1
+ import { JupyterFrontEndPlugin } from '@jupyterlab/application';
2
+ import { ServiceManagerPlugin, Terminal } from '@jupyterlab/services';
3
+ declare const _default: (ServiceManagerPlugin<Terminal.IManager> | JupyterFrontEndPlugin<void>)[];
4
4
  export default _default;
package/lib/index.js CHANGED
@@ -1,61 +1,39 @@
1
1
  // Copyright (c) Jupyter Development Team.
2
2
  // Distributed under the terms of the Modified BSD License.
3
- import { TerminalManager } from './manager';
4
- import { ITerminalManager } from './tokens';
3
+ import { ITerminalManager } from '@jupyterlab/services';
4
+ import { IServiceWorkerManager } from '@jupyterlite/server';
5
+ import { isILiteTerminalManager, LiteTerminalManager } from './manager';
5
6
  /**
6
- * The terminals service plugin.
7
+ * The terminal manager plugin, replacing the JupyterLab terminal manager.
7
8
  */
8
- const terminalsPlugin = {
9
+ const terminalManagerPlugin = {
9
10
  id: '@jupyterlite/terminal:plugin',
10
- description: 'A terminal for JupyterLite',
11
+ description: 'A JupyterLite extension providing a custom terminal manager',
11
12
  autoStart: true,
12
13
  provides: ITerminalManager,
13
- activate: async (app) => {
14
+ activate: (_) => {
14
15
  console.log('JupyterLite extension @jupyterlite/terminal:plugin is activated!');
15
- const { serviceManager } = app;
16
- const { serverSettings, terminals } = serviceManager;
17
- console.log('terminals available:', terminals.isAvailable());
18
- console.log('terminals ready:', terminals.isReady); // Not ready
19
- console.log('terminals active:', terminals.isActive);
20
- // Not sure this is necessary?
21
- await terminals.ready;
22
- console.log('terminals ready after await:', terminals.isReady); // Ready
23
- return new TerminalManager(serverSettings.wsUrl);
16
+ return new LiteTerminalManager();
24
17
  }
25
18
  };
26
19
  /**
27
- * A plugin providing the routes for the terminals service
20
+ * A plugin that sets the browsingContextId of the terminal manager.
28
21
  */
29
- const terminalsRoutesPlugin = {
30
- id: '@jupyterlite/terminal:routes-plugin',
22
+ const browsingContextIdSetter = {
23
+ id: '@jupyterlite/terminal:browsing-context-id',
31
24
  autoStart: true,
25
+ optional: [IServiceWorkerManager],
32
26
  requires: [ITerminalManager],
33
- activate: (app, terminalManager) => {
34
- console.log('JupyterLite extension @jupyterlite/terminal:routes-plugin is activated!', terminalManager);
35
- // GET /api/terminals - List the running terminals
36
- app.router.get('/api/terminals', async (req) => {
37
- const res = await terminalManager.listRunning();
38
- // Should return last_activity for each too,
39
- return new Response(JSON.stringify(res));
40
- });
41
- // POST /api/terminals - Start a terminal
42
- app.router.post('/api/terminals', async (req) => {
43
- const res = await terminalManager.startNew();
44
- // Should return last_activity too.
45
- return new Response(JSON.stringify(res));
46
- });
47
- // DELETE /api/terminals/{terminal name} - Delete a terminal
48
- app.router.delete('/api/terminals/(.+)', async (req, name) => {
49
- const exists = terminalManager.has(name);
50
- if (exists) {
51
- await terminalManager.shutdownTerminal(name);
27
+ activate: (_, terminalManager, serviceWorkerManager) => {
28
+ if (serviceWorkerManager !== undefined) {
29
+ if (isILiteTerminalManager(terminalManager)) {
30
+ const { browsingContextId } = serviceWorkerManager;
31
+ terminalManager.browsingContextId = browsingContextId;
52
32
  }
53
33
  else {
54
- const msg = `The terminal session "${name}"" does not exist`;
55
- console.warn(msg);
34
+ console.warn('Terminal manager does not support setting browsingContextId');
56
35
  }
57
- return new Response(null, { status: exists ? 204 : 404 });
58
- });
36
+ }
59
37
  }
60
38
  };
61
- export default [terminalsPlugin, terminalsRoutesPlugin];
39
+ export default [terminalManagerPlugin, browsingContextIdSetter];
package/lib/manager.d.ts CHANGED
@@ -1,32 +1,93 @@
1
- import { TerminalAPI } from '@jupyterlab/services';
2
- import { ITerminalManager } from './tokens';
1
+ import { BaseManager, Terminal, TerminalManager } from '@jupyterlab/services';
2
+ import { ISignal } from '@lumino/signaling';
3
3
  /**
4
- * A class to handle requests to /api/terminals.
5
- * Although this looks similar to a JupyterLab TerminalManager, it is really a class that
6
- * implements the terminal REST API.
4
+ * Interface for Lite terminal manager, supports setting browserContextId.
7
5
  */
8
- export declare class TerminalManager implements ITerminalManager {
6
+ interface ILiteTerminalManager extends Terminal.IManager {
7
+ browsingContextId: string;
8
+ }
9
+ /**
10
+ * Type guard for ILiteTerminalManager.
11
+ */
12
+ export declare function isILiteTerminalManager(obj: Terminal.IManager): obj is ILiteTerminalManager;
13
+ /**
14
+ * A terminal session manager.
15
+ */
16
+ export declare class LiteTerminalManager extends BaseManager implements ILiteTerminalManager {
17
+ /**
18
+ * Construct a new terminal manager.
19
+ */
20
+ constructor(options?: TerminalManager.IOptions);
21
+ /**
22
+ * Set identifier for communicating with service worker.
23
+ */
24
+ set browsingContextId(browsingContextId: string);
25
+ /**
26
+ * A signal emitted when there is a connection failure.
27
+ */
28
+ get connectionFailure(): ISignal<this, Error>;
29
+ connectTo(options: Omit<Terminal.ITerminalConnection.IOptions, 'serverSettings'>): Terminal.ITerminalConnection;
30
+ /**
31
+ * Whether the terminal service is available.
32
+ */
33
+ isAvailable(): boolean;
34
+ /**
35
+ * Test whether the manager is ready.
36
+ */
37
+ get isReady(): boolean;
38
+ /**
39
+ * A promise that fulfills when the manager is ready.
40
+ */
41
+ get ready(): Promise<void>;
42
+ /**
43
+ * Force a refresh of the running terminals.
44
+ *
45
+ * @returns A promise that with the list of running terminals.
46
+ *
47
+ * #### Notes
48
+ * This is intended to be called only in response to a user action,
49
+ * since the manager maintains its internal state.
50
+ */
51
+ refreshRunning(): Promise<void>;
9
52
  /**
10
- * Construct a new TerminalManager object.
53
+ * Create an iterator over the most recent running terminals.
54
+ *
55
+ * @returns A new iterator over the running terminals.
11
56
  */
12
- constructor(wsUrl: string);
57
+ running(): IterableIterator<Terminal.IModel>;
13
58
  /**
14
- * Return whether the named terminal exists.
59
+ * A signal emitted when the running terminals change.
15
60
  */
16
- has(name: string): boolean;
61
+ get runningChanged(): ISignal<this, Terminal.IModel[]>;
17
62
  /**
18
- * List the running terminals.
63
+ * Shut down a terminal session by name.
19
64
  */
20
- listRunning(): Promise<TerminalAPI.IModel[]>;
65
+ shutdown(name: string): Promise<void>;
21
66
  /**
22
- * Shutdown a terminal by name.
67
+ * Shut down all terminal sessions.
68
+ *
69
+ * @returns A promise that resolves when all of the sessions are shut down.
23
70
  */
24
- shutdownTerminal(name: string): Promise<void>;
71
+ shutdownAll(): Promise<void>;
25
72
  /**
26
- * Start a new kernel.
73
+ * Create a new terminal session.
74
+ *
75
+ * @param options - The options used to create the terminal.
76
+ *
77
+ * @returns A promise that resolves with the terminal connection instance.
78
+ *
79
+ * #### Notes
80
+ * The manager `serverSettings` will be used unless overridden in the
81
+ * options.
27
82
  */
28
- startNew(): Promise<TerminalAPI.IModel>;
83
+ startNew(options: Terminal.ITerminal.IOptions): Promise<Terminal.ITerminalConnection>;
84
+ private get _models();
29
85
  private _nextAvailableName;
30
- private _wsUrl;
31
- private _terminals;
86
+ private _browsingContextId?;
87
+ private _connectionFailure;
88
+ private _isReady;
89
+ private _ready;
90
+ private _runningChanged;
91
+ private _terminalConnections;
32
92
  }
93
+ export {};
package/lib/manager.js CHANGED
@@ -1,65 +1,165 @@
1
- // Copyright (c) Jupyter Development Team.
2
- // Distributed under the terms of the Modified BSD License.
3
- import { PageConfig } from '@jupyterlab/coreutils';
4
- import { Terminal } from './terminal';
1
+ import { BaseManager } from '@jupyterlab/services';
2
+ import { Signal } from '@lumino/signaling';
3
+ import { LiteTerminalConnection } from './terminal';
5
4
  /**
6
- * A class to handle requests to /api/terminals.
7
- * Although this looks similar to a JupyterLab TerminalManager, it is really a class that
8
- * implements the terminal REST API.
5
+ * Type guard for ILiteTerminalManager.
9
6
  */
10
- export class TerminalManager {
7
+ export function isILiteTerminalManager(obj) {
8
+ return 'browsingContextId' in obj;
9
+ }
10
+ /**
11
+ * A terminal session manager.
12
+ */
13
+ export class LiteTerminalManager extends BaseManager {
14
+ /**
15
+ * Construct a new terminal manager.
16
+ */
17
+ constructor(options = {}) {
18
+ super(options);
19
+ this._connectionFailure = new Signal(this);
20
+ this._isReady = false;
21
+ this._runningChanged = new Signal(this);
22
+ this._terminalConnections = new Map();
23
+ // Initialize internal data.
24
+ this._ready = (async () => {
25
+ this._isReady = true;
26
+ })();
27
+ }
28
+ /**
29
+ * Set identifier for communicating with service worker.
30
+ */
31
+ set browsingContextId(browsingContextId) {
32
+ console.log('==> LiteTerminalManager browsingContextId', browsingContextId);
33
+ this._browsingContextId = browsingContextId;
34
+ }
35
+ /**
36
+ * A signal emitted when there is a connection failure.
37
+ */
38
+ get connectionFailure() {
39
+ return this._connectionFailure;
40
+ }
41
+ /*
42
+ * Connect to a running terminal.
43
+ *
44
+ * @param options - The options used to connect to the terminal.
45
+ *
46
+ * @returns The new terminal connection instance.
47
+ *
48
+ * #### Notes
49
+ * The manager `serverSettings` will be used.
50
+ */
51
+ connectTo(options) {
52
+ const { model } = options;
53
+ const { name } = model;
54
+ console.log('==> LiteTerminalManager.connectTo', name);
55
+ const { serverSettings } = this;
56
+ const terminal = new LiteTerminalConnection({
57
+ browsingContextId: this._browsingContextId,
58
+ model,
59
+ serverSettings
60
+ });
61
+ terminal.disposed.connect(() => this.shutdown(name));
62
+ return terminal;
63
+ }
11
64
  /**
12
- * Construct a new TerminalManager object.
65
+ * Whether the terminal service is available.
13
66
  */
14
- constructor(wsUrl) {
15
- this._terminals = new Map();
16
- this._wsUrl = wsUrl;
17
- console.log('==> TerminalManager.constructor', this._wsUrl);
67
+ isAvailable() {
68
+ return true;
18
69
  }
19
70
  /**
20
- * Return whether the named terminal exists.
71
+ * Test whether the manager is ready.
21
72
  */
22
- has(name) {
23
- return this._terminals.has(name);
73
+ get isReady() {
74
+ return this._isReady;
24
75
  }
25
76
  /**
26
- * List the running terminals.
77
+ * A promise that fulfills when the manager is ready.
27
78
  */
28
- async listRunning() {
29
- const ret = [...this._terminals.values()].map(terminal => ({
30
- name: terminal.name
31
- }));
32
- return ret;
79
+ get ready() {
80
+ return this._ready;
33
81
  }
34
82
  /**
35
- * Shutdown a terminal by name.
83
+ * Force a refresh of the running terminals.
84
+ *
85
+ * @returns A promise that with the list of running terminals.
86
+ *
87
+ * #### Notes
88
+ * This is intended to be called only in response to a user action,
89
+ * since the manager maintains its internal state.
36
90
  */
37
- async shutdownTerminal(name) {
38
- const terminal = this._terminals.get(name);
91
+ async refreshRunning() {
92
+ this._runningChanged.emit(this._models);
93
+ }
94
+ /**
95
+ * Create an iterator over the most recent running terminals.
96
+ *
97
+ * @returns A new iterator over the running terminals.
98
+ */
99
+ running() {
100
+ return this._models[Symbol.iterator]();
101
+ }
102
+ /**
103
+ * A signal emitted when the running terminals change.
104
+ */
105
+ get runningChanged() {
106
+ return this._runningChanged;
107
+ }
108
+ /**
109
+ * Shut down a terminal session by name.
110
+ */
111
+ async shutdown(name) {
112
+ const terminal = this._terminalConnections.get(name);
39
113
  if (terminal !== undefined) {
40
- console.log('==> TerminalManager.shutdownTerminal', name);
41
- this._terminals.delete(name);
114
+ this._terminalConnections.delete(name);
42
115
  terminal.dispose();
116
+ this.refreshRunning();
43
117
  }
44
118
  }
45
119
  /**
46
- * Start a new kernel.
120
+ * Shut down all terminal sessions.
121
+ *
122
+ * @returns A promise that resolves when all of the sessions are shut down.
123
+ */
124
+ async shutdownAll() {
125
+ await Promise.all(this._models.map(model => this.shutdown(model.name)));
126
+ this.refreshRunning();
127
+ }
128
+ /**
129
+ * Create a new terminal session.
130
+ *
131
+ * @param options - The options used to create the terminal.
132
+ *
133
+ * @returns A promise that resolves with the terminal connection instance.
134
+ *
135
+ * #### Notes
136
+ * The manager `serverSettings` will be used unless overridden in the
137
+ * options.
47
138
  */
48
- async startNew() {
49
- const name = this._nextAvailableName();
50
- console.log('==> TerminalManager.startNew', name);
51
- const baseUrl = PageConfig.getBaseUrl();
52
- const terminal = new Terminal({ name, baseUrl });
53
- this._terminals.set(name, terminal);
54
- terminal.disposed.connect(() => this.shutdownTerminal(name));
55
- const url = `${this._wsUrl}terminals/websocket/${name}`;
56
- await terminal.wsConnect(url);
57
- return { name };
139
+ async startNew(options) {
140
+ var _a;
141
+ const name = (_a = options.name) !== null && _a !== void 0 ? _a : this._nextAvailableName();
142
+ const model = { name };
143
+ const { serverSettings } = this;
144
+ const terminal = new LiteTerminalConnection({
145
+ browsingContextId: this._browsingContextId,
146
+ model,
147
+ serverSettings
148
+ });
149
+ terminal.disposed.connect(() => this.shutdown(name));
150
+ this._terminalConnections.set(name, terminal);
151
+ await this.refreshRunning();
152
+ return terminal;
153
+ }
154
+ get _models() {
155
+ return Array.from(this._terminalConnections, ([name, value]) => {
156
+ return { name };
157
+ });
58
158
  }
59
159
  _nextAvailableName() {
60
160
  for (let i = 1;; ++i) {
61
161
  const name = `${i}`;
62
- if (!this._terminals.has(name)) {
162
+ if (!this._terminalConnections.has(name)) {
63
163
  return name;
64
164
  }
65
165
  }
package/lib/terminal.d.ts CHANGED
@@ -1,24 +1,88 @@
1
+ import { ServerConnection, Terminal } from '@jupyterlab/services';
1
2
  import { ISignal } from '@lumino/signaling';
2
- import { ITerminal } from './tokens';
3
- export declare class Terminal implements ITerminal {
4
- readonly options: ITerminal.IOptions;
3
+ /**
4
+ * An implementation of a terminal interface.
5
+ */
6
+ export declare class LiteTerminalConnection implements Terminal.ITerminalConnection {
5
7
  /**
6
- * Construct a new Terminal.
8
+ * Construct a new terminal session.
9
+ */
10
+ constructor(options: LiteTerminalConnection.IOptions);
11
+ /**
12
+ * The current connection status of the terminal connection.
13
+ */
14
+ get connectionStatus(): Terminal.ConnectionStatus;
15
+ /**
16
+ * A signal emitted when the terminal connection status changes.
17
+ */
18
+ get connectionStatusChanged(): ISignal<this, Terminal.ConnectionStatus>;
19
+ /**
20
+ * Dispose of the resources held by the session.
7
21
  */
8
- constructor(options: ITerminal.IOptions);
9
- private _outputCallback;
10
22
  dispose(): void;
23
+ /**
24
+ * A signal emitted when the session is disposed.
25
+ */
11
26
  get disposed(): ISignal<this, void>;
27
+ /**
28
+ * Test whether the session is disposed.
29
+ */
12
30
  get isDisposed(): boolean;
13
31
  /**
14
- * Get the name of the terminal.
32
+ * A signal emitted when a message is received from the server.
33
+ */
34
+ get messageReceived(): ISignal<Terminal.ITerminalConnection, Terminal.IMessage>;
35
+ /**
36
+ * Get the model for the terminal session.
37
+ */
38
+ get model(): Terminal.IModel;
39
+ /**
40
+ * Get the name of the terminal session.
15
41
  */
16
42
  get name(): string;
17
- wsConnect(url: string): Promise<void>;
18
- private _disposed;
43
+ /**
44
+ * Reconnect to a terminal.
45
+ *
46
+ * #### Notes
47
+ * This may try multiple times to reconnect to a terminal, and will sever
48
+ * any existing connection.
49
+ */
50
+ reconnect(): Promise<void>;
51
+ /**
52
+ * Send a message to the terminal session.
53
+ *
54
+ * #### Notes
55
+ * If the connection is down, the message will be queued for sending when
56
+ * the connection comes back up.
57
+ */
58
+ send(message: Terminal.IMessage): void;
59
+ /**
60
+ * The server settings for the session.
61
+ */
62
+ get serverSettings(): ServerConnection.ISettings;
63
+ /**
64
+ * Shut down the terminal session.
65
+ */
66
+ shutdown(): Promise<void>;
67
+ private _outputCallback;
68
+ /**
69
+ * Handle connection status changes.
70
+ */
71
+ private _updateConnectionStatus;
19
72
  private _isDisposed;
20
- private _server?;
21
- private _socket?;
73
+ private _disposed;
74
+ private _name;
75
+ private _serverSettings;
76
+ private _connectionStatus;
77
+ private _connectionStatusChanged;
78
+ private _messageReceived;
22
79
  private _shell;
23
- private _running;
80
+ }
81
+ export declare namespace LiteTerminalConnection {
82
+ interface IOptions extends Terminal.ITerminalConnection.IOptions {
83
+ /**
84
+ * The ID of the browsing context where the request originated.
85
+ */
86
+ browsingContextId?: string;
87
+ }
24
88
  }