mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-19 18:27:29 -05:00
[sw] Added a first version of the PyScript Service Worker (#1621)
* Added a first version of the PyScript Service Worker * Fix typo as suggested Co-authored-by: Fabio Pliger <fpliger@users.noreply.github.com> --------- Co-authored-by: Fabio Pliger <fpliger@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
77d8fe3562
commit
b5a0cd4057
@@ -47,7 +47,7 @@ repos:
|
|||||||
rev: "v3.0.0-alpha.6"
|
rev: "v3.0.0-alpha.6"
|
||||||
hooks:
|
hooks:
|
||||||
- id: prettier
|
- id: prettier
|
||||||
exclude: pyscript\.core/test|pyscript\.core/core.*|pyscript\.core/types/
|
exclude: pyscript\.core/test|pyscript\.core/core.*|pyscript\.core/types/|pyscript\.sw/
|
||||||
args: [--tab-width, "4"]
|
args: [--tab-width, "4"]
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-eslint
|
- repo: https://github.com/pre-commit/mirrors-eslint
|
||||||
|
|||||||
5
pyscript.sw/.npmignore
Normal file
5
pyscript.sw/.npmignore
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
node_modules/
|
||||||
|
rollup/
|
||||||
|
src/
|
||||||
|
test/
|
||||||
|
package-lock.json
|
||||||
201
pyscript.sw/LICENSE
Normal file
201
pyscript.sw/LICENSE
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright (c) 2022-present, PyScript Development Team
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
47
pyscript.sw/README.md
Normal file
47
pyscript.sw/README.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# @pyscript/sw
|
||||||
|
|
||||||
|
<sup>**[PyScript](https://github.com/pyscript/pyscript) Service Worker**</sup>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
This module provides a single, standalone, *script* able to bootstrap a Service Worker which can drive a whole site via Python code.
|
||||||
|
|
||||||
|
Please note the file *must* be available locally and it *must not* be loaded as a module, as a Service Worker is *not a module*.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
This is the bare minimal example of an `index.html` file at the root of the site.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!doctype html>
|
||||||
|
<script src="./pyscript.sw.js"
|
||||||
|
handler="./handler.py"
|
||||||
|
config="./handler_config.toml"
|
||||||
|
scope="."></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
* **src** is where the PyScript Service Worker is located.
|
||||||
|
* **handler** is where Python code is located. This *must* provide a `handle_request` method that will be invoked per each browsing *fetch* operation. Such method should return a `[body, status, headers]` tuple where *body* is the content of the page, *status* is its *HTTP* status and *headers* contain the `content-type` or any other useful header.
|
||||||
|
* **config** is an *optional* attribute that indicates packages to load, files to fetch, and all other usual [py-config goodness](https://docs.pyscript.net/latest/reference/elements/py-config.html).
|
||||||
|
* **scope** (advanced use-case) is an *optional* attribute that indicates [where the Service Worker operates](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope). By default it operates from the same folder, and any subfolder, the `pyscript.sw.js` is.
|
||||||
|
|
||||||
|
#### How to update `handle_request`
|
||||||
|
|
||||||
|
Because the Service Worker, once activated, will persist over any further session, it is pretty hard to change its operating handler.
|
||||||
|
|
||||||
|
To do so, there are two options:
|
||||||
|
|
||||||
|
* unregister the Service Worker, clear all browsing data per that domain and hard-refresh the browser
|
||||||
|
* change and save your `handler.py` file and, once saved, reach the `/pyscript.sw/update_handler` via browser, or run the following code in console:
|
||||||
|
|
||||||
|
```js
|
||||||
|
fetch('/pyscript.sw/update_handler')
|
||||||
|
.then(b => b.text())
|
||||||
|
.then(console.log, console.error);
|
||||||
|
```
|
||||||
|
|
||||||
|
This operation will be intercepted behind the scene and the new file will be parsed.
|
||||||
|
|
||||||
|
The result should be an `OK` response, with status `200`, or an error message with status `500` handled by the `console.error` or visible within the page once reached.
|
||||||
467
pyscript.sw/package-lock.json
generated
Normal file
467
pyscript.sw/package-lock.json
generated
Normal file
@@ -0,0 +1,467 @@
|
|||||||
|
{
|
||||||
|
"name": "@pyscript/sw",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "@pyscript/sw",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"license": "APACHE-2.0",
|
||||||
|
"devDependencies": {
|
||||||
|
"@rollup/plugin-node-resolve": "^15.1.0",
|
||||||
|
"@rollup/plugin-terser": "^0.4.3",
|
||||||
|
"basic-toml": "^0.3.1",
|
||||||
|
"rollup": "^3.27.0",
|
||||||
|
"static-handler": "^0.4.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
|
"version": "0.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||||
|
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/set-array": "^1.0.1",
|
||||||
|
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||||
|
"@jridgewell/trace-mapping": "^0.3.9"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@jridgewell/resolve-uri": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@jridgewell/set-array": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@jridgewell/source-map": {
|
||||||
|
"version": "0.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
|
||||||
|
"integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/gen-mapping": "^0.3.0",
|
||||||
|
"@jridgewell/trace-mapping": "^0.3.9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@jridgewell/sourcemap-codec": {
|
||||||
|
"version": "1.4.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||||
|
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/@jridgewell/trace-mapping": {
|
||||||
|
"version": "0.3.18",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz",
|
||||||
|
"integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/resolve-uri": "3.1.0",
|
||||||
|
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": {
|
||||||
|
"version": "1.4.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
|
||||||
|
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/plugin-node-resolve": {
|
||||||
|
"version": "15.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.1.0.tgz",
|
||||||
|
"integrity": "sha512-xeZHCgsiZ9pzYVgAo9580eCGqwh/XCEUM9q6iQfGNocjgkufHAqC3exA+45URvhiYV8sBF9RlBai650eNs7AsA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@rollup/pluginutils": "^5.0.1",
|
||||||
|
"@types/resolve": "1.20.2",
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
|
"is-builtin-module": "^3.2.1",
|
||||||
|
"is-module": "^1.0.0",
|
||||||
|
"resolve": "^1.22.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"rollup": "^2.78.0||^3.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"rollup": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/plugin-terser": {
|
||||||
|
"version": "0.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.3.tgz",
|
||||||
|
"integrity": "sha512-EF0oejTMtkyhrkwCdg0HJ0IpkcaVg1MMSf2olHb2Jp+1mnLM04OhjpJWGma4HobiDTF0WCyViWuvadyE9ch2XA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"serialize-javascript": "^6.0.1",
|
||||||
|
"smob": "^1.0.0",
|
||||||
|
"terser": "^5.17.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"rollup": "^2.x || ^3.x"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"rollup": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/pluginutils": {
|
||||||
|
"version": "5.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz",
|
||||||
|
"integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/estree": "^1.0.0",
|
||||||
|
"estree-walker": "^2.0.2",
|
||||||
|
"picomatch": "^2.3.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"rollup": "^1.20.0||^2.0.0||^3.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"rollup": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/estree": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/@types/resolve": {
|
||||||
|
"version": "1.20.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
|
||||||
|
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/acorn": {
|
||||||
|
"version": "8.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
|
||||||
|
"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"acorn": "bin/acorn"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/basic-toml": {
|
||||||
|
"version": "0.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/basic-toml/-/basic-toml-0.3.1.tgz",
|
||||||
|
"integrity": "sha512-O1ywy7Win4Tw215aY/cHyzZXCYlhyzEUbVR+hqkmosBA6Z7ejBcZb3fwDtsirAsd+KADY9A/D3qkbAQ4CqkaHg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/buffer-from": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/builtin-modules": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/commander": {
|
||||||
|
"version": "2.20.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/deepmerge": {
|
||||||
|
"version": "4.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||||
|
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/estree-walker": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/fsevents": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/function-bind": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/has": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"function-bind": "^1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-builtin-module": {
|
||||||
|
"version": "3.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
|
||||||
|
"integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"builtin-modules": "^3.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-core-module": {
|
||||||
|
"version": "2.12.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
|
||||||
|
"integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"has": "^1.0.3"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-module": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/mime-db": {
|
||||||
|
"version": "1.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-types": {
|
||||||
|
"version": "2.1.35",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"mime-db": "1.52.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/path-parse": {
|
||||||
|
"version": "1.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||||
|
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/picomatch": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/randombytes": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "^5.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/resolve": {
|
||||||
|
"version": "1.22.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
|
||||||
|
"integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"is-core-module": "^2.11.0",
|
||||||
|
"path-parse": "^1.0.7",
|
||||||
|
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"resolve": "bin/resolve"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rollup": {
|
||||||
|
"version": "3.27.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.27.1.tgz",
|
||||||
|
"integrity": "sha512-tXNDFwOkN6C2w5Blj1g6ForKeFw6c1mDu5jxoeDO3/pmYjgt+8yvIFjKzH5FQUq70OKZBkOt0zzv0THXL7vwzQ==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"rollup": "dist/bin/rollup"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.18.0",
|
||||||
|
"npm": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "~2.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/safe-buffer": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/serialize-javascript": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"randombytes": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/smob": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/smob/-/smob-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-MqR3fVulhjWuRNSMydnTlweu38UhQ0HXM4buStD/S3mc/BzX3CuM9OmhyQpmtYCvoYdl5ris6TI0ZqH355Ymqg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/source-map": {
|
||||||
|
"version": "0.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/source-map-support": {
|
||||||
|
"version": "0.5.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||||
|
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"buffer-from": "^1.0.0",
|
||||||
|
"source-map": "^0.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/static-handler": {
|
||||||
|
"version": "0.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/static-handler/-/static-handler-0.4.2.tgz",
|
||||||
|
"integrity": "sha512-Szbk521mneb5npxg3SEyoufsHr2osAzxMy71W2zFCzLB8wLhHYvKUDCMkLY6imi+fIqkpfas3rzXGBQf99aeEA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"mime-types": "^2.1.35"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"static-handler": "static-handler.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/supports-preserve-symlinks-flag": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/terser": {
|
||||||
|
"version": "5.19.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz",
|
||||||
|
"integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/source-map": "^0.3.3",
|
||||||
|
"acorn": "^8.8.2",
|
||||||
|
"commander": "^2.20.0",
|
||||||
|
"source-map-support": "~0.5.20"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"terser": "bin/terser"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
pyscript.sw/package.json
Normal file
20
pyscript.sw/package.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "@pyscript/sw",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "PyScript Service Worker",
|
||||||
|
"main": "pyscript.sw.js",
|
||||||
|
"scripts": {
|
||||||
|
"server": "npx static-handler .",
|
||||||
|
"build": "rollup --config rollup/sw.config.mjs"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "Anaconda Inc.",
|
||||||
|
"license": "APACHE-2.0",
|
||||||
|
"devDependencies": {
|
||||||
|
"@rollup/plugin-node-resolve": "^15.1.0",
|
||||||
|
"@rollup/plugin-terser": "^0.4.3",
|
||||||
|
"basic-toml": "^0.3.1",
|
||||||
|
"rollup": "^3.27.0",
|
||||||
|
"static-handler": "^0.4.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
3
pyscript.sw/pyscript.sw.js
Normal file
3
pyscript.sw/pyscript.sw.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
!function(){"use strict";(({document:e,navigator:{serviceWorker:t}})=>{if(e){const{href:s}=location,{controller:n}=t,{currentScript:a}=e,{src:r,attributes:{config:i,handler:o,scope:c}}=a;n&&n.postMessage({config:i?.value?new URL(i.value,s).href:"",handler:new URL(o.value,s).href}),t.addEventListener("message",(({data:e})=>{"reload"===e&&location.reload()})),t.register(r,{scope:c?.value||"."}).then((e=>{e.addEventListener("updatefound",(()=>location.reload())),e.active&&!n&&location.reload()}))}else{const e="https://cdn.jsdelivr.net/pyodide/v0.23.4/full";importScripts(`${e}/pyodide.js`);const t=async e=>(await Promise.resolve().then((function(){return r}))).parse(e),s=loadPyodide({indexURL:e});addEventListener("install",(()=>skipWaiting())),addEventListener("activate",(e=>e.waitUntil(clients.claim())));let n,a,i=!1,o=new Promise((e=>{addEventListener("message",(async({data:{config:r,handler:o}})=>{if(r){const e=await s,n=[fetch(r),e.loadPackage("micropip")];n[0]=r.endsWith(".json")?n[0].then((e=>e.json())):n[0].then((e=>e.text())).then(t);const[{packages:a}]=await Promise.all(n),i=await e.pyimport("micropip");await i.install(a)}a=o;const l=await c();i=!0;(await clients.get(n)).postMessage("reload"),e(l)}),{once:!0})}));const c=()=>new Promise((async(e,t)=>{const n=await s,r=await fetch(a).then((e=>e.text())),i=n.globals.get("dict")();await n.runPythonAsync(r,{globals:i}).catch(t),e(i.get("handle_request")),i.destroy()}));addEventListener("fetch",(e=>{if(n||(n=e.clientId),i)if("/pyscript.sw/update_handler"===new URL(e.request.url).pathname){const t=c();e.respondWith(t.then((()=>(o=t,new Response("OK",{headers:{"content-type":"text/plain"},status:200}))),(e=>new Response(e.message,{headers:{"content-type":"text/plain"},status:500}))))}else e.respondWith(o.then((async t=>{const[s,n,a]=await t(e.request);return new Response(s,{headers:a,status:n})})))}))}})(self);
|
||||||
|
/*! (c) Andrea Giammarchi - ISC */
|
||||||
|
const{isArray:e}=Array,{parse:t}=JSON,s=(e,{s:t})=>e.replace(/"s(\d+)"/g,((e,s)=>t[s])),n=(e,s)=>t(e.replace(/(\S+?)\s*=/g,'"$1":'),((e,t)=>"string"==typeof t?s[t[0]][t.slice(1)]:t)),a=(t,n,a,r)=>{for(let i=0,{length:o}=t,c=o-1;i<o;i++){const o=s(t[i],n);a=a[o]||(a[o]=r&&i===c?[]:{}),e(a)&&(i!==c&&a.length||a.push({}),a=a.at(-1))}return a};var r=Object.freeze({__proto__:null,parse:e=>{const[t,r]=((e,t,s)=>[e.replace(/(["'])(?:(?=(\\?))\2.)*?\1/g,(e=>`"s${t.push(e.slice(1,-1))-1}"`)).replace(/\d{2,}([:-]\d{2}){2}([ T:-][\dZ:-]+)?/g,(e=>`"d${s.push(new Date(e))-1}"`)).replace(/,\s*[\r\n]+/g,", ").replace(/\[\s*[\r\n]+/g,"[").replace(/[\r\n]+\s*]/g,"]"),{s:t,d:s}])(e,[],[]),i={};let o=i;for(let e of t.split(/[\r\n]+/))if((e=e.trim())&&!e.startsWith("#"))if(/^(\[+)(.*?)\]+/.test(e))o=a(RegExp.$2.trim().split("."),r,i,"["!==RegExp.$1);else if(/^(\S+?)\s*=([^#]+)/.test(e)){const{$1:e,$2:t}=RegExp;o[s(e,r)]=n(t.trim(),r)}return i}})}();
|
||||||
16
pyscript.sw/rollup/sw.config.mjs
Normal file
16
pyscript.sw/rollup/sw.config.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// This file generates /core.js minified version of the module, which is
|
||||||
|
// the default exported as npm entry.
|
||||||
|
|
||||||
|
import { nodeResolve } from "@rollup/plugin-node-resolve";
|
||||||
|
import terser from "@rollup/plugin-terser";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
input: "./src/sw.js",
|
||||||
|
plugins: process.env.NO_MIN ? [nodeResolve()] : [nodeResolve(), terser()],
|
||||||
|
output: {
|
||||||
|
esModule: false,
|
||||||
|
inlineDynamicImports: true,
|
||||||
|
file: "./pyscript.sw.js",
|
||||||
|
format: "iife",
|
||||||
|
},
|
||||||
|
};
|
||||||
154
pyscript.sw/src/sw.js
Normal file
154
pyscript.sw/src/sw.js
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
// NOTE: this file must be a single JS file so that we can distribute it
|
||||||
|
// as standalone "one-shop" entry for the Service Worker, i.e.:
|
||||||
|
// <script src="../pyscript.sw.js" handler="./file.py"></script>
|
||||||
|
|
||||||
|
// prevent global scope pollution with local references
|
||||||
|
// this callback works in both the main page and in the SW
|
||||||
|
(({ document, navigator: { serviceWorker } }) => {
|
||||||
|
// here we are on the main page
|
||||||
|
if (document) {
|
||||||
|
const { href } = location;
|
||||||
|
const { controller } = serviceWorker;
|
||||||
|
|
||||||
|
const { currentScript } = document;
|
||||||
|
const {
|
||||||
|
src,
|
||||||
|
attributes: { config, handler, scope },
|
||||||
|
} = currentScript;
|
||||||
|
|
||||||
|
// send files to fetch and handle to the Service Worker
|
||||||
|
// after resolving the path through current page location
|
||||||
|
// (not the service worker one as these likely have different relative folders)
|
||||||
|
if (controller) {
|
||||||
|
controller.postMessage({
|
||||||
|
config: config?.value ? new URL(config.value, href).href : "",
|
||||||
|
// handler is mandatory (or it means there's nothing to run as Python)
|
||||||
|
handler: new URL(handler.value, href).href,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// do reload automatically once everything has been bootstrapped
|
||||||
|
serviceWorker.addEventListener("message", ({ data }) => {
|
||||||
|
if (data === "reload") location.reload();
|
||||||
|
});
|
||||||
|
|
||||||
|
// register the Service Worker with an optional scope ...
|
||||||
|
serviceWorker
|
||||||
|
.register(src, { scope: scope?.value || "." })
|
||||||
|
.then((registration) => {
|
||||||
|
// ... once registered, let the SW automatically handle the page reload
|
||||||
|
registration.addEventListener("updatefound", () =>
|
||||||
|
location.reload(),
|
||||||
|
);
|
||||||
|
if (registration.active && !controller) location.reload();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// here we are on the Service Worker
|
||||||
|
else {
|
||||||
|
const indexURL = "https://cdn.jsdelivr.net/pyodide/v0.23.4/full";
|
||||||
|
|
||||||
|
// because of this issue https://github.com/w3c/ServiceWorker/issues/1356
|
||||||
|
// the pyodide must be loaded sync ASAP or `importScripts` will fail
|
||||||
|
importScripts(`${indexURL}/pyodide.js`);
|
||||||
|
|
||||||
|
// ⚠️ WARNING: this will be inlined by rollup - can't be used AS IS
|
||||||
|
const parse = async (text) => (await import('basic-toml')).parse(text);
|
||||||
|
|
||||||
|
// this is still not blocking so no problems should happen ... we can bring anything
|
||||||
|
// directly from the CDN at this point, as pyodide is flagged as secure script here
|
||||||
|
const interpreter = loadPyodide({ indexURL });
|
||||||
|
|
||||||
|
// skip waiting on installation and ensure activation
|
||||||
|
// this will trigger the automatic reload on the main page
|
||||||
|
// once the Service Worker is ready to operate
|
||||||
|
addEventListener("install", () => skipWaiting());
|
||||||
|
addEventListener("activate", (e) => e.waitUntil(clients.claim()));
|
||||||
|
|
||||||
|
let // used to postMessage a reload when everything is ready
|
||||||
|
clientId,
|
||||||
|
// keeps the handler path known for future updates
|
||||||
|
handlerPath,
|
||||||
|
// let fetch operations through until there is a handler
|
||||||
|
handleReady = false,
|
||||||
|
// wait for the postMessage to communicate where is the python file
|
||||||
|
// and where is the config, if any
|
||||||
|
handleRequest = new Promise(resolve => {
|
||||||
|
addEventListener(
|
||||||
|
"message",
|
||||||
|
async ({ data: { config, handler } }) => {
|
||||||
|
if (config) {
|
||||||
|
const pyodide = await interpreter;
|
||||||
|
const deps = [
|
||||||
|
fetch(config),
|
||||||
|
pyodide.loadPackage("micropip"),
|
||||||
|
];
|
||||||
|
|
||||||
|
// assign the right body retriever accordingly
|
||||||
|
// with the config extension
|
||||||
|
deps[0] = config.endsWith(".json") ?
|
||||||
|
deps[0].then((b) => b.json()) :
|
||||||
|
deps[0].then((b) => b.text()).then(parse);
|
||||||
|
|
||||||
|
const [{ packages }] = await Promise.all(deps);
|
||||||
|
const micropip = await pyodide.pyimport("micropip");
|
||||||
|
await micropip.install(packages);
|
||||||
|
}
|
||||||
|
handlerPath = handler;
|
||||||
|
const result = await getHandler();
|
||||||
|
handleReady = true;
|
||||||
|
const client = await clients.get(clientId);
|
||||||
|
client.postMessage("reload");
|
||||||
|
resolve(result);
|
||||||
|
},
|
||||||
|
{ once: true },
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// used to update the handler when '/pyscript.sw/update_handler'
|
||||||
|
// path is reached and the service worker is already initialized
|
||||||
|
const getHandler = () => new Promise(async (resolve, reject) => {
|
||||||
|
const pyodide = await interpreter;
|
||||||
|
const code = await fetch(handlerPath).then(b => b.text());
|
||||||
|
const globals = pyodide.globals.get("dict")();
|
||||||
|
await pyodide.runPythonAsync(code, { globals }).catch(reject);
|
||||||
|
resolve(globals.get("handle_request"));
|
||||||
|
globals.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
addEventListener("fetch", (event) => {
|
||||||
|
if (!clientId) clientId = event.clientId;
|
||||||
|
if (!handleReady) return;
|
||||||
|
// this switch is to allow possible future operations too
|
||||||
|
switch (new URL(event.request.url).pathname) {
|
||||||
|
// reserved: this is our namespace to operate internally
|
||||||
|
case '/pyscript.sw/update_handler':
|
||||||
|
const newHandler = getHandler();
|
||||||
|
event.respondWith(newHandler.then(
|
||||||
|
() => {
|
||||||
|
// only if successful the handleRequest is re-assigned
|
||||||
|
handleRequest = newHandler;
|
||||||
|
return new Response('OK', {
|
||||||
|
headers: {'content-type': 'text/plain'},
|
||||||
|
status: 200
|
||||||
|
});
|
||||||
|
},
|
||||||
|
error => new Response(error.message, {
|
||||||
|
headers: {'content-type': 'text/plain'},
|
||||||
|
status: 500
|
||||||
|
})
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
event.respondWith(
|
||||||
|
handleRequest.then(async (handler) => {
|
||||||
|
const [text, status, headers] = await handler(
|
||||||
|
event.request,
|
||||||
|
);
|
||||||
|
return new Response(text, { headers, status });
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})(self);
|
||||||
21
pyscript.sw/test/index.html
Normal file
21
pyscript.sw/test/index.html
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<style>body { font-family: sans-serif; }</style>
|
||||||
|
<script src="../pyscript.sw.js" handler="./test.py" config="./test.toml"></script>
|
||||||
|
<script type="module">
|
||||||
|
// this is just to show some progress
|
||||||
|
const span = document.querySelector('span');
|
||||||
|
let i = 0;
|
||||||
|
(function dot() {
|
||||||
|
span.textContent = '.'.repeat(++i % 6);
|
||||||
|
setTimeout(dot, 300);
|
||||||
|
}());
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
Loading PyScript Service Worker <span></span>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
59
pyscript.sw/test/test.py
Normal file
59
pyscript.sw/test/test.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import random
|
||||||
|
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi.responses import HTMLResponse
|
||||||
|
from httpx import AsyncClient
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
base = "/test"
|
||||||
|
|
||||||
|
|
||||||
|
def generate_html_response():
|
||||||
|
html_content = """
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>PyScript Service Worker</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>PyScript from a service worker 🦄</h1>
|
||||||
|
<h2>FastAPI demo</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Test some random <a href="./json">json</a></li>
|
||||||
|
<li>Test some random <a href="./emoji">emoji</a></li>
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
return HTMLResponse(content=html_content, status_code=200)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get(base + "/", response_class=HTMLResponse)
|
||||||
|
async def root():
|
||||||
|
return generate_html_response()
|
||||||
|
|
||||||
|
|
||||||
|
# used to test errors forwarded as 500
|
||||||
|
# shenanigans(1, 2, 3)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get(base + "/json")
|
||||||
|
async def json():
|
||||||
|
# used to test that file changes actually happen when
|
||||||
|
# '/pyscript.sw/update_handler' is reached
|
||||||
|
# print(base + "/json")
|
||||||
|
return {"message": random.choice(["Hello World", "Bonjour le monde", "Hola Mundo"])}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get(base + "/emoji")
|
||||||
|
async def emoji():
|
||||||
|
return {"emoji": random.choice(["👋", "👋🏻", "👋🏼", "👋🏽", "👋🏾", "👋🏿"])}
|
||||||
|
|
||||||
|
|
||||||
|
async def handle_request(request):
|
||||||
|
async with AsyncClient(app=app, base_url="http://testserver") as client:
|
||||||
|
response = await client.get(request.url)
|
||||||
|
|
||||||
|
return response.text, response.status_code, response.headers.items()
|
||||||
1
pyscript.sw/test/test.toml
Normal file
1
pyscript.sw/test/test.toml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
packages = ["ssl", "httpx", "fastapi"]
|
||||||
Reference in New Issue
Block a user