jupyterpack 0.3.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +1 -1
  2. package/lib/document/commands.d.ts +8 -0
  3. package/lib/document/commands.js +76 -0
  4. package/lib/document/iframePanel.d.ts +4 -1
  5. package/lib/document/plugin.d.ts +2 -1
  6. package/lib/document/plugin.js +22 -4
  7. package/lib/document/toolbar.d.ts +9 -0
  8. package/lib/document/toolbar.js +20 -0
  9. package/lib/document/widgetFactory.d.ts +2 -1
  10. package/lib/document/widgetFactory.js +14 -6
  11. package/lib/index.d.ts +1 -1
  12. package/lib/pythonServer/baseServer.d.ts +82 -0
  13. package/lib/pythonServer/baseServer.js +141 -0
  14. package/lib/pythonServer/dash/dashServer.d.ts +5 -17
  15. package/lib/pythonServer/dash/dashServer.js +19 -24
  16. package/lib/pythonServer/index.d.ts +3 -3
  17. package/lib/pythonServer/index.js +5 -1
  18. package/lib/pythonServer/kernelExecutor.d.ts +2 -53
  19. package/lib/pythonServer/kernelExecutor.js +5 -70
  20. package/lib/pythonServer/shiny/shinyServer.d.ts +14 -0
  21. package/lib/pythonServer/shiny/shinyServer.js +49 -0
  22. package/lib/pythonServer/starlette/starletteServer.d.ts +13 -0
  23. package/lib/pythonServer/starlette/starletteServer.js +49 -0
  24. package/lib/pythonServer/streamlit/streamlitServer.d.ts +6 -26
  25. package/lib/pythonServer/streamlit/streamlitServer.js +33 -41
  26. package/lib/pythonServer/tornado/tornadoServer.d.ts +6 -26
  27. package/lib/pythonServer/tornado/tornadoServer.js +28 -36
  28. package/lib/pythonWidget/comm.d.ts +11 -0
  29. package/lib/pythonWidget/comm.js +52 -0
  30. package/lib/pythonWidget/pythonWidget.d.ts +5 -0
  31. package/lib/pythonWidget/pythonWidget.js +19 -0
  32. package/lib/pythonWidget/pythonWidgetModel.d.ts +16 -4
  33. package/lib/pythonWidget/pythonWidgetModel.js +77 -13
  34. package/lib/sandpackWidget/sandpackFilesModel.d.ts +6 -2
  35. package/lib/sandpackWidget/sandpackFilesModel.js +13 -2
  36. package/lib/sandpackWidget/sandpackPanel.d.ts +10 -1
  37. package/lib/sandpackWidget/sandpackPanel.js +38 -3
  38. package/lib/swConnection/mainConnectionManager.d.ts +4 -4
  39. package/lib/swConnection/mainConnectionManager.js +23 -12
  40. package/lib/token.d.ts +2 -1
  41. package/lib/token.js +1 -0
  42. package/lib/tools.d.ts +6 -0
  43. package/lib/tools.js +25 -0
  44. package/lib/type.d.ts +39 -4
  45. package/lib/type.js +2 -0
  46. package/lib/websocket/websocket.js +5 -1
  47. package/package.json +6 -6
  48. package/src/document/commands.ts +91 -0
  49. package/src/document/iframePanel.ts +4 -1
  50. package/src/document/plugin.ts +28 -7
  51. package/src/document/toolbar.ts +39 -0
  52. package/src/document/widgetFactory.ts +16 -6
  53. package/src/global.d.ts +5 -0
  54. package/src/pythonServer/baseServer.ts +245 -0
  55. package/src/pythonServer/dash/dashServer.ts +25 -35
  56. package/src/pythonServer/index.ts +9 -5
  57. package/src/pythonServer/kernelExecutor.ts +8 -147
  58. package/src/pythonServer/shiny/shinyServer.ts +62 -0
  59. package/src/pythonServer/starlette/starletteServer.ts +59 -0
  60. package/src/pythonServer/streamlit/streamlitServer.ts +40 -62
  61. package/src/pythonServer/tornado/tornadoServer.ts +33 -60
  62. package/src/pythonWidget/comm.ts +65 -0
  63. package/src/pythonWidget/pythonWidget.ts +19 -1
  64. package/src/pythonWidget/pythonWidgetModel.ts +107 -20
  65. package/src/sandpackWidget/sandpackFilesModel.ts +17 -3
  66. package/src/sandpackWidget/sandpackPanel.ts +45 -4
  67. package/src/swConnection/mainConnectionManager.ts +28 -20
  68. package/src/token.ts +5 -1
  69. package/src/tools.ts +31 -0
  70. package/src/type.ts +46 -7
  71. package/src/websocket/websocket.ts +9 -1
  72. package/style/base.css +7 -0
  73. package/style/icons/autoreload.svg +16 -0
  74. package/style/icons/box.svg +12 -0
  75. package/style/icons/externallink.svg +10 -0
  76. package/lib/pythonServer/common/generatedPythonFiles.d.ts +0 -2
  77. package/lib/pythonServer/common/generatedPythonFiles.js +0 -72
  78. package/lib/pythonServer/dash/generatedPythonFiles.d.ts +0 -2
  79. package/lib/pythonServer/dash/generatedPythonFiles.js +0 -31
  80. package/lib/pythonServer/streamlit/generatedPythonFiles.d.ts +0 -2
  81. package/lib/pythonServer/streamlit/generatedPythonFiles.js +0 -147
  82. package/lib/pythonServer/tornado/generatedPythonFiles.d.ts +0 -3
  83. package/lib/pythonServer/tornado/generatedPythonFiles.js +0 -456
  84. package/src/pythonServer/common/generatedPythonFiles.ts +0 -73
  85. package/src/pythonServer/dash/generatedPythonFiles.ts +0 -32
  86. package/src/pythonServer/streamlit/generatedPythonFiles.ts +0 -148
  87. package/src/pythonServer/tornado/generatedPythonFiles.ts +0 -457
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  ## Features
9
9
 
10
- - **Python Web Apps**: Serve Python web applications directly in the browser using JupyterLite's in-browser Python kernel. `jupyterpack` currently supports Dash.
10
+ - **Python Web Apps**: Serve Python web applications directly in the browser using JupyterLite's in-browser Python kernel. `jupyterpack` currently supports Dash and Streamlit.
11
11
  - **JavaScript Web Apps**: Bundle and serve JavaScript web applications using in-browser bundlers.
12
12
 
13
13
  ![Image](https://github.com/user-attachments/assets/22849fe8-199f-4d9f-ad45-055bccf88bad)
@@ -0,0 +1,8 @@
1
+ import { CommandRegistry } from '@lumino/commands';
2
+ import { IJupyterpackDocTracker } from '../type';
3
+ export declare const CommandIDs: {
4
+ RELOAD: string;
5
+ TOGGLE_AUTORELOAD: string;
6
+ OPEN_SPECTA: string;
7
+ };
8
+ export declare function addCommands(commands: CommandRegistry, tracker: IJupyterpackDocTracker): void;
@@ -0,0 +1,76 @@
1
+ import { refreshIcon } from '@jupyterlab/ui-components';
2
+ import { autoReloadIcon, linkIcon } from '../tools';
3
+ import { PageConfig, URLExt } from '@jupyterlab/coreutils';
4
+ export const CommandIDs = {
5
+ RELOAD: 'jupyterpack:reload',
6
+ TOGGLE_AUTORELOAD: 'jupyterpack:toggleAutoreload',
7
+ OPEN_SPECTA: 'jupyterpack:openInSpecta'
8
+ };
9
+ const labBaseUrl = PageConfig.getOption('baseUrl');
10
+ function getCurrentIframPanel(tracker) {
11
+ var _a;
12
+ const current = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.content;
13
+ if (!current) {
14
+ return;
15
+ }
16
+ const widget = current.widgets[0];
17
+ if (!widget) {
18
+ return;
19
+ }
20
+ return widget;
21
+ }
22
+ export function addCommands(commands, tracker) {
23
+ commands.addCommand(CommandIDs.RELOAD, {
24
+ caption: 'Reload',
25
+ isEnabled: () => {
26
+ return tracker.currentWidget !== null;
27
+ },
28
+ icon: refreshIcon,
29
+ execute: async () => {
30
+ const widget = getCurrentIframPanel(tracker);
31
+ if (widget) {
32
+ await widget.reload();
33
+ }
34
+ }
35
+ });
36
+ const commandState = { toggled: false };
37
+ commands.addCommand(CommandIDs.TOGGLE_AUTORELOAD, {
38
+ isEnabled: () => {
39
+ return tracker.currentWidget !== null;
40
+ },
41
+ isToggled: () => {
42
+ const widget = getCurrentIframPanel(tracker);
43
+ return Boolean(widget === null || widget === void 0 ? void 0 : widget.autoreload);
44
+ },
45
+ icon: autoReloadIcon,
46
+ caption: e => {
47
+ return commandState.toggled
48
+ ? 'Auto-reload enabled'
49
+ : 'Auto-reload disabled';
50
+ },
51
+ execute: async () => {
52
+ const widget = getCurrentIframPanel(tracker);
53
+ if (widget) {
54
+ widget.autoreload = !(widget === null || widget === void 0 ? void 0 : widget.autoreload);
55
+ commands.notifyCommandChanged(CommandIDs.TOGGLE_AUTORELOAD);
56
+ }
57
+ }
58
+ });
59
+ commands.addCommand(CommandIDs.OPEN_SPECTA, {
60
+ caption: 'Open in Specta',
61
+ isEnabled: () => {
62
+ return tracker.currentWidget !== null;
63
+ },
64
+ icon: linkIcon,
65
+ execute: async () => {
66
+ var _a;
67
+ const context = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.context;
68
+ if (!context) {
69
+ return;
70
+ }
71
+ const spectaUrl = new URL(URLExt.join(labBaseUrl, 'specta'), window.location.origin);
72
+ spectaUrl.searchParams.set('path', context.path);
73
+ window.open(spectaUrl.toString(), '_blank');
74
+ }
75
+ });
76
+ }
@@ -1,7 +1,10 @@
1
1
  import { Widget } from '@lumino/widgets';
2
- export declare class IFramePanel extends Widget {
2
+ export declare abstract class IFramePanel extends Widget {
3
3
  constructor();
4
4
  toggleSpinner(show: boolean): void;
5
+ abstract reload(): Promise<void>;
6
+ abstract autoreload: boolean;
7
+ abstract isReady: Promise<void>;
5
8
  protected _iframe: HTMLIFrameElement;
6
9
  protected _spinner: HTMLDivElement;
7
10
  }
@@ -1,2 +1,3 @@
1
1
  import { JupyterFrontEndPlugin } from '@jupyterlab/application';
2
- export declare const spkPlugin: JupyterFrontEndPlugin<void>;
2
+ import { IJupyterpackDocTracker } from '../type';
3
+ export declare const spkPlugin: JupyterFrontEndPlugin<IJupyterpackDocTracker>;
@@ -1,12 +1,20 @@
1
1
  import { JupyterPackWidgetFactory } from './widgetFactory';
2
- import { IConnectionManagerToken } from '../token';
2
+ import { IConnectionManagerToken, IJupyterpackDocTrackerToken } from '../token';
3
+ import { WidgetTracker } from '@jupyterlab/apputils';
4
+ import { logoIcon } from '../tools';
5
+ import { addCommands } from './commands';
3
6
  const FACTORY = 'jupyterpack';
4
7
  const CONTENT_TYPE = 'jupyterpack';
5
8
  export const spkPlugin = {
6
9
  id: 'jupyterpack:spkplugin',
7
10
  requires: [IConnectionManagerToken],
8
11
  autoStart: true,
12
+ provides: IJupyterpackDocTrackerToken,
9
13
  activate: (app, connectionManager) => {
14
+ const tracker = new WidgetTracker({
15
+ namespace: FACTORY
16
+ });
17
+ addCommands(app.commands, tracker);
10
18
  const widgetFactory = new JupyterPackWidgetFactory({
11
19
  name: FACTORY,
12
20
  modelName: 'text',
@@ -14,7 +22,8 @@ export const spkPlugin = {
14
22
  defaultFor: [CONTENT_TYPE],
15
23
  commands: app.commands,
16
24
  manager: app.serviceManager,
17
- connectionManager
25
+ connectionManager,
26
+ tracker
18
27
  });
19
28
  // Registering the widget factory
20
29
  app.docRegistry.addWidgetFactory(widgetFactory);
@@ -22,10 +31,19 @@ export const spkPlugin = {
22
31
  app.docRegistry.addFileType({
23
32
  name: CONTENT_TYPE,
24
33
  displayName: 'SPK',
25
- mimeTypes: ['text/json'],
34
+ mimeTypes: ['application/json'],
26
35
  extensions: ['.spk', '.SPK'],
27
36
  fileFormat: 'json',
28
- contentType: CONTENT_TYPE
37
+ contentType: CONTENT_TYPE,
38
+ icon: logoIcon
39
+ });
40
+ widgetFactory.widgetCreated.connect((_, widget) => {
41
+ widget.title.icon = logoIcon;
42
+ widget.context.pathChanged.connect(() => {
43
+ tracker.save(widget);
44
+ });
45
+ tracker.add(widget);
29
46
  });
47
+ return tracker;
30
48
  }
31
49
  };
@@ -0,0 +1,9 @@
1
+ import { ReactiveToolbar } from '@jupyterlab/ui-components';
2
+ import { CommandRegistry } from '@lumino/commands';
3
+ import { IJupyterpackDocTracker } from '../type';
4
+ export declare class ToolbarWidget extends ReactiveToolbar {
5
+ constructor(options: {
6
+ tracker: IJupyterpackDocTracker;
7
+ commands: CommandRegistry;
8
+ });
9
+ }
@@ -0,0 +1,20 @@
1
+ import { CommandToolbarButton, ReactiveToolbar } from '@jupyterlab/ui-components';
2
+ import { CommandIDs } from './commands';
3
+ export class ToolbarWidget extends ReactiveToolbar {
4
+ constructor(options) {
5
+ super();
6
+ this.addClass('jupyterpack-toolbar');
7
+ this.addItem('Reload', new CommandToolbarButton({
8
+ commands: options.commands,
9
+ id: CommandIDs.RELOAD
10
+ }));
11
+ this.addItem('Toggle Auto Reload', new CommandToolbarButton({
12
+ id: CommandIDs.TOGGLE_AUTORELOAD,
13
+ commands: options.commands
14
+ }));
15
+ this.addItem('Open Specta', new CommandToolbarButton({
16
+ id: CommandIDs.OPEN_SPECTA,
17
+ commands: options.commands
18
+ }));
19
+ }
20
+ }
@@ -1,12 +1,13 @@
1
1
  import { ABCWidgetFactory, DocumentRegistry } from '@jupyterlab/docregistry';
2
2
  import { ServiceManager } from '@jupyterlab/services';
3
3
  import { CommandRegistry } from '@lumino/commands';
4
- import { IConnectionManager } from '../type';
4
+ import { IConnectionManager, IJupyterpackDocTracker } from '../type';
5
5
  import { JupyterPackDocWidget } from './jupyterpackDocWidget';
6
6
  interface IOptions extends DocumentRegistry.IWidgetFactoryOptions {
7
7
  commands: CommandRegistry;
8
8
  manager: ServiceManager.IManager;
9
9
  connectionManager: IConnectionManager;
10
+ tracker: IJupyterpackDocTracker;
10
11
  }
11
12
  export declare class JupyterPackWidgetFactory extends ABCWidgetFactory<JupyterPackDocWidget> {
12
13
  private options;
@@ -1,11 +1,12 @@
1
1
  import { ABCWidgetFactory } from '@jupyterlab/docregistry';
2
+ import { UUID } from '@lumino/coreutils';
2
3
  import { Panel } from '@lumino/widgets';
3
- import { JupyterPackFramework } from '../type';
4
+ import { PythonWidget } from '../pythonWidget/pythonWidget';
5
+ import { PythonWidgetModel } from '../pythonWidget/pythonWidgetModel';
4
6
  import { SandpackPanel } from '../sandpackWidget/sandpackPanel';
7
+ import { JupyterPackFramework } from '../type';
5
8
  import { JupyterPackDocWidget } from './jupyterpackDocWidget';
6
- import { PythonWidgetModel } from '../pythonWidget/pythonWidgetModel';
7
- import { UUID } from '@lumino/coreutils';
8
- import { PythonWidget } from '../pythonWidget/pythonWidget';
9
+ import { ToolbarWidget } from './toolbar';
9
10
  export class JupyterPackWidgetFactory extends ABCWidgetFactory {
10
11
  constructor(options) {
11
12
  super(options);
@@ -34,7 +35,9 @@ export class JupyterPackWidgetFactory extends ABCWidgetFactory {
34
35
  }
35
36
  case JupyterPackFramework.DASH:
36
37
  case JupyterPackFramework.STREAMLIT:
37
- case JupyterPackFramework.TORNADO: {
38
+ case JupyterPackFramework.TORNADO:
39
+ case JupyterPackFramework.STARLETTE:
40
+ case JupyterPackFramework.SHINY: {
38
41
  const model = new PythonWidgetModel({
39
42
  jpackModel,
40
43
  context,
@@ -55,9 +58,14 @@ export class JupyterPackWidgetFactory extends ABCWidgetFactory {
55
58
  }
56
59
  }
57
60
  });
61
+ const toolbar = new ToolbarWidget({
62
+ tracker: this.options.tracker,
63
+ commands: this.options.commands
64
+ });
58
65
  return new JupyterPackDocWidget({
59
66
  context,
60
- content
67
+ content,
68
+ toolbar
61
69
  });
62
70
  }
63
71
  }
package/lib/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- declare const _default: (import("@jupyterlab/application").JupyterFrontEndPlugin<void> | import("@jupyterlab/application").JupyterFrontEndPlugin<import("./type").IConnectionManager>)[];
1
+ declare const _default: (import("@jupyterlab/application").JupyterFrontEndPlugin<import("./type").IJupyterpackDocTracker> | import("@jupyterlab/application").JupyterFrontEndPlugin<import("./type").IConnectionManager>)[];
2
2
  export default _default;
@@ -0,0 +1,82 @@
1
+ import { KernelExecutor } from './kernelExecutor';
2
+ import { IDict, IBasePythonServer, IKernelExecutor, JupyterPackFramework } from '../type';
3
+ export declare abstract class BasePythonServer implements IBasePythonServer {
4
+ constructor(options: KernelExecutor.IOptions);
5
+ abstract reloadPythonServer(options: {
6
+ entryPath?: string;
7
+ initCode?: string;
8
+ }): Promise<void>;
9
+ get isDisposed(): boolean;
10
+ get kernelExecutor(): IKernelExecutor;
11
+ dispose(): void;
12
+ init(options: {
13
+ entryPath?: string;
14
+ initCode?: string;
15
+ instanceId: string;
16
+ kernelClientId: string;
17
+ }): Promise<void>;
18
+ disposePythonServer(): Promise<void>;
19
+ getResponseFunctionFactory(options: {
20
+ urlPath: string;
21
+ method: string;
22
+ headers: IDict;
23
+ params?: string;
24
+ content?: string;
25
+ }): string;
26
+ openWebsocketFunctionFactory(options: {
27
+ instanceId: string;
28
+ kernelId: string;
29
+ wsUrl: string;
30
+ protocol?: string;
31
+ }): string;
32
+ closeWebsocketFunctionFactory(options: {
33
+ instanceId: string;
34
+ kernelId: string;
35
+ wsUrl: string;
36
+ }): string;
37
+ sendWebsocketMessageFunctionFactory(options: {
38
+ instanceId: string;
39
+ kernelId: string;
40
+ wsUrl: string;
41
+ message: string;
42
+ }): string;
43
+ openWebsocket(options: {
44
+ instanceId: string;
45
+ kernelId: string;
46
+ wsUrl: string;
47
+ protocol?: string;
48
+ }): Promise<void>;
49
+ closeWebsocket(options: {
50
+ instanceId: string;
51
+ kernelId: string;
52
+ wsUrl: string;
53
+ }): Promise<void>;
54
+ sendWebsocketMessage(options: {
55
+ instanceId: string;
56
+ kernelId: string;
57
+ wsUrl: string;
58
+ message: string;
59
+ }): Promise<void>;
60
+ getResponse(options: {
61
+ method: string;
62
+ urlPath: string;
63
+ headers: IDict;
64
+ requestBody?: ArrayBuffer;
65
+ params?: string;
66
+ }): Promise<IDict>;
67
+ protected buildBaseURL(options: {
68
+ instanceId: string;
69
+ kernelClientId: string;
70
+ framework: JupyterPackFramework;
71
+ }): string;
72
+ protected _baseUrl: string | undefined;
73
+ protected readonly _openedWebsockets: {
74
+ instanceId: string;
75
+ kernelId: string;
76
+ wsUrl: string;
77
+ }[];
78
+ protected readonly _server_var = "__jupyterpack_python_server";
79
+ private _kernelExecutor;
80
+ private _isDisposed;
81
+ private _wsPatch;
82
+ }
@@ -0,0 +1,141 @@
1
+ import { KernelExecutor } from './kernelExecutor';
2
+ import websocketPatch from '../websocket/websocket.js?raw';
3
+ import { PageConfig, URLExt } from '@jupyterlab/coreutils';
4
+ import { arrayBufferToBase64, base64ToArrayBuffer, base64ToString, isBinaryContentType, stringOrNone } from '../tools';
5
+ export class BasePythonServer {
6
+ constructor(options) {
7
+ this._openedWebsockets = [];
8
+ this._server_var = '__jupyterpack_python_server';
9
+ this._isDisposed = false;
10
+ this._kernelExecutor = new KernelExecutor(options);
11
+ this._wsPatch = websocketPatch.replaceAll('"use strict";', '');
12
+ }
13
+ get isDisposed() {
14
+ return this._isDisposed;
15
+ }
16
+ get kernelExecutor() {
17
+ return this._kernelExecutor;
18
+ }
19
+ dispose() {
20
+ if (this._isDisposed) {
21
+ return;
22
+ }
23
+ this._isDisposed = true;
24
+ this.disposePythonServer()
25
+ .then(() => {
26
+ this._kernelExecutor.dispose();
27
+ })
28
+ .catch(console.error);
29
+ }
30
+ async init(options) {
31
+ const patchCode = `
32
+ from jupyterpack.common import patch_all
33
+ patch_all()
34
+ `;
35
+ await this._kernelExecutor.executeCode({ code: patchCode });
36
+ }
37
+ async disposePythonServer() {
38
+ await this.kernelExecutor.executeCode({
39
+ code: `${this._server_var}.dispose()`
40
+ });
41
+ for (const element of this._openedWebsockets) {
42
+ await this.closeWebsocket(element);
43
+ }
44
+ }
45
+ getResponseFunctionFactory(options) {
46
+ const { method, urlPath, headers, params, content } = options;
47
+ const code = `await ${this._server_var}.get_response("${method}", "${urlPath}", headers=${JSON.stringify(headers)} , content=${stringOrNone(content)}, params=${stringOrNone(params)})`;
48
+ return code;
49
+ }
50
+ openWebsocketFunctionFactory(options) {
51
+ const { instanceId, kernelId, wsUrl, protocol } = options;
52
+ const code = `await ${this._server_var}.open_ws("${instanceId}", "${kernelId}", "${wsUrl}", ${stringOrNone(protocol)})`;
53
+ return code;
54
+ }
55
+ closeWebsocketFunctionFactory(options) {
56
+ const { instanceId, kernelId, wsUrl } = options;
57
+ const code = `await ${this._server_var}.close_ws("${instanceId}", "${kernelId}", "${wsUrl}")`;
58
+ return code;
59
+ }
60
+ sendWebsocketMessageFunctionFactory(options) {
61
+ const { instanceId, kernelId, wsUrl, message } = options;
62
+ const code = `await ${this._server_var}.receive_ws_message("${instanceId}", "${kernelId}", "${wsUrl}", '''${message}''')`;
63
+ return code;
64
+ }
65
+ async openWebsocket(options) {
66
+ const code = this.openWebsocketFunctionFactory(options);
67
+ if (code) {
68
+ try {
69
+ await this._kernelExecutor.executeCode({ code });
70
+ this._openedWebsockets.push(options);
71
+ }
72
+ catch (e) {
73
+ console.error('Failed to open websocket', e);
74
+ }
75
+ }
76
+ else {
77
+ throw new Error('Missing websocket open code');
78
+ }
79
+ }
80
+ async closeWebsocket(options) {
81
+ const code = this.closeWebsocketFunctionFactory(options);
82
+ if (code) {
83
+ await this._kernelExecutor.executeCode({ code });
84
+ }
85
+ else {
86
+ throw new Error('Missing websocket close code');
87
+ }
88
+ }
89
+ async sendWebsocketMessage(options) {
90
+ const code = this.sendWebsocketMessageFunctionFactory(options);
91
+ if (code) {
92
+ await this._kernelExecutor.executeCode({ code });
93
+ }
94
+ else {
95
+ throw new Error('Missing websocket send code');
96
+ }
97
+ }
98
+ async getResponse(options) {
99
+ var _a;
100
+ const { method, urlPath, requestBody, params, headers } = options;
101
+ const content = requestBody ? arrayBufferToBase64(requestBody) : undefined;
102
+ const code = this.getResponseFunctionFactory({
103
+ method,
104
+ urlPath,
105
+ headers,
106
+ params,
107
+ content
108
+ });
109
+ const raw = await this._kernelExecutor.executeCode({ code }, true);
110
+ if (!raw) {
111
+ throw new Error(`Missing response for ${urlPath}`);
112
+ }
113
+ const jsonStr = raw.replaceAll("'", '');
114
+ const obj = JSON.parse(jsonStr);
115
+ const responseHeaders = JSON.parse(atob(obj.headers));
116
+ const contentType = (_a = responseHeaders === null || responseHeaders === void 0 ? void 0 : responseHeaders['Content-Type']) !== null && _a !== void 0 ? _a : responseHeaders === null || responseHeaders === void 0 ? void 0 : responseHeaders['content-type'];
117
+ let responseContent;
118
+ if (isBinaryContentType(contentType)) {
119
+ responseContent = base64ToArrayBuffer(obj.content);
120
+ }
121
+ else {
122
+ responseContent = base64ToString(obj.content);
123
+ }
124
+ if (contentType && contentType.toLowerCase().includes('text/html')) {
125
+ responseContent = responseContent.replace('<head>', `<head>\n<script>\n${this._wsPatch}\n</script>\n`);
126
+ }
127
+ const decodedObj = {
128
+ status_code: obj.status_code,
129
+ headers: responseHeaders,
130
+ content: responseContent
131
+ };
132
+ return decodedObj;
133
+ }
134
+ buildBaseURL(options) {
135
+ const { instanceId, kernelClientId, framework } = options;
136
+ const fullLabextensionsUrl = PageConfig.getOption('fullLabextensionsUrl');
137
+ const baseURL = URLExt.join(fullLabextensionsUrl, 'jupyterpack/static', instanceId, framework, kernelClientId, '/');
138
+ this._baseUrl = baseURL;
139
+ return baseURL;
140
+ }
141
+ }
@@ -1,24 +1,12 @@
1
- import { IDict } from '../../type';
2
- import { KernelExecutor } from '../kernelExecutor';
3
- export declare class DashServer extends KernelExecutor {
1
+ import { BasePythonServer } from '../baseServer';
2
+ export declare class DashServer extends BasePythonServer {
4
3
  init(options: {
5
4
  initCode?: string;
6
5
  instanceId: string;
7
6
  kernelClientId: string;
8
7
  }): Promise<void>;
9
- getResponseFunctionFactory(options: {
10
- urlPath: string;
11
- method: string;
12
- headers: IDict;
13
- params?: string;
14
- content?: string;
15
- }): string;
16
- disposePythonServer(): Promise<void>;
17
- openWebsocket(options: {
18
- instanceId: string;
19
- kernelId: string;
20
- wsUrl: string;
21
- protocol?: string;
8
+ reloadPythonServer(options: {
9
+ entryPath?: string;
10
+ initCode?: string;
22
11
  }): Promise<void>;
23
- private DASH_GET_RESPONSE_FUNCTION;
24
12
  }
@@ -1,13 +1,6 @@
1
- import { stringOrNone } from '../../tools';
2
1
  import { JupyterPackFramework } from '../../type';
3
- import { patch } from '../common/generatedPythonFiles';
4
- import { KernelExecutor } from '../kernelExecutor';
5
- import { bootstrap, dashLoader } from './generatedPythonFiles';
6
- export class DashServer extends KernelExecutor {
7
- constructor() {
8
- super(...arguments);
9
- this.DASH_GET_RESPONSE_FUNCTION = '__jupyterpack_dash_get_response';
10
- }
2
+ import { BasePythonServer } from '../baseServer';
3
+ export class DashServer extends BasePythonServer {
11
4
  async init(options) {
12
5
  await super.init(options);
13
6
  const { initCode, instanceId, kernelClientId } = options;
@@ -16,24 +9,26 @@ export class DashServer extends KernelExecutor {
16
9
  kernelClientId,
17
10
  framework: JupyterPackFramework.DASH
18
11
  });
19
- await this.executeCode({ code: patch });
20
- await this.executeCode({
21
- code: bootstrap.replaceAll('{{base_url}}', baseURL)
12
+ await this.kernelExecutor.executeCode({
13
+ code: `
14
+ import os
15
+ os.environ["DASH_URL_BASE_PATHNAME"] = "${baseURL}"
16
+ `
22
17
  });
23
18
  if (initCode) {
24
- await this.executeCode({ code: initCode });
19
+ await this.kernelExecutor.executeCode({ code: initCode });
25
20
  }
26
- await this.executeCode({ code: dashLoader });
27
- }
28
- getResponseFunctionFactory(options) {
29
- const { method, urlPath, headers, params, content } = options;
30
- const code = `${this.DASH_GET_RESPONSE_FUNCTION}("${method}", "${urlPath}", headers=${JSON.stringify(headers)} , content=${stringOrNone(content)}, params=${stringOrNone(params)})`;
31
- return code;
32
- }
33
- async disposePythonServer() {
34
- //no-op
21
+ const loaderCode = `
22
+ from jupyterpack.dash import DashServer
23
+ ${this._server_var} = DashServer(app, "${baseURL}")
24
+ `;
25
+ await this.kernelExecutor.executeCode({ code: loaderCode });
35
26
  }
36
- async openWebsocket(options) {
37
- //no-op
27
+ async reloadPythonServer(options) {
28
+ const { initCode } = options;
29
+ if (initCode) {
30
+ await this.kernelExecutor.executeCode({ code: initCode });
31
+ }
32
+ await this.kernelExecutor.executeCode({ code: `${this._server_var}.reload(app)` }, true);
38
33
  }
39
34
  }
@@ -1,5 +1,5 @@
1
- import { IKernelExecutor, JupyterPackFramework } from '../type';
1
+ import { IBasePythonServer, JupyterPackFramework } from '../type';
2
2
  import { KernelExecutor } from './kernelExecutor';
3
- type KernelExecutorConstructor = new (options: KernelExecutor.IOptions) => IKernelExecutor;
4
- export declare const PYTHON_SERVER: Map<JupyterPackFramework, KernelExecutorConstructor>;
3
+ type BasePythonServerConstructor = new (options: KernelExecutor.IOptions) => IBasePythonServer;
4
+ export declare const PYTHON_SERVER: Map<JupyterPackFramework, BasePythonServerConstructor>;
5
5
  export {};
@@ -1,9 +1,13 @@
1
1
  import { JupyterPackFramework } from '../type';
2
2
  import { DashServer } from './dash/dashServer';
3
+ import { ShinyServer } from './shiny/shinyServer';
4
+ import { StarletteServer } from './starlette/starletteServer';
3
5
  import { StreamlitServer } from './streamlit/streamlitServer';
4
6
  import { TornadoServer } from './tornado/tornadoServer';
5
7
  export const PYTHON_SERVER = new Map([
6
8
  [JupyterPackFramework.DASH, DashServer],
7
9
  [JupyterPackFramework.STREAMLIT, StreamlitServer],
8
- [JupyterPackFramework.TORNADO, TornadoServer]
10
+ [JupyterPackFramework.TORNADO, TornadoServer],
11
+ [JupyterPackFramework.SHINY, ShinyServer],
12
+ [JupyterPackFramework.STARLETTE, StarletteServer]
9
13
  ]);
@@ -1,63 +1,12 @@
1
1
  import { KernelMessage, Session } from '@jupyterlab/services';
2
- import { IDict, IKernelExecutor, JupyterPackFramework } from '../type';
3
- export declare abstract class KernelExecutor implements IKernelExecutor {
2
+ import { IKernelExecutor } from '../type';
3
+ export declare class KernelExecutor implements IKernelExecutor {
4
4
  constructor(options: KernelExecutor.IOptions);
5
5
  get isDisposed(): boolean;
6
- abstract disposePythonServer(): Promise<void>;
7
- abstract getResponseFunctionFactory(options: {
8
- urlPath: string;
9
- method: string;
10
- headers: IDict;
11
- params?: string;
12
- content?: string;
13
- }): string;
14
- init(options: {
15
- entryPath?: string;
16
- initCode?: string;
17
- instanceId: string;
18
- kernelClientId: string;
19
- }): Promise<void>;
20
- openWebsocketFunctionFactory(options: {
21
- instanceId: string;
22
- kernelId: string;
23
- wsUrl: string;
24
- protocol?: string;
25
- }): string | undefined;
26
- sendWebsocketMessageFunctionFactory(options: {
27
- instanceId: string;
28
- kernelId: string;
29
- wsUrl: string;
30
- message: string;
31
- }): string | undefined;
32
- openWebsocket(options: {
33
- instanceId: string;
34
- kernelId: string;
35
- wsUrl: string;
36
- protocol?: string;
37
- }): Promise<void>;
38
- sendWebsocketMessage(options: {
39
- instanceId: string;
40
- kernelId: string;
41
- wsUrl: string;
42
- message: string;
43
- }): Promise<void>;
44
- getResponse(options: {
45
- method: string;
46
- urlPath: string;
47
- headers: IDict;
48
- requestBody?: ArrayBuffer;
49
- params?: string;
50
- }): Promise<IDict>;
51
6
  executeCode(code: KernelMessage.IExecuteRequestMsg['content'], waitForResult?: boolean): Promise<string | null>;
52
7
  dispose(): void;
53
- protected buildBaseURL(options: {
54
- instanceId: string;
55
- kernelClientId: string;
56
- framework: JupyterPackFramework;
57
- }): string;
58
8
  private _isDisposed;
59
9
  private _sessionConnection;
60
- private _wsPatch;
61
10
  }
62
11
  export declare namespace KernelExecutor {
63
12
  interface IOptions {