@webqit/webflo 0.11.39 → 0.11.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/docker/Dockerfile +43 -0
- package/docker/README.md +91 -0
- package/docker/package.json +3 -0
- package/package.json +2 -3
- package/src/Context.js +3 -3
- package/src/config-pi/deployment/Layout.js +0 -1
- package/src/config-pi/deployment/Origins.js +7 -0
- package/src/config-pi/deployment/{Virtualization.js → Proxy.js} +3 -3
- package/src/config-pi/deployment/index.js +2 -2
- package/src/config-pi/runtime/Server.js +2 -2
- package/src/deployment-pi/origins/index.js +3 -2
- package/src/runtime-pi/{RuntimeClient.js → Application.js} +2 -2
- package/src/runtime-pi/HttpEvent.js +106 -0
- package/src/runtime-pi/Router.js +2 -3
- package/src/runtime-pi/Runtime.js +3 -3
- package/src/runtime-pi/client/{RuntimeClient.js → Application.js} +12 -4
- package/src/runtime-pi/client/Router.js +4 -3
- package/src/runtime-pi/client/Runtime.js +37 -59
- package/src/runtime-pi/client/Url.js +3 -3
- package/src/runtime-pi/client/Workport.js +1 -1
- package/src/runtime-pi/client/{Storage.js → createStorage.js} +3 -3
- package/src/runtime-pi/client/generate.js +5 -3
- package/src/runtime-pi/client/index.js +4 -4
- package/src/runtime-pi/client/worker/{WorkerClient.js → Application.js} +12 -8
- package/src/runtime-pi/client/worker/{Worker.js → Runtime.js} +25 -27
- package/src/runtime-pi/client/worker/index.js +6 -6
- package/src/runtime-pi/server/{RuntimeClient.js → Application.js} +8 -8
- package/src/runtime-pi/server/Router.js +3 -2
- package/src/runtime-pi/server/Runtime.js +50 -107
- package/src/runtime-pi/server/index.js +4 -4
- package/src/runtime-pi/util-http.js +70 -0
- package/src/runtime-pi/util-url.js +147 -0
- package/src/runtime-pi/xFormData.js +10 -46
- package/src/runtime-pi/xHeaders.js +2 -11
- package/src/runtime-pi/xRequest.js +29 -42
- package/src/runtime-pi/xRequestHeaders.js +20 -23
- package/src/runtime-pi/xResponse.js +19 -15
- package/src/runtime-pi/xResponseHeaders.js +41 -43
- package/src/runtime-pi/xURL.js +71 -77
- package/src/runtime-pi/xfetch.js +15 -6
- package/src/runtime-pi/xxHttpMessage.js +102 -0
- package/src/runtime-pi/client/whatwag.js +0 -27
- package/src/runtime-pi/server/whatwag.js +0 -35
- package/src/runtime-pi/util.js +0 -162
- package/src/runtime-pi/xHttpEvent.js +0 -101
- package/src/runtime-pi/xHttpMessage.js +0 -171
package/README.md
CHANGED
|
@@ -186,7 +186,7 @@ cd my-app
|
|
|
186
186
|
|
|
187
187
|
With [npm available on your terminal](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm), run the following command to install Webflo to your project:
|
|
188
188
|
|
|
189
|
-
> System Requirements: Node.js
|
|
189
|
+
> System Requirements: Node.js 18.0 (having stable Fetch API support) or later
|
|
190
190
|
|
|
191
191
|
```shell
|
|
192
192
|
npm i @webqit/webflo
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Base installations
|
|
2
|
+
# (Node 18 is the minimum required version: stable Fetch API, etc)
|
|
3
|
+
FROM node:18-alpine
|
|
4
|
+
RUN apk add git
|
|
5
|
+
RUN apk add certbot
|
|
6
|
+
|
|
7
|
+
# Refer to https://www.digitalocean.com/community/tutorials/how-to-build-a-node-js-application-with-docker
|
|
8
|
+
# By default, the Docker Node image includes a non-root node user that we can use to avoid running the application container as root.
|
|
9
|
+
USER node
|
|
10
|
+
|
|
11
|
+
# Create the working directory with node-user permissions
|
|
12
|
+
RUN mkdir -p /home/node/www/app && chown -R node:node /home/node/www
|
|
13
|
+
WORKDIR /home/node/www
|
|
14
|
+
|
|
15
|
+
# Adding this COPY instruction before running npm install or copying the application code allows you to take advantage of Docker’s caching mechanism.
|
|
16
|
+
COPY -chown=node:node package*.json ./
|
|
17
|
+
|
|
18
|
+
# Install
|
|
19
|
+
RUN npm install
|
|
20
|
+
# If you are building your code for production
|
|
21
|
+
# RUN npm ci --only=production
|
|
22
|
+
|
|
23
|
+
# Copy application code with node-user permissions
|
|
24
|
+
COPY --chown=node:node . .
|
|
25
|
+
|
|
26
|
+
# Install Webflo and friends globally
|
|
27
|
+
RUN npm install @webqit/webflo -g
|
|
28
|
+
RUN npm install @webqit/oohtml-cli -g
|
|
29
|
+
RUN npm install pm2 -g
|
|
30
|
+
|
|
31
|
+
# The deployment directory
|
|
32
|
+
WORKDIR /home/node/www/app
|
|
33
|
+
|
|
34
|
+
# To auto-start app (flags optional), we would add...
|
|
35
|
+
# CMD ["webflo", "start"]
|
|
36
|
+
|
|
37
|
+
# To build the image locally...
|
|
38
|
+
# docker build --no-cache -t webflo ./docker
|
|
39
|
+
|
|
40
|
+
# To publish to docker hub...
|
|
41
|
+
# docker login -u webqit
|
|
42
|
+
# docker tag webflo webqit/webflo
|
|
43
|
+
# docker push webqit/webflo
|
package/docker/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Webflo Container
|
|
2
|
+
|
|
3
|
+
This is simply a node.js container with the `@webqit/webflo` framework installed. Once started, any webflo app can be deployed into the container from any git repository.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
This container image lives on Docker Hub and can be pulled to a local machine or a remote Virtual Machine (VM) on any cloud platform.
|
|
8
|
+
|
|
9
|
+
+ [To Use Locally](#to-use-locally)
|
|
10
|
+
+ [To Use In the Cloud](#to-use-in-the-cloud)
|
|
11
|
+
* [To Deploy An App From Any Repo](#to-deploy-an-app-from-any-repo)
|
|
12
|
+
|
|
13
|
+
### To Use Locally
|
|
14
|
+
|
|
15
|
+
Ensure you have docker installed on your computer and run the following command from any location on your terminal:
|
|
16
|
+
|
|
17
|
+
```shell
|
|
18
|
+
docker pull webqit/webflo:latest
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The above command pulls the `webqit/webflo` image to your local machine. (But this can be automatically done by docker on running any docker commands that reference the `webqit/webflo` image.)
|
|
22
|
+
|
|
23
|
+
Next is to use the following commands to start the container and the Webflo runtime. In each case, the first part of the command starts the container, while the second part (from `webflo start`) starts the application.
|
|
24
|
+
|
|
25
|
+
#### To Start
|
|
26
|
+
|
|
27
|
+
Start the container using `docker run`; map a port (e.g `80`) of your host machine to `3000` of the container; optionally, give your container a name; reference `webqit/webflo` as the image to use; and lastly, start webflo using `webflo start`.
|
|
28
|
+
|
|
29
|
+
```shell
|
|
30
|
+
docker run -d -p 80:3000 --name my-app webqit/webflo webflo start
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
> Unless a port has been explicitly set via `webflo config server`, webflo *HTTP* port defaults to `3000` or the value specified in an environmental variable named `PORT`. If a `PORT` variable has been defined, then port mapping above would now need to use that variable: `-p 80:${PORT}`.
|
|
34
|
+
|
|
35
|
+
Visit [localhost](http://localhost) to view your app.
|
|
36
|
+
|
|
37
|
+
#### To Run In HTTPS Mode
|
|
38
|
+
|
|
39
|
+
To run Webflo apps in HTTPS inside a container, you basically need to map the appropriate SSL port from the host machine to a custom port in the container.
|
|
40
|
+
|
|
41
|
+
Below, we're now mapping port `443` to an application-level port defined as `${SSL_PORT}`.
|
|
42
|
+
|
|
43
|
+
```shell
|
|
44
|
+
docker run -d -p 80:${PORT} 443:${SSL_PORT} --name my-app webqit/webflo webflo start
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
> Unless an SSL port has been explicitly set via `webflo config server`, webflo *HTTPS* port defaults to `0` (no HTTPS) or the value specified in an environmental variable named `SSL_PORT`.
|
|
48
|
+
|
|
49
|
+
If you will be managing your SSL certificates in the host machine, you would also need to *bind-mount* the appropriate certificate volume from the host to the container.
|
|
50
|
+
|
|
51
|
+
Below, we're now mapping the directory `/etc/letsencrypt/` - the default location for `letsencrypt` certificates - to an equivalent directory in the container.
|
|
52
|
+
|
|
53
|
+
```shell
|
|
54
|
+
docker run -d -p 80:${PORT} 443:${SSL_PORT} -v /etc/letsencrypt/:/etc/letsencrypt/ --name my-app webqit/webflo webflo start
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
> Webflo lets you generate `letsencrypt` certificates with the `webflo generate:cert <domain1,domain2,etc>` command. Just be sure to have your app running in HTTP mode to enable the process handle certbot's `http` challenge.
|
|
58
|
+
|
|
59
|
+
#### To Start In Dev Mode
|
|
60
|
+
|
|
61
|
+
Webflo's *dev* mode is the perfect mode for developing locally. All you do is append the `--env=dev --watch` flags to your webflo commands. [(Learn more)](#)
|
|
62
|
+
|
|
63
|
+
```shell
|
|
64
|
+
docker run -d -p 80:3000 --name my-app webqit/webflo webflo start --env=dev --watch
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
In *dev* mode, webflo automatically restarts as you make changes to your codebase. But since webflo now lives inside a container, you'll need to *bind* the directory of your source code on your host machine to the `/home/node/www/app` directory of the container.
|
|
68
|
+
|
|
69
|
+
```shell
|
|
70
|
+
docker run -d -v /Users/me/my-app:/home/node/www/app -p 80:3000 --name my-app webqit/webflo webflo start --env=dev --watch
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### To Use In the Cloud
|
|
74
|
+
|
|
75
|
+
TODO
|
|
76
|
+
|
|
77
|
+
### To Deploy An App From Any Repo
|
|
78
|
+
|
|
79
|
+
Whether running locally or in the cloud, webflo can easily take your application from any git repo. This follows webflo's normal `deploy` command.
|
|
80
|
+
|
|
81
|
+
Simply point docker at your container (using `docker exec [container-name]`) and execute the `webflo deploy` command.
|
|
82
|
+
|
|
83
|
+
```shell
|
|
84
|
+
docker exec my-app webflo deploy https://github.com/me/my-app.git
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
If you will need to install any npm dependencies, you would run `npm install` from within your container.
|
|
88
|
+
|
|
89
|
+
```shell
|
|
90
|
+
docker exec my-app npm install
|
|
91
|
+
```
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"vanila-javascript"
|
|
13
13
|
],
|
|
14
14
|
"homepage": "https://webqit.io/tooling/webflo",
|
|
15
|
-
"version": "0.11.
|
|
15
|
+
"version": "0.11.41",
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@octokit/webhooks": "^7.15.1",
|
|
39
39
|
"@webqit/backpack": "^0.1.6",
|
|
40
|
-
"@webqit/oohtml-ssr": "^1.1.
|
|
40
|
+
"@webqit/oohtml-ssr": "^1.1.5",
|
|
41
41
|
"@webqit/util": "^0.8.9",
|
|
42
42
|
"client-sessions": "^0.8.0",
|
|
43
43
|
"esbuild": "^0.14.38",
|
|
@@ -45,7 +45,6 @@
|
|
|
45
45
|
"formdata-node": "^4.3.0",
|
|
46
46
|
"formidable": "^2.0.1",
|
|
47
47
|
"mime-types": "^2.1.33",
|
|
48
|
-
"node-fetch": "^2.6.1",
|
|
49
48
|
"simple-git": "^2.20.1",
|
|
50
49
|
"stream-slice": "^0.1.2",
|
|
51
50
|
"urlpattern-polyfill": "^4.0.3"
|
package/src/Context.js
CHANGED
|
@@ -56,7 +56,7 @@ export default class Context {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
set flags(value) {
|
|
59
|
-
this.dict
|
|
59
|
+
Object.defineProperty(this.dict, 'flags', { value } );
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// layout
|
|
@@ -65,7 +65,7 @@ export default class Context {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
set layout(value) {
|
|
68
|
-
this.dict
|
|
68
|
+
Object.defineProperty(this.dict, 'layout', { value } );
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
// logger
|
|
@@ -74,7 +74,7 @@ export default class Context {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
set logger(value) {
|
|
77
|
-
this.dict
|
|
77
|
+
Object.defineProperty(this.dict, 'logger', { value } );
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
}
|
|
@@ -31,6 +31,7 @@ export default class Origins extends Dotfile {
|
|
|
31
31
|
return this.merge({
|
|
32
32
|
entries: [{
|
|
33
33
|
host: hostname,
|
|
34
|
+
access_token: '',
|
|
34
35
|
repo: origin,
|
|
35
36
|
branch: 'master',
|
|
36
37
|
tag: 'root',
|
|
@@ -74,6 +75,12 @@ export default class Origins extends Dotfile {
|
|
|
74
75
|
choices: CHOICES.host,
|
|
75
76
|
validation: ['input', 'important'],
|
|
76
77
|
},
|
|
78
|
+
{
|
|
79
|
+
name: 'access_token',
|
|
80
|
+
type: 'text',
|
|
81
|
+
message: 'Enter your Personal Acess Token at host (if exists)',
|
|
82
|
+
validation: ['input', 'important'],
|
|
83
|
+
},
|
|
77
84
|
{
|
|
78
85
|
name: 'repo',
|
|
79
86
|
type: 'text',
|
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { Dotfile } from '@webqit/backpack';
|
|
6
6
|
|
|
7
|
-
export default class
|
|
7
|
+
export default class Proxy extends Dotfile {
|
|
8
8
|
|
|
9
9
|
// Base name
|
|
10
10
|
get name() {
|
|
11
|
-
return '
|
|
11
|
+
return 'proxy';
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
// @desc
|
|
15
15
|
static get ['@desc']() {
|
|
16
|
-
return 'Layout
|
|
16
|
+
return 'Layout proxy config.';
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
// Defaults merger
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import Env from './Env.js';
|
|
6
6
|
import Layout from './Layout.js';
|
|
7
7
|
import Origins from './Origins.js';
|
|
8
|
-
import
|
|
8
|
+
import Proxy from './Proxy.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @exports
|
|
@@ -14,5 +14,5 @@ export {
|
|
|
14
14
|
Env,
|
|
15
15
|
Layout,
|
|
16
16
|
Origins,
|
|
17
|
-
|
|
17
|
+
Proxy,
|
|
18
18
|
}
|
|
@@ -19,10 +19,10 @@ export default class Server extends Dotfile {
|
|
|
19
19
|
// Defaults merger
|
|
20
20
|
withDefaults(config) {
|
|
21
21
|
return this.merge({
|
|
22
|
-
port: process.env.
|
|
22
|
+
port: process.env.PORT || 3000,
|
|
23
23
|
domains: [],
|
|
24
24
|
https: {
|
|
25
|
-
port: 0,
|
|
25
|
+
port: process.env.SSL_PORT || 0,
|
|
26
26
|
domains: [],
|
|
27
27
|
keyfile: '/etc/letsencrypt/live/[domain]/privkey.pem',
|
|
28
28
|
certfile: '/etc/letsencrypt/live/[domain]/fullchain.pem',
|
|
@@ -55,6 +55,7 @@ export async function deploy(origin) {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
// ---------------
|
|
58
|
+
const accessToken = origin.access_token;
|
|
58
59
|
const isDeployPathSet = origin.deploy_path;
|
|
59
60
|
origin.deploy_path = Path.join(cx.CWD || '', origin.deploy_path || '.');
|
|
60
61
|
// ---------------
|
|
@@ -72,8 +73,8 @@ export async function deploy(origin) {
|
|
|
72
73
|
await git.init();
|
|
73
74
|
|
|
74
75
|
const hosts = {
|
|
75
|
-
github: '
|
|
76
|
-
bitbucket: '
|
|
76
|
+
github: `https://${ accessToken ? accessToken + '@' : '' }github.com`,
|
|
77
|
+
bitbucket: `https://${ accessToken ? accessToken + '@' : '' }bitbucket.org`,
|
|
77
78
|
};
|
|
78
79
|
const url = origin.url || hosts[origin.host] + '/' + origin.repo + '.git';
|
|
79
80
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
|
|
2
2
|
/**
|
|
3
3
|
* ---------------------------
|
|
4
|
-
* The base
|
|
4
|
+
* The base Application class
|
|
5
5
|
* ---------------------------
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
export default class
|
|
8
|
+
export default class Application {
|
|
9
9
|
|
|
10
10
|
constructor(cx) {
|
|
11
11
|
this.cx = cx;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* @imports
|
|
4
|
+
*/
|
|
5
|
+
import { _isEmpty } from '@webqit/util/js/index.js';
|
|
6
|
+
import xRequest from "./xRequest.js";
|
|
7
|
+
import xResponse from "./xResponse.js";
|
|
8
|
+
import xURL from "./xURL.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The xHttpEvent Mixin
|
|
12
|
+
*/
|
|
13
|
+
export default class HttpEvent {
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Initializes a new HttpEvent instance.
|
|
17
|
+
*
|
|
18
|
+
* @param Request _request
|
|
19
|
+
* @param Object _detail
|
|
20
|
+
* @param Function _sessionFactory
|
|
21
|
+
* @param Function _storageFactory
|
|
22
|
+
*/
|
|
23
|
+
constructor(_request, _detail, _sessionFactory, _storageFactory) {
|
|
24
|
+
this._request = _request;
|
|
25
|
+
this._detail = _detail || {};
|
|
26
|
+
this._sessionFactory = _sessionFactory;
|
|
27
|
+
this._storageFactory = _storageFactory;
|
|
28
|
+
// -------
|
|
29
|
+
this.Request = xRequest;
|
|
30
|
+
this.Response = xResponse;
|
|
31
|
+
this.URL = xURL;
|
|
32
|
+
// -------
|
|
33
|
+
this.port = {
|
|
34
|
+
listeners: [],
|
|
35
|
+
post(message) {
|
|
36
|
+
const promises = this.listeners.map(listener => listener(message))
|
|
37
|
+
.filter(returnValue => returnValue instanceof Promise);
|
|
38
|
+
if (process.length) return Promise.all(promises);
|
|
39
|
+
},
|
|
40
|
+
listen(listener) { this.listeners.push(listener); },
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// url
|
|
45
|
+
get url() {
|
|
46
|
+
if (!this._url) {
|
|
47
|
+
this._url = new this.URL(this._request.url);
|
|
48
|
+
}
|
|
49
|
+
return this._url;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// request
|
|
53
|
+
get request() {
|
|
54
|
+
return this._request;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// detail
|
|
58
|
+
get detail() {
|
|
59
|
+
return this._detail;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Session
|
|
63
|
+
get session() {
|
|
64
|
+
if (!this._session) {
|
|
65
|
+
this._session = this.sessionFactory();
|
|
66
|
+
}
|
|
67
|
+
return this._session;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Storage
|
|
71
|
+
get storage() {
|
|
72
|
+
if (!this._storage) {
|
|
73
|
+
this._storage = this.storageFactory();
|
|
74
|
+
}
|
|
75
|
+
return this._storage;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Session factory
|
|
79
|
+
sessionFactory(...args) {
|
|
80
|
+
return this._sessionFactory(...args);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// storage factory
|
|
84
|
+
storageFactory(...args) {
|
|
85
|
+
return this._storageFactory(...args);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Redirect Response
|
|
89
|
+
redirect(url, code = 302) {
|
|
90
|
+
return new this.Response(null, { status: code, headers: { Location: url } });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// "with()"
|
|
94
|
+
with(url, init = {}) {
|
|
95
|
+
let request;
|
|
96
|
+
if (url instanceof Request) {
|
|
97
|
+
request = !_isEmpty(init) ? new xRequest(url, init) : url;
|
|
98
|
+
} else {
|
|
99
|
+
url = new this.URL(url, this.url.origin);
|
|
100
|
+
request = new xRequest(url, this._request);
|
|
101
|
+
request = new xRequest(request, { ...init, referrer: this.request.url });
|
|
102
|
+
}
|
|
103
|
+
return new HttpEvent(request, this.detail, this._sessionFactory, this.storageFactory);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
}
|
package/src/runtime-pi/Router.js
CHANGED
|
@@ -58,7 +58,7 @@ export default class Router {
|
|
|
58
58
|
if (thisTick.exports) {
|
|
59
59
|
// Broadcast any hints exported by handler
|
|
60
60
|
if (thisTick.exports.hints) { await event.port.post({ ...thisTick.exports.hints, $type: 'handler:hints' }); }
|
|
61
|
-
const methods = _arrFrom(thisTick.method);
|
|
61
|
+
const methods = _arrFrom(thisTick.method).map(m => m === 'default' ? m : m.toUpperCase());
|
|
62
62
|
const handler = _isFunction(thisTick.exports) && methods.includes('default') ? thisTick.exports : methods.reduce((_handler, name) => _handler || thisTick.exports[name], null);
|
|
63
63
|
if (handler) {
|
|
64
64
|
// -------------
|
|
@@ -74,7 +74,7 @@ export default class Router {
|
|
|
74
74
|
} else if (!_isString(_url)) {
|
|
75
75
|
throw new Error('Router redirect url must be a string!');
|
|
76
76
|
}
|
|
77
|
-
|
|
77
|
+
let newDestination = _url.startsWith('/') ? _url : $this.pathJoin(`/${thisTick.trail.join('/')}`, _url);
|
|
78
78
|
if (newDestination.startsWith('../')) {
|
|
79
79
|
throw new Error('Router redirect cannot traverse beyond the routing directory! (' + _url + ' >> ' + newDestination + ')');
|
|
80
80
|
}
|
|
@@ -89,7 +89,6 @@ export default class Router {
|
|
|
89
89
|
} else {
|
|
90
90
|
nextTick.event = thisTick.event.with(newDestination, requestInit);
|
|
91
91
|
}
|
|
92
|
-
|
|
93
92
|
nextTick.source = thisTick.destination.join('/');
|
|
94
93
|
nextTick.destination = newDestination.split('?').shift().split('/').map(a => a.trim()).filter(a => a);
|
|
95
94
|
nextTick.trail = _args[1].startsWith('/') ? [] : thisTick.trail.reduce((_commonRoot, _seg, i) => _commonRoot.length === i && _seg === nextTick.destination[i] ? _commonRoot.concat(_seg) : _commonRoot, []);
|
|
@@ -12,10 +12,10 @@ import { _isFunction } from "@webqit/util/js/index.js";
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
export default class Runtime {
|
|
15
|
-
constructor(cx,
|
|
15
|
+
constructor(cx, applicationInstance) {
|
|
16
16
|
this.cx = cx;
|
|
17
17
|
this.cx.runtime = this;
|
|
18
|
-
this.
|
|
19
|
-
if (!this.
|
|
18
|
+
this.app = _isFunction(applicationInstance) ? applicationInstance(this.cx) : applicationInstance;
|
|
19
|
+
if (!this.app || !this.app.handle) throw new Error(`Application instance must define a ".handle()" method.`);
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* @imports
|
|
4
4
|
*/
|
|
5
5
|
import Router from './Router.js';
|
|
6
|
-
import
|
|
6
|
+
import _Application from '../Application.js';
|
|
7
7
|
|
|
8
|
-
export default class
|
|
8
|
+
export default class Application extends _Application {
|
|
9
9
|
|
|
10
10
|
// Returns router class
|
|
11
11
|
get Router() {
|
|
@@ -27,8 +27,16 @@ export default class RuntimeClient extends _RuntimeClient {
|
|
|
27
27
|
// --------
|
|
28
28
|
// ROUTE FOR DATA
|
|
29
29
|
// --------
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
return router.route([httpEvent.request.method, 'default'], httpEvent, { ...( document.state?.data || {} ) }, async event => {
|
|
31
|
+
if (event !== httpEvent) {
|
|
32
|
+
// This was nexted()
|
|
33
|
+
if (!event.request.headers.has('Accept')) {
|
|
34
|
+
event.request.headers.set('Accept', 'application/json');
|
|
35
|
+
}
|
|
36
|
+
if (event.request.body && !event.request.headers.has('Content-Type')) {
|
|
37
|
+
event.request.headers.set('Content-Type', 'application/json');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
32
40
|
return remoteFetch(event.request);
|
|
33
41
|
}, remoteFetch);
|
|
34
42
|
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* @imports
|
|
4
4
|
*/
|
|
5
|
-
import { path as Path } from '../util.js';
|
|
5
|
+
import { path as Path } from '../util-url.js';
|
|
6
6
|
import _Router from '../Router.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -14,6 +14,7 @@ import _Router from '../Router.js';
|
|
|
14
14
|
export default class Router extends _Router {
|
|
15
15
|
|
|
16
16
|
async readTick(thisTick) {
|
|
17
|
+
thisTick = { ...thisTick };
|
|
17
18
|
var routeTree = this.cx.layout;
|
|
18
19
|
var routePaths = Object.keys(this.cx.layout);
|
|
19
20
|
if (thisTick.trail) {
|
|
@@ -25,8 +26,8 @@ export default class Router extends _Router {
|
|
|
25
26
|
routePaths.filter(p => p.startsWith(`${_currentPath}/`)).length ? { seg: _seg, dirExists: true } : _segmentOnFile
|
|
26
27
|
);
|
|
27
28
|
}, { seg: null });
|
|
28
|
-
thisTick.trail.
|
|
29
|
-
thisTick.trailOnFile.
|
|
29
|
+
thisTick.trail = thisTick.trail.concat(thisTick.currentSegment);
|
|
30
|
+
thisTick.trailOnFile = thisTick.trailOnFile.concat(thisTick.currentSegmentOnFile.seg);
|
|
30
31
|
thisTick.exports = routeTree[thisTick.currentSegmentOnFile.index];
|
|
31
32
|
} else {
|
|
32
33
|
thisTick.trail = [];
|