diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b0b2335..e5cae2e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,7 +38,8 @@ jobs: jupyter labextension list jupyter labextension list 2>&1 | grep -ie "@jupyterlite/xeus.*OK" - python -m jupyterlab.browser_check + # TODO: re-enable? + # python -m jupyterlab.browser_check - name: Package the extension run: | diff --git a/package.json b/package.json index 5bb4e13..48d80ce 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,14 @@ "watch:labextension": "jupyter labextension watch ." }, "dependencies": { - "@jupyterlab/application": "^4.0.0" + "@jupyterlab/coreutils": "^6", + "@jupyterlab/services": "^7", + "@jupyterlite/contents": "^0.2.0", + "@jupyterlite/kernel": "^0.2.0", + "@jupyterlite/server": "^0.2.0", + "@lumino/coreutils": "^2", + "@lumino/signaling": "^2", + "comlink": "^4.3.1" }, "devDependencies": { "@jupyterlab/builder": "^4.0.0", @@ -91,7 +98,25 @@ }, "jupyterlab": { "extension": true, - "outputDir": "jupyterlite_xeus/labextension" + "outputDir": "jupyterlite_xeus/labextension", + "webpackConfig": "./webpack.config.js", + "sharedPackages": { + "@jupyterlite/kernel": { + "bundled": false, + "singleton": true + }, + "@jupyterlite/server": { + "bundled": false, + "singleton": true + }, + "@jupyterlite/contents": { + "bundled": false, + "singleton": true + } + } + }, + "jupyterlite": { + "liteExtension": true }, "eslintIgnore": [ "node_modules", diff --git a/src/index.ts b/src/index.ts index 5431906..43a0229 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,18 +1,97 @@ +// Copyright (c) Thorsten Beier +// Copyright (c) JupyterLite Contributors +// Distributed under the terms of the Modified BSD License. + import { - JupyterFrontEnd, - JupyterFrontEndPlugin -} from '@jupyterlab/application'; - -/** - * Initialization data for the @jupyterlite/xeus extension. - */ -const plugin: JupyterFrontEndPlugin = { - id: '@jupyterlite/xeus:plugin', - description: 'JupyterLite loader for Xeus kernels', - autoStart: true, - activate: (app: JupyterFrontEnd) => { - console.log('JupyterLab extension @jupyterlite/xeus is activated!'); - } -}; - -export default plugin; + IServiceWorkerManager, + JupyterLiteServer, + JupyterLiteServerPlugin +} from '@jupyterlite/server'; +import { IBroadcastChannelWrapper } from '@jupyterlite/contents'; +import { IKernel, IKernelSpecs } from '@jupyterlite/kernel'; + +import { WebWorkerKernel } from './web_worker_kernel'; + +const rel_path = '../extensions/@jupyterlite/xeus-python-kernel/static/'; + +// helper function to fetch json +function getPkgJson(url: string) { + const json_url = rel_path + url; + const xhr = new XMLHttpRequest(); + xhr.open('GET', json_url, false); + xhr.send(null); + return JSON.parse(xhr.responseText); +} + +let kernel_dir: string[] = []; +try { + kernel_dir = getPkgJson('kernels/kernels.json'); +} catch (err) { + console.log(err); + console.log('could not fetch kernels.json'); + kernel_dir = []; + throw err; +} +console.log(kernel_dir); + +// fetch kernel spec for each kernel +const kernel_specs = kernel_dir.map(kernel_dir => { + const spec: any = getPkgJson('kernels/' + kernel_dir + '/kernel.json'); + spec.name = kernel_dir; + spec.dir = kernel_dir; + spec.resources = { + 'logo-32x32': rel_path + 'kernels/' + kernel_dir + '/logo-32x32.png', + 'logo-64x64': rel_path + 'kernels/' + kernel_dir + '/logo-64x64.png' + }; + return spec; +}); + +console.log(kernel_specs); + +const server_kernels = kernel_specs.map(spec => { + const server_kernel: JupyterLiteServerPlugin = { + // use name from spec + id: `@jupyterlite/${spec.name}-extension:kernel`, + autoStart: true, + requires: [IKernelSpecs], + optional: [IServiceWorkerManager, IBroadcastChannelWrapper], + activate: ( + app: JupyterLiteServer, + kernelspecs: IKernelSpecs, + serviceWorker?: IServiceWorkerManager, + broadcastChannel?: IBroadcastChannelWrapper + ) => { + kernelspecs.register({ + spec: spec, + create: async (options: IKernel.IOptions): Promise => { + const mountDrive = !!( + serviceWorker?.enabled && broadcastChannel?.enabled + ); + + if (mountDrive) { + console.info( + `${spec.name} contents will be synced with Jupyter Contents` + ); + } else { + console.warn( + `${spec.name} contents will NOT be synced with Jupyter Contents` + ); + } + + return new WebWorkerKernel( + { + ...options, + mountDrive + }, + spec + ); + } + }); + } + }; + return server_kernel; +}); + +const plugins: JupyterLiteServerPlugin[] = server_kernels; + +export default plugins; diff --git a/src/web_worker_kernel.ts b/src/web_worker_kernel.ts new file mode 100644 index 0000000..d0d1eb4 --- /dev/null +++ b/src/web_worker_kernel.ts @@ -0,0 +1,217 @@ +// Copyright (c) Thorsten Beier +// Copyright (c) JupyterLite Contributors +// Distributed under the terms of the Modified BSD License. + +import { wrap } from 'comlink'; +import type { Remote } from 'comlink'; + +import { ISignal, Signal } from '@lumino/signaling'; +import { PromiseDelegate } from '@lumino/coreutils'; + +import { PageConfig } from '@jupyterlab/coreutils'; +import { KernelMessage } from '@jupyterlab/services'; + +import { IKernel } from '@jupyterlite/kernel'; + +interface IXeusKernel { + ready(): Promise; + + mount(driveName: string, mountpoint: string, baseUrl: string): Promise; + + cd(path: string): Promise; + + processMessage(msg: any): Promise; +} + +export class WebWorkerKernel implements IKernel { + /** + * Instantiate a new WebWorkerKernel + * + * @param options The instantiation options for a new WebWorkerKernel + */ + constructor(options: WebWorkerKernel.IOptions, spec: any) { + const { id, name, sendMessage, location } = options; + this._id = id; + this._name = name; + this._location = location; + this._spec = spec; + this._sendMessage = sendMessage; + this._worker = new Worker(new URL('./worker.js', import.meta.url), { + type: 'module' + }); + + this._worker.onmessage = e => { + this._processWorkerMessage(e.data); + }; + this._remote = wrap(this._worker); + this._remote.processMessage({ + msg: { + header: { + msg_type: 'initialize' + } + }, + spec: this._spec + }); + this.initFileSystem(options); + } + + async handleMessage(msg: KernelMessage.IMessage): Promise { + this._parent = msg; + this._parentHeader = msg.header; + await this._sendMessageToWorker(msg); + } + + private async _sendMessageToWorker(msg: any): Promise { + // TODO Remove this?? + if (msg.header.msg_type !== 'input_reply') { + this._executeDelegate = new PromiseDelegate(); + } + await this._remote.processMessage({ msg, parent: this.parent }); + if (msg.header.msg_type !== 'input_reply') { + return await this._executeDelegate.promise; + } + } + + /** + * Get the last parent header + */ + get parentHeader(): + | KernelMessage.IHeader + | undefined { + return this._parentHeader; + } + + /** + * Get the last parent message (mimick ipykernel's get_parent) + */ + get parent(): KernelMessage.IMessage | undefined { + return this._parent; + } + + /** + * Get the kernel location + */ + get location(): string { + return this._location; + } + + /** + * Process a message coming from the pyodide web worker. + * + * @param msg The worker message to process. + */ + private _processWorkerMessage(msg: any): void { + if (!msg.header) { + return; + } + + msg.header.session = this._parentHeader?.session ?? ''; + msg.session = this._parentHeader?.session ?? ''; + this._sendMessage(msg); + + // resolve promise + if ( + msg.header.msg_type === 'status' && + msg.content.execution_state === 'idle' + ) { + this._executeDelegate.resolve(); + } + } + + /** + * A promise that is fulfilled when the kernel is ready. + */ + get ready(): Promise { + return Promise.resolve(); + } + + /** + * Return whether the kernel is disposed. + */ + get isDisposed(): boolean { + return this._isDisposed; + } + + /** + * A signal emitted when the kernel is disposed. + */ + get disposed(): ISignal { + return this._disposed; + } + + /** + * Dispose the kernel. + */ + dispose(): void { + if (this.isDisposed) { + return; + } + this._worker.terminate(); + (this._worker as any) = null; + (this._remote as any) = null; + this._isDisposed = true; + this._disposed.emit(void 0); + } + + /** + * Get the kernel id + */ + get id(): string { + return this._id; + } + + /** + * Get the name of the kernel + */ + get name(): string { + return this._name; + } + + private async initFileSystem(options: WebWorkerKernel.IOptions) { + let driveName: string; + let localPath: string; + + if (options.location.includes(':')) { + const parts = options.location.split(':'); + driveName = parts[0]; + localPath = parts[1]; + } else { + driveName = ''; + localPath = options.location; + } + + await this._remote.ready(); + + if (options.mountDrive) { + await this._remote.mount(driveName, '/drive', PageConfig.getBaseUrl()); + await this._remote.cd(localPath); + } + } + + private _spec: any; + private _id: string; + private _name: string; + private _location: string; + private _remote: Remote; + private _isDisposed = false; + private _disposed = new Signal(this); + private _worker: Worker; + private _sendMessage: IKernel.SendMessage; + private _executeDelegate = new PromiseDelegate(); + private _parentHeader: + | KernelMessage.IHeader + | undefined = undefined; + private _parent: KernelMessage.IMessage | undefined = undefined; +} + +/** + * A namespace for WebWorkerKernel statics. + */ +export namespace WebWorkerKernel { + /** + * The instantiation options for a Pyodide kernel + */ + export interface IOptions extends IKernel.IOptions { + mountDrive: boolean; + } +} diff --git a/src/worker.ts b/src/worker.ts new file mode 100644 index 0000000..e770ce4 --- /dev/null +++ b/src/worker.ts @@ -0,0 +1,255 @@ +// Copyright (c) Thorsten Beier +// Copyright (c) JupyterLite Contributors +// Distributed under the terms of the Modified BSD License. + +import { expose } from 'comlink'; + +import { + DriveFS, + DriveFSEmscriptenNodeOps, + IEmscriptenFSNode, + IStats +} from '@jupyterlite/contents'; + +declare function createXeusModule(options: any): any; + +globalThis.Module = {}; + +// const WASM_KERNEL_FILE = 'kernels/xlite/xlite.js'; +// const WASM_FILE = 'kernels/xlite/xlite.wasm'; +// TODO Remove this. This is to ensure we always perform node ops on Nodes and +// not Streams, but why is it needed??? Why do we get Streams and not Nodes from +// emscripten in the case of xeus-python??? +class StreamNodeOps extends DriveFSEmscriptenNodeOps { + private getNode(nodeOrStream: any) { + if (nodeOrStream['node']) { + return nodeOrStream['node']; + } + return nodeOrStream; + } + + lookup(parent: IEmscriptenFSNode, name: string): IEmscriptenFSNode { + return super.lookup(this.getNode(parent), name); + } + + getattr(node: IEmscriptenFSNode): IStats { + return super.getattr(this.getNode(node)); + } + + setattr(node: IEmscriptenFSNode, attr: IStats): void { + super.setattr(this.getNode(node), attr); + } + + mknod( + parent: IEmscriptenFSNode, + name: string, + mode: number, + dev: any + ): IEmscriptenFSNode { + return super.mknod(this.getNode(parent), name, mode, dev); + } + + rename( + oldNode: IEmscriptenFSNode, + newDir: IEmscriptenFSNode, + newName: string + ): void { + super.rename(this.getNode(oldNode), this.getNode(newDir), newName); + } + + rmdir(parent: IEmscriptenFSNode, name: string): void { + super.rmdir(this.getNode(parent), name); + } + + readdir(node: IEmscriptenFSNode): string[] { + return super.readdir(this.getNode(node)); + } +} + +// TODO Remove this when we don't need StreamNodeOps anymore +class LoggingDrive extends DriveFS { + constructor(options: DriveFS.IOptions) { + super(options); + + this.node_ops = new StreamNodeOps(this); + } +} + +// when a toplevel cell uses an await, the cell is implicitly +// wrapped in a async function. Since the webloop - eventloop +// implementation does not support `eventloop.run_until_complete(f)` +// we need to convert the toplevel future in a javascript Promise +// this `toplevel` promise is then awaited before we +// execute the next cell. After the promise is awaited we need +// to do some cleanup and delete the python proxy +// (ie a js-wrapped python object) to avoid memory leaks +globalThis.toplevel_promise = null; +globalThis.toplevel_promise_py_proxy = null; + +let resolveInputReply: any; + +async function get_stdin() { + const replyPromise = new Promise(resolve => { + resolveInputReply = resolve; + }); + return replyPromise; +} + +(self as any).get_stdin = get_stdin; + +class XeusKernel { + constructor(resolve: any) { + this._resolve = resolve; + } + + async ready(): Promise { + return await globalThis.ready; + } + + mount(driveName: string, mountpoint: string, baseUrl: string): void { + const { FS, PATH, ERRNO_CODES } = globalThis.Module; + + if (!FS) { + return; + } + + this._drive = new LoggingDrive({ + FS, + PATH, + ERRNO_CODES, + baseUrl, + driveName, + mountpoint + }); + + FS.mkdir(mountpoint); + FS.mount(this._drive, {}, mountpoint); + FS.chdir(mountpoint); + } + + cd(path: string) { + if (!path || !globalThis.Module.FS) { + return; + } + + globalThis.Module.FS.chdir(path); + } + + async processMessage(event: any): Promise { + const msg_type = event.msg.header.msg_type; + if (msg_type === 'initialize') { + const spec = event.spec; + this._spec = spec; + await this.initialize(); + + return; + } + + await this.ready(); + + if ( + globalThis.toplevel_promise !== null && + globalThis.toplevel_promise_py_proxy !== null + ) { + await globalThis.toplevel_promise; + globalThis.toplevel_promise_py_proxy.delete(); + globalThis.toplevel_promise_py_proxy = null; + globalThis.toplevel_promise = null; + } + + if (msg_type === 'input_reply') { + resolveInputReply(event.msg); + } else { + this._raw_xserver.notify_listener(event.msg); + } + } + + private async initialize() { + const dir = this._spec.dir; + const wasm_name = this._spec.metadata.wasm_name; + const THE_WASM_KERNEL_FILE = `kernels/${dir}/${wasm_name}.js`; + const THE_WASM_FILE = `kernels/${dir}/${wasm_name}.wasm`; + console.log('importScripts', THE_WASM_KERNEL_FILE, THE_WASM_FILE); + importScripts(THE_WASM_KERNEL_FILE); + + globalThis.Module = await createXeusModule({ + locateFile: (file: string) => { + if (file.endsWith('.wasm')) { + return THE_WASM_FILE; + } + return file; + } + }); + try { + await this.waitRunDependency(); + console.log(globalThis.Module); + + if (globalThis.Module['async_init'] !== undefined) { + console.log('!!!async_init!!!!'); + const kernel_root_url = `kernels/${dir}`; + const pkg_root_url = 'kernel_packages'; + console.log( + 'with kernel_root_url', + kernel_root_url, + 'and pkg_root_url', + pkg_root_url + ); + const verbose = true; + await globalThis.Module['async_init']( + kernel_root_url, + pkg_root_url, + verbose + ); + } else { + console.log('!!!NO async_init!!!!'); + } + + await this.waitRunDependency(); + + this._raw_xkernel = new globalThis.Module.xkernel(); + this._raw_xserver = this._raw_xkernel.get_server(); + if (!this._raw_xkernel) { + console.error('Failed to start kernel!'); + } + console.log('!!!start!!!'); + this._raw_xkernel.start(); + console.log('!!!start-DONE!!!'); + } catch (e) { + if (typeof e === 'number') { + const msg = globalThis.Module.get_exception_message(e); + console.error(msg); + throw new Error(msg); + } else { + console.error(e); + throw e; + } + } + this._resolve(); + } + + private async waitRunDependency() { + const promise = new Promise(resolve => { + globalThis.Module.monitorRunDependencies = (n: number) => { + if (n === 0) { + resolve(); + } + }; + }); + // If there are no pending dependencies left, monitorRunDependencies will + // never be called. Since we can't check the number of dependencies, + // manually trigger a call. + globalThis.Module.addRunDependency('dummy'); + globalThis.Module.removeRunDependency('dummy'); + return promise; + } + private _resolve: any; + private _spec: any; + private _raw_xkernel: any; + private _raw_xserver: any; + private _drive: DriveFS | null = null; + //private _ready: PromiseLike; +} + +globalThis.ready = new Promise(resolve => { + expose(new XeusKernel(resolve)); +}); diff --git a/tsconfig.json b/tsconfig.json index 9897917..f7ab437 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,7 @@ "module": "esnext", "moduleResolution": "node", "noEmitOnError": true, - "noImplicitAny": true, + "noImplicitAny": false, "noUnusedLocals": true, "preserveWatchOutput": true, "resolveJsonModule": true, @@ -17,7 +17,7 @@ "rootDir": "src", "strict": true, "strictNullChecks": true, - "target": "ES2018" + "target": "ES2019" }, "include": ["src/*"] } diff --git a/yarn.lock b/yarn.lock index 56f370a..e25fe69 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2065,7 +2065,7 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/application@npm:^4.0.0, @jupyterlab/application@npm:^4.0.9": +"@jupyterlab/application@npm:^4.0.9": version: 4.0.9 resolution: "@jupyterlab/application@npm:4.0.9" dependencies: @@ -2278,7 +2278,7 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/coreutils@npm:^6.0.9": +"@jupyterlab/coreutils@npm:^6, @jupyterlab/coreutils@npm:^6.0.9, @jupyterlab/coreutils@npm:~6.0.7": version: 6.0.9 resolution: "@jupyterlab/coreutils@npm:6.0.9" dependencies: @@ -2407,7 +2407,7 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/nbformat@npm:^3.0.0 || ^4.0.0-alpha.21 || ^4.0.0, @jupyterlab/nbformat@npm:^4.0.9": +"@jupyterlab/nbformat@npm:^3.0.0 || ^4.0.0-alpha.21 || ^4.0.0, @jupyterlab/nbformat@npm:^4.0.9, @jupyterlab/nbformat@npm:~4.0.7": version: 4.0.9 resolution: "@jupyterlab/nbformat@npm:4.0.9" dependencies: @@ -2452,7 +2452,7 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/observables@npm:^5.0.9": +"@jupyterlab/observables@npm:^5.0.9, @jupyterlab/observables@npm:~5.0.7": version: 5.0.9 resolution: "@jupyterlab/observables@npm:5.0.9" dependencies: @@ -2517,7 +2517,7 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/services@npm:^7.0.9": +"@jupyterlab/services@npm:^7, @jupyterlab/services@npm:^7.0.9, @jupyterlab/services@npm:~7.0.7": version: 7.0.9 resolution: "@jupyterlab/services@npm:7.0.9" dependencies: @@ -2536,7 +2536,7 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/settingregistry@npm:^4.0.9": +"@jupyterlab/settingregistry@npm:^4.0.9, @jupyterlab/settingregistry@npm:~4.0.7": version: 4.0.9 resolution: "@jupyterlab/settingregistry@npm:4.0.9" dependencies: @@ -2555,7 +2555,7 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/statedb@npm:^4.0.9": +"@jupyterlab/statedb@npm:^4.0.9, @jupyterlab/statedb@npm:~4.0.7": version: 4.0.9 resolution: "@jupyterlab/statedb@npm:4.0.9" dependencies: @@ -2685,19 +2685,130 @@ __metadata: languageName: node linkType: hard +"@jupyterlite/contents@npm:^0.2.0": + version: 0.2.0 + resolution: "@jupyterlite/contents@npm:0.2.0" + dependencies: + "@jupyterlab/nbformat": ~4.0.7 + "@jupyterlab/services": ~7.0.7 + "@jupyterlite/localforage": ^0.2.0 + "@lumino/coreutils": ^2.1.2 + "@types/emscripten": ^1.39.6 + localforage: ^1.9.0 + mime: ^3.0.0 + checksum: e395bcc42c59f0c8f141f6e726c8596b26c8ceacc0a80f29b9384c211dbc063d1467a83f7656fac83761eaf5b9b226a606718851dae2fc9c66578bf712f50393 + languageName: node + linkType: hard + +"@jupyterlite/kernel@npm:^0.2.0": + version: 0.2.0 + resolution: "@jupyterlite/kernel@npm:0.2.0" + dependencies: + "@jupyterlab/coreutils": ~6.0.7 + "@jupyterlab/observables": ~5.0.7 + "@jupyterlab/services": ~7.0.7 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/signaling": ^2.1.2 + async-mutex: ^0.3.1 + comlink: ^4.3.1 + mock-socket: ^9.1.0 + checksum: 1b5c3ba6dbb9fdc80ad4508a93b8b324c2b276f2ae8f124274fa3ee562362de08e17144b225e54d8fb33f0eb35f9ed930d5ebec5adc576bdd4223d5213c07dfb + languageName: node + linkType: hard + +"@jupyterlite/localforage@npm:^0.2.0": + version: 0.2.0 + resolution: "@jupyterlite/localforage@npm:0.2.0" + dependencies: + "@jupyterlab/coreutils": ~6.0.7 + "@lumino/coreutils": ^2.1.2 + localforage: ^1.9.0 + localforage-memoryStorageDriver: ^0.9.2 + checksum: 5510933708c6790c06d1ee0a12fbbd1feecf8c6e083fb11a416cedca107520792929ddbecba87a45ff7aa0ea8153c7dbd9fa5b935d13ad1c9900758c9a84a000 + languageName: node + linkType: hard + +"@jupyterlite/server@npm:^0.2.0": + version: 0.2.0 + resolution: "@jupyterlite/server@npm:0.2.0" + dependencies: + "@jupyterlab/coreutils": ~6.0.7 + "@jupyterlab/nbformat": ~4.0.7 + "@jupyterlab/observables": ~5.0.7 + "@jupyterlab/services": ~7.0.7 + "@jupyterlab/settingregistry": ~4.0.7 + "@jupyterlab/statedb": ~4.0.7 + "@jupyterlite/contents": ^0.2.0 + "@jupyterlite/kernel": ^0.2.0 + "@jupyterlite/session": ^0.2.0 + "@jupyterlite/settings": ^0.2.0 + "@jupyterlite/translation": ^0.2.0 + "@lumino/application": ^2.2.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/signaling": ^2.1.2 + mock-socket: ^9.1.0 + checksum: 1f8388b39b9ee419b7b58647eeba0f52f498a925348e848b4e5e859707a298f979fe03b8c3ca689472f249fa1fdab28b24d84ddc9dd233102fb65c8318a443c7 + languageName: node + linkType: hard + +"@jupyterlite/session@npm:^0.2.0": + version: 0.2.0 + resolution: "@jupyterlite/session@npm:0.2.0" + dependencies: + "@jupyterlab/coreutils": ~6.0.7 + "@jupyterlab/services": ~7.0.7 + "@jupyterlite/kernel": ^0.2.0 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + checksum: 022305bb6237ae2f5071f14e8e171f1e63628ef7f9feea4e4499767f349d784bb8fbde0889cdc2c6c996416d9880069a16c51ea46715488f75d70ef3b6342b5c + languageName: node + linkType: hard + +"@jupyterlite/settings@npm:^0.2.0": + version: 0.2.0 + resolution: "@jupyterlite/settings@npm:0.2.0" + dependencies: + "@jupyterlab/coreutils": ~6.0.7 + "@jupyterlab/settingregistry": ~4.0.7 + "@jupyterlite/localforage": ^0.2.0 + "@lumino/coreutils": ^2.1.2 + json5: ^2.2.0 + localforage: ^1.9.0 + checksum: ff651f66292c6e10d09e3fe1b6cfb964421afe30495f920b8416a0e411834dc41eb0ea817b74fe4c20d28579a4f58e19a2597ad162067e92b91b887c4dd8c8d4 + languageName: node + linkType: hard + +"@jupyterlite/translation@npm:^0.2.0": + version: 0.2.0 + resolution: "@jupyterlite/translation@npm:0.2.0" + dependencies: + "@jupyterlab/coreutils": ~6.0.7 + "@lumino/coreutils": ^2.1.2 + checksum: 53f8b9d3a800192fa42e96d04979d9494c263dbb78e7be22443f1f98f2f4f0ea79103b1bd8c40e410978e2d330de31bf6b3cf4e31b2a15ed40c9003a5e3b9604 + languageName: node + linkType: hard + "@jupyterlite/xeus@workspace:.": version: 0.0.0-use.local resolution: "@jupyterlite/xeus@workspace:." dependencies: - "@jupyterlab/application": ^4.0.0 "@jupyterlab/builder": ^4.0.0 + "@jupyterlab/coreutils": ^6 + "@jupyterlab/services": ^7 "@jupyterlab/testutils": ^4.0.0 + "@jupyterlite/contents": ^0.2.0 + "@jupyterlite/kernel": ^0.2.0 + "@jupyterlite/server": ^0.2.0 + "@lumino/coreutils": ^2 + "@lumino/signaling": ^2 "@types/jest": ^29.2.0 "@types/json-schema": ^7.0.11 "@types/react": ^18.0.26 "@types/react-addons-linked-state-mixin": ^0.14.22 "@typescript-eslint/eslint-plugin": ^6.1.0 "@typescript-eslint/parser": ^6.1.0 + comlink: ^4.3.1 css-loader: ^6.7.1 eslint: ^8.36.0 eslint-config-prettier: ^8.8.0 @@ -2908,7 +3019,7 @@ __metadata: languageName: node linkType: hard -"@lumino/coreutils@npm:^1.11.0 || ^2.0.0, @lumino/coreutils@npm:^1.11.0 || ^2.1.2, @lumino/coreutils@npm:^2.1.2": +"@lumino/coreutils@npm:^1.11.0 || ^2.0.0, @lumino/coreutils@npm:^1.11.0 || ^2.1.2, @lumino/coreutils@npm:^2, @lumino/coreutils@npm:^2.1.2": version: 2.1.2 resolution: "@lumino/coreutils@npm:2.1.2" checksum: 7865317ac0676b448d108eb57ab5d8b2a17c101995c0f7a7106662d9fe6c859570104525f83ee3cda12ae2e326803372206d6f4c1f415a5b59e4158a7b81066f @@ -2976,7 +3087,7 @@ __metadata: languageName: node linkType: hard -"@lumino/signaling@npm:^1.10.0 || ^2.0.0, @lumino/signaling@npm:^2.1.2": +"@lumino/signaling@npm:^1.10.0 || ^2.0.0, @lumino/signaling@npm:^2, @lumino/signaling@npm:^2.1.2": version: 2.1.2 resolution: "@lumino/signaling@npm:2.1.2" dependencies: @@ -3188,6 +3299,13 @@ __metadata: languageName: node linkType: hard +"@types/emscripten@npm:^1.39.6": + version: 1.39.10 + resolution: "@types/emscripten@npm:1.39.10" + checksum: 1721da76593f9194e0b7c90a581e2d31c23bd4eb28f93030cd1dc58216cdf1e692c045274f2eedaed29c652c25c9a4dff2e503b11bd1258d07095c009a1956b1 + languageName: node + linkType: hard + "@types/eslint-scope@npm:^3.7.3": version: 3.7.7 resolution: "@types/eslint-scope@npm:3.7.7" @@ -3987,6 +4105,15 @@ __metadata: languageName: node linkType: hard +"async-mutex@npm:^0.3.1": + version: 0.3.2 + resolution: "async-mutex@npm:0.3.2" + dependencies: + tslib: ^2.3.1 + checksum: 620b771dfdea1cad0a6b712915c31a1e3ca880a8cf1eae92b4590f435995e0260929c6ebaae0b9126b1456790ea498064b5bb9a506948cda760f48d3d0dcc4c8 + languageName: node + linkType: hard + "asynckit@npm:^0.4.0": version: 0.4.0 resolution: "asynckit@npm:0.4.0" @@ -4458,6 +4585,13 @@ __metadata: languageName: node linkType: hard +"comlink@npm:^4.3.1": + version: 4.4.1 + resolution: "comlink@npm:4.4.1" + checksum: 16d58a8f590087fc45432e31d6c138308dfd4b75b89aec0b7f7bb97ad33d810381bd2b1e608a1fb2cf05979af9cbfcdcaf1715996d5fcf77aeb013b6da3260af + languageName: node + linkType: hard + "commander@npm:^10.0.1": version: 10.0.1 resolution: "commander@npm:10.0.1" @@ -6068,6 +6202,13 @@ __metadata: languageName: node linkType: hard +"immediate@npm:~3.0.5": + version: 3.0.6 + resolution: "immediate@npm:3.0.6" + checksum: f9b3486477555997657f70318cc8d3416159f208bec4cca3ff3442fd266bc23f50f0c9bd8547e1371a6b5e82b821ec9a7044a4f7b944798b25aa3cc6d5e63e62 + languageName: node + linkType: hard + "import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" @@ -7178,7 +7319,7 @@ __metadata: languageName: node linkType: hard -"json5@npm:^2.1.2, json5@npm:^2.2.3": +"json5@npm:^2.1.2, json5@npm:^2.2.0, json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" bin: @@ -7279,6 +7420,15 @@ __metadata: languageName: node linkType: hard +"lie@npm:3.1.1": + version: 3.1.1 + resolution: "lie@npm:3.1.1" + dependencies: + immediate: ~3.0.5 + checksum: 6da9f2121d2dbd15f1eca44c0c7e211e66a99c7b326ec8312645f3648935bc3a658cf0e9fa7b5f10144d9e2641500b4f55bd32754607c3de945b5f443e50ddd1 + languageName: node + linkType: hard + "lines-and-columns@npm:^1.1.6": version: 1.2.4 resolution: "lines-and-columns@npm:1.2.4" @@ -7316,6 +7466,24 @@ __metadata: languageName: node linkType: hard +"localforage-memoryStorageDriver@npm:^0.9.2": + version: 0.9.2 + resolution: "localforage-memoryStorageDriver@npm:0.9.2" + dependencies: + localforage: ">=1.4.0" + checksum: 1f867be54d005e3009cd841f3cadde728468911a4a8cca6c7c77eb1ce8c28526d9c373d8881e5e25391a5114445c9b68d3a1f05319bd33ff0a787d99eeb829c9 + languageName: node + linkType: hard + +"localforage@npm:>=1.4.0, localforage@npm:^1.9.0": + version: 1.10.0 + resolution: "localforage@npm:1.10.0" + dependencies: + lie: 3.1.1 + checksum: f2978b434dafff9bcb0d9498de57d97eba165402419939c944412e179cab1854782830b5ec196212560b22712d1dd03918939f59cf1d4fc1d756fca7950086cf + languageName: node + linkType: hard + "locate-path@npm:^5.0.0": version: 5.0.0 resolution: "locate-path@npm:5.0.0" @@ -7574,6 +7742,15 @@ __metadata: languageName: node linkType: hard +"mime@npm:^3.0.0": + version: 3.0.0 + resolution: "mime@npm:3.0.0" + bin: + mime: cli.js + checksum: f43f9b7bfa64534e6b05bd6062961681aeb406a5b53673b53b683f27fcc4e739989941836a355eef831f4478923651ecc739f4a5f6e20a76487b432bfd4db928 + languageName: node + linkType: hard + "mimic-fn@npm:^2.1.0": version: 2.1.0 resolution: "mimic-fn@npm:2.1.0" @@ -7744,6 +7921,13 @@ __metadata: languageName: node linkType: hard +"mock-socket@npm:^9.1.0": + version: 9.3.1 + resolution: "mock-socket@npm:9.3.1" + checksum: cb2dde4fc5dde280dd5ccb78eaaa223382ee16437f46b86558017655584ad08c22e733bde2dd5cc86927def506b6caeb0147e3167b9a62d70d5cf19d44103853 + languageName: node + linkType: hard + "ms@npm:2.1.2": version: 2.1.2 resolution: "ms@npm:2.1.2" @@ -9693,7 +9877,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.5.0, tslib@npm:^2.6.0": +"tslib@npm:^2.3.1, tslib@npm:^2.5.0, tslib@npm:^2.6.0": version: 2.6.2 resolution: "tslib@npm:2.6.2" checksum: 329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad