@qelos/plugin-play 2.0.22
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/.nvmrc +1 -0
- package/LICENSE +21 -0
- package/create-cert.js +6 -0
- package/dist/examples/basic-demo.d.ts +1 -0
- package/dist/examples/basic-demo.js +38 -0
- package/dist/examples/basic-demo.js.map +1 -0
- package/dist/examples/stocks/server.d.ts +1 -0
- package/dist/examples/stocks/server.js +47 -0
- package/dist/examples/stocks/server.js.map +1 -0
- package/dist/examples/todos/server.d.ts +1 -0
- package/dist/examples/todos/server.js +64 -0
- package/dist/examples/todos/server.js.map +1 -0
- package/dist/src/app.d.ts +16 -0
- package/dist/src/app.js +130 -0
- package/dist/src/app.js.map +1 -0
- package/dist/src/authentication.d.ts +20 -0
- package/dist/src/authentication.js +292 -0
- package/dist/src/authentication.js.map +1 -0
- package/dist/src/config.d.ts +17 -0
- package/dist/src/config.js +20 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/endpoints.d.ts +5 -0
- package/dist/src/endpoints.js +21 -0
- package/dist/src/endpoints.js.map +1 -0
- package/dist/src/handlers.d.ts +47 -0
- package/dist/src/handlers.js +32 -0
- package/dist/src/handlers.js.map +1 -0
- package/dist/src/index.d.ts +25 -0
- package/dist/src/index.js +15 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/manifest.d.ts +33 -0
- package/dist/src/manifest.js +24 -0
- package/dist/src/manifest.js.map +1 -0
- package/dist/src/sdk.d.ts +5 -0
- package/dist/src/sdk.js +49 -0
- package/dist/src/sdk.js.map +1 -0
- package/examples/basic-demo.ts +43 -0
- package/examples/stocks/public/assets/AMZN.png +0 -0
- package/examples/stocks/public/assets/GOOGL.png +0 -0
- package/examples/stocks/public/assets/META.png +0 -0
- package/examples/stocks/public/assets/MSFT.png +0 -0
- package/examples/stocks/public/future-client-sdk.js +30 -0
- package/examples/stocks/public/index.html +29 -0
- package/examples/stocks/public/main.js +56 -0
- package/examples/stocks/server.ts +51 -0
- package/examples/todos/public/index.html +13 -0
- package/examples/todos/public/main.js +70 -0
- package/examples/todos/server.ts +66 -0
- package/package.json +30 -0
- package/src/app.ts +152 -0
- package/src/authentication.ts +321 -0
- package/src/config.ts +24 -0
- package/src/endpoints.ts +24 -0
- package/src/handlers.ts +52 -0
- package/src/index.ts +36 -0
- package/src/manifest.ts +31 -0
- package/src/sdk.ts +53 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {start, registerToHook, addMicroFrontend, getSdkForTenant} from '../src';
|
|
2
|
+
|
|
3
|
+
registerToHook({source: 'content', path: 'my-hook'}, async (request) => {
|
|
4
|
+
console.log('yay')
|
|
5
|
+
console.log(request.body);
|
|
6
|
+
const sdk = await getSdkForTenant(request.tenantPayload);
|
|
7
|
+
|
|
8
|
+
console.log(await sdk.blocks.getList());
|
|
9
|
+
|
|
10
|
+
return {message: 'king'};
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
addMicroFrontend({
|
|
14
|
+
name: 'league',
|
|
15
|
+
url: 'https://www.monkeyleague.io/#team',
|
|
16
|
+
description: 'google it',
|
|
17
|
+
route: {
|
|
18
|
+
name: 'custom-demo',
|
|
19
|
+
path: 'league',
|
|
20
|
+
navBarPosition: 'top',
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
addMicroFrontend({
|
|
25
|
+
name: 'David',
|
|
26
|
+
url: 'https://www.davidlevy.co.il/wallak/vue-react-rectivity',
|
|
27
|
+
description: 'tweet it',
|
|
28
|
+
route: {
|
|
29
|
+
name: 'davidlevy',
|
|
30
|
+
path: 'davidlevy',
|
|
31
|
+
navBarPosition: 'top',
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
start({
|
|
36
|
+
config: {
|
|
37
|
+
accessTokenSecret: 'demo-secret',
|
|
38
|
+
refreshTokenSecret: 'refresh-token-secret',
|
|
39
|
+
greenpressUrl: 'http://localhost:3000',
|
|
40
|
+
greenpressUsername: 'test@test.com',
|
|
41
|
+
greenpressPassword: 'admin',
|
|
42
|
+
},
|
|
43
|
+
});
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const code = (new URL(location.href)).searchParams.get('code');
|
|
2
|
+
|
|
3
|
+
export async function unAuthorize() {
|
|
4
|
+
await fetch('/api/un-authorize', {
|
|
5
|
+
method: 'post',
|
|
6
|
+
headers: {
|
|
7
|
+
code
|
|
8
|
+
},
|
|
9
|
+
})
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function authorize() {
|
|
13
|
+
const returnUrl = location.href.replace(location.search, '');
|
|
14
|
+
const token = (new URL(location.href)).searchParams.get('token');
|
|
15
|
+
|
|
16
|
+
const res = await fetch('/api/authorize', {
|
|
17
|
+
method: 'post',
|
|
18
|
+
headers: {
|
|
19
|
+
'content-type': 'application/json',
|
|
20
|
+
},
|
|
21
|
+
body: JSON.stringify({
|
|
22
|
+
returnUrl,
|
|
23
|
+
token
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
window.addEventListener('beforeunload', unAuthorize);
|
|
28
|
+
|
|
29
|
+
return res.json();
|
|
30
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>Stocks</title>
|
|
6
|
+
<script type="module" src="main.js"></script>
|
|
7
|
+
<style>
|
|
8
|
+
table, iframe {width: 100%;}
|
|
9
|
+
td {width: 50%;text-align: center;padding: 10px;}
|
|
10
|
+
img {max-width: 100%;}
|
|
11
|
+
input {padding: 10px;border-radius: 5px;border: 1px solid #eee;}
|
|
12
|
+
</style>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<h1>Stocks!</h1>
|
|
16
|
+
<div id="app">
|
|
17
|
+
<table>
|
|
18
|
+
<tr>
|
|
19
|
+
<th><input class="stock-0-input"></th>
|
|
20
|
+
<th><input class="stock-1-input"></th>
|
|
21
|
+
</tr>
|
|
22
|
+
<tr>
|
|
23
|
+
<td class="stock-0-view"></td>
|
|
24
|
+
<td class="stock-1-view"></td>
|
|
25
|
+
</tr>
|
|
26
|
+
</table>
|
|
27
|
+
</div>
|
|
28
|
+
</body>
|
|
29
|
+
</html>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import {authorize, code} from ''
|
|
2
|
+
|
|
3
|
+
const {user, tenant} = await authorize()
|
|
4
|
+
|
|
5
|
+
console.log(user, tenant)
|
|
6
|
+
|
|
7
|
+
const inputs = [
|
|
8
|
+
document.querySelector('.stock-0-input'),
|
|
9
|
+
document.querySelector('.stock-1-input'),
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
const viewers = [
|
|
13
|
+
document.querySelector('.stock-0-view'),
|
|
14
|
+
document.querySelector('.stock-1-view'),
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
async function fetchStocks() {
|
|
18
|
+
const res = await fetch('/api/get', {
|
|
19
|
+
headers: {
|
|
20
|
+
code
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const stocks = await res.json()
|
|
25
|
+
|
|
26
|
+
stocks.forEach((stock, i) => {
|
|
27
|
+
inputs[i].value = stock;
|
|
28
|
+
viewers[i].innerHTML = `<img src="/assets/${stock}.png">`
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function updateStocks() {
|
|
33
|
+
const res = await fetch('/api/set', {
|
|
34
|
+
method: 'post',
|
|
35
|
+
headers: {
|
|
36
|
+
'content-type': 'application/json',
|
|
37
|
+
code
|
|
38
|
+
},
|
|
39
|
+
body: JSON.stringify(inputs.map(input => input.value))
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const stocks = await res.json()
|
|
43
|
+
|
|
44
|
+
stocks.forEach((stock, i) => {
|
|
45
|
+
viewers[i].innerHTML = `<img src="/assets/${stock}.png">`
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
inputs.forEach(input => {
|
|
50
|
+
input.addEventListener('change', () => {
|
|
51
|
+
updateStocks();
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
await fetchStocks();
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {start, addMicroFrontend, addEndpoint} from '../../src';
|
|
2
|
+
import {join} from 'path';
|
|
3
|
+
|
|
4
|
+
let stocks = ['GOOGL', 'META']
|
|
5
|
+
|
|
6
|
+
addMicroFrontend({
|
|
7
|
+
name: 'Stocks',
|
|
8
|
+
url: 'index.html',
|
|
9
|
+
description: 'My Stocks',
|
|
10
|
+
route: {
|
|
11
|
+
name: 'Stocks',
|
|
12
|
+
path: 'stocks',
|
|
13
|
+
navBarPosition: 'top',
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
addEndpoint('/api/get', {
|
|
18
|
+
async handler(req) {
|
|
19
|
+
return stocks
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
addEndpoint('/api/set', {
|
|
24
|
+
method: 'POST',
|
|
25
|
+
async handler(req) {
|
|
26
|
+
const body: any = req.body || stocks;
|
|
27
|
+
if(body instanceof Array) {
|
|
28
|
+
stocks = body;
|
|
29
|
+
}
|
|
30
|
+
return stocks;
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
start({
|
|
35
|
+
manifest: {
|
|
36
|
+
name: '@examples/stocks',
|
|
37
|
+
apiPath: '@examples:stocks'
|
|
38
|
+
},
|
|
39
|
+
config: {
|
|
40
|
+
port: '1087',
|
|
41
|
+
accessTokenSecret: 'demo-secret',
|
|
42
|
+
refreshTokenSecret: 'refresh-token-secret',
|
|
43
|
+
greenpressUrl: 'http://localhost:3000',
|
|
44
|
+
greenpressUsername: 'test@test.com',
|
|
45
|
+
greenpressPassword: 'admin',
|
|
46
|
+
staticFrontend: {
|
|
47
|
+
root: join(__dirname, 'public'),
|
|
48
|
+
prefix: '/'
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>TODOS</title>
|
|
6
|
+
<script type="module" src="main.js"></script>
|
|
7
|
+
<style>.box {border-radius: 5px; background-color: #fff4c2; padding: 10px; margin: 10px;}</style>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<h1>Todos!</h1>
|
|
11
|
+
<div id="app"></div>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
console.log(location);
|
|
2
|
+
const code = (new URL(location.href)).searchParams.get('code');
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
async function authorize() {
|
|
6
|
+
const returnUrl = location.href.replace(location.search, '');
|
|
7
|
+
const token = (new URL(location.href)).searchParams.get('token');
|
|
8
|
+
|
|
9
|
+
await fetch('/api/authorize', {
|
|
10
|
+
method: 'post',
|
|
11
|
+
headers: {
|
|
12
|
+
'content-type': 'application/json',
|
|
13
|
+
},
|
|
14
|
+
body: JSON.stringify({
|
|
15
|
+
returnUrl,
|
|
16
|
+
token
|
|
17
|
+
})
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function fetchTodos() {
|
|
22
|
+
const res = await fetch('/api/todos', {
|
|
23
|
+
headers: {
|
|
24
|
+
code
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const todos = await res.json()
|
|
29
|
+
|
|
30
|
+
document.querySelector('#app').innerHTML = `<add-todo>ADD</add-todo>` + todos.map(todo => {
|
|
31
|
+
return `<div class="box">
|
|
32
|
+
<h3>${todo.name}</h3>
|
|
33
|
+
<div>${todo.content}</div>
|
|
34
|
+
</div>`
|
|
35
|
+
}).join('')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
class AddTodoButton extends HTMLElement {
|
|
39
|
+
async add() {
|
|
40
|
+
const name = prompt('choose a name');
|
|
41
|
+
const content = prompt('add content');
|
|
42
|
+
if (!(name && content)) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
await fetch('/api/add-todos', {
|
|
47
|
+
method: 'post',
|
|
48
|
+
headers: {
|
|
49
|
+
'content-type': 'application/json',
|
|
50
|
+
code
|
|
51
|
+
},
|
|
52
|
+
body: JSON.stringify({
|
|
53
|
+
name,
|
|
54
|
+
content
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
await fetchTodos();
|
|
59
|
+
}
|
|
60
|
+
constructor() {
|
|
61
|
+
super();
|
|
62
|
+
this.addEventListener('click', () => this.add());
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
customElements.define('add-todo', AddTodoButton)
|
|
67
|
+
|
|
68
|
+
await authorize()
|
|
69
|
+
await fetchTodos();
|
|
70
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import {start, addMicroFrontend, addEndpoint, getSdkForTenant} from '../../src';
|
|
2
|
+
import {join} from 'path';
|
|
3
|
+
|
|
4
|
+
addMicroFrontend({
|
|
5
|
+
name: 'Todos',
|
|
6
|
+
url: 'index.html',
|
|
7
|
+
description: 'Todos List',
|
|
8
|
+
route: {
|
|
9
|
+
name: 'Todos',
|
|
10
|
+
path: 'todos',
|
|
11
|
+
navBarPosition: 'top',
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
addEndpoint('/api/todos', {
|
|
16
|
+
async handler(req) {
|
|
17
|
+
try {
|
|
18
|
+
const sdk = await getSdkForTenant(req.tenantPayload);
|
|
19
|
+
if (!sdk) {
|
|
20
|
+
return ['empty'];
|
|
21
|
+
}
|
|
22
|
+
return sdk.blocks.getList();
|
|
23
|
+
} catch {
|
|
24
|
+
//
|
|
25
|
+
}
|
|
26
|
+
return ['no access']
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
addEndpoint('/api/add-todos', {
|
|
31
|
+
method: 'POST',
|
|
32
|
+
async handler(req) {
|
|
33
|
+
const body: any = req.body || {}
|
|
34
|
+
try {
|
|
35
|
+
const sdk = await getSdkForTenant(req.tenantPayload);
|
|
36
|
+
if (!sdk) {
|
|
37
|
+
return ['empty'];
|
|
38
|
+
}
|
|
39
|
+
await sdk.blocks.create({
|
|
40
|
+
name: body.name,
|
|
41
|
+
content: body.content
|
|
42
|
+
})
|
|
43
|
+
} catch {
|
|
44
|
+
//
|
|
45
|
+
}
|
|
46
|
+
return ['no access']
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
start({
|
|
52
|
+
manifest: {
|
|
53
|
+
name: '@examples/todos'
|
|
54
|
+
},
|
|
55
|
+
config: {
|
|
56
|
+
accessTokenSecret: 'demo-secret',
|
|
57
|
+
refreshTokenSecret: 'refresh-token-secret',
|
|
58
|
+
greenpressUrl: 'http://localhost:3000',
|
|
59
|
+
greenpressUsername: 'test@test.com',
|
|
60
|
+
greenpressPassword: 'admin',
|
|
61
|
+
staticFrontend: {
|
|
62
|
+
root: join(__dirname, 'public'),
|
|
63
|
+
prefix: '/'
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@qelos/plugin-play",
|
|
3
|
+
"version": "2.0.22",
|
|
4
|
+
"description": "Play a plugin for Qelos",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"create-certs": "node create-cert.js",
|
|
8
|
+
"demo:basic": "npx tsx watch ./examples/basic-demo.ts",
|
|
9
|
+
"demo:todos": "npx tsx watch ./examples/todos/server.ts",
|
|
10
|
+
"demo:stocks": "npx tsx watch ./examples/stocks/server.ts",
|
|
11
|
+
"build": "tsc"
|
|
12
|
+
},
|
|
13
|
+
"author": "David Meir-Levy <davidmeirlevy@gmail.com>",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@fastify/cookie": "^8.3.0",
|
|
20
|
+
"@fastify/static": "^6.5.0",
|
|
21
|
+
"@qelos/sdk": "^2.0.22",
|
|
22
|
+
"@qelos/web-sdk": "^2.0.22",
|
|
23
|
+
"fastify": "^4.3.0",
|
|
24
|
+
"jsonwebtoken": "^8.5.1",
|
|
25
|
+
"undici": "^5.8.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"typescript": "^4.6.3"
|
|
29
|
+
}
|
|
30
|
+
}
|
package/src/app.ts
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import {existsSync, readFileSync} from 'fs';
|
|
2
|
+
import {join} from 'path';
|
|
3
|
+
import fastify, {FastifyInstance} from 'fastify';
|
|
4
|
+
import {RouteHandlerMethod} from 'fastify/types/route';
|
|
5
|
+
import type {FastifyCookieOptions} from '@fastify/cookie'
|
|
6
|
+
import cookie from '@fastify/cookie'
|
|
7
|
+
import {manifest, ManifestOptions} from './manifest';
|
|
8
|
+
import config, {ConfigOptions, setConfig} from './config';
|
|
9
|
+
import {
|
|
10
|
+
getCallbackRoute,
|
|
11
|
+
getFrontendAuthorizationRoute, getFrontendUnAuthorizationRoute,
|
|
12
|
+
getRefreshTokenRoute,
|
|
13
|
+
getRegisterRoute,
|
|
14
|
+
verifyAccessToken, verifyCookieToken
|
|
15
|
+
} from './authentication';
|
|
16
|
+
import handlers from './handlers';
|
|
17
|
+
import {endpoints} from './endpoints';
|
|
18
|
+
|
|
19
|
+
const hooks = new Set<{ subscribedEvent, path, handler }>();
|
|
20
|
+
|
|
21
|
+
let app: FastifyInstance;
|
|
22
|
+
|
|
23
|
+
export async function start(options?: { manifest?: ManifestOptions, config?: ConfigOptions }) {
|
|
24
|
+
configure(options?.manifest || {}, options?.config || {});
|
|
25
|
+
|
|
26
|
+
const app = getApp();
|
|
27
|
+
try {
|
|
28
|
+
console.log('start application for environment: ', config.dev ? 'development' : 'production');
|
|
29
|
+
await app.listen({port: Number(config.port), host: config.host})
|
|
30
|
+
} catch (err) {
|
|
31
|
+
app.log.error(err);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function configure(manifestOptions: ManifestOptions, appConfig: ConfigOptions) {
|
|
37
|
+
Object.assign(manifest, manifestOptions);
|
|
38
|
+
setConfig(appConfig);
|
|
39
|
+
|
|
40
|
+
if (config.dev && !manifest.appUrl) {
|
|
41
|
+
manifest.appUrl = 'https://' + config.host + ':' + config.port;
|
|
42
|
+
}
|
|
43
|
+
manifest.proxyUrl = new URL(manifest.proxyPath, manifest.appUrl).href;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getApp(): FastifyInstance {
|
|
47
|
+
return app || createApp();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function registerToHook(hook: { source?: string, kind?: string, eventName?: string, path?: string }, handler: RouteHandlerMethod) {
|
|
51
|
+
hook.path = hook.path || btoa(JSON.stringify(hook));
|
|
52
|
+
const subscribedEvent = {
|
|
53
|
+
source: hook.source || '*',
|
|
54
|
+
kind: hook.kind || '*',
|
|
55
|
+
eventName: hook.eventName || '*',
|
|
56
|
+
};
|
|
57
|
+
hooks.add({
|
|
58
|
+
subscribedEvent,
|
|
59
|
+
path: hook.path,
|
|
60
|
+
handler
|
|
61
|
+
});
|
|
62
|
+
manifest.subscribedEvents.push(subscribedEvent);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function createApp(): FastifyInstance {
|
|
66
|
+
app = fastify( {
|
|
67
|
+
logger: !!config.dev,
|
|
68
|
+
https: {
|
|
69
|
+
cert: readFileSync(join(process.cwd(), 'cert/cert.pem')).toString(),
|
|
70
|
+
key: readFileSync(join(process.cwd(), 'cert/key.pem')).toString(),
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
app.addContentTypeParser('application/json', {parseAs: 'string'}, function (req, body, done) {
|
|
75
|
+
try {
|
|
76
|
+
const bodyStr = body.toString() as string;
|
|
77
|
+
done(null, bodyStr ? JSON.parse(bodyStr) : {})
|
|
78
|
+
} catch (err) {
|
|
79
|
+
err.statusCode = 400
|
|
80
|
+
done(err, undefined)
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
app.route(getRefreshTokenRoute());
|
|
85
|
+
app.route(getRegisterRoute());
|
|
86
|
+
app.route(getCallbackRoute());
|
|
87
|
+
playManifest();
|
|
88
|
+
playHooks();
|
|
89
|
+
playEndpoints();
|
|
90
|
+
playFrontend();
|
|
91
|
+
|
|
92
|
+
if (!(config.greenpressUrl || handlers.refreshToken.length)) {
|
|
93
|
+
throw new Error('you must provide either a refresh token handler or Greenpress application credentials');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return app;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function playManifest() {
|
|
100
|
+
getApp().route({
|
|
101
|
+
method: 'GET',
|
|
102
|
+
url: manifest.manifestUrl,
|
|
103
|
+
handler({headers, body}, res) {
|
|
104
|
+
setImmediate(() => handlers.manifest.forEach(cb => cb({headers, body})));
|
|
105
|
+
res.header('Access-Control-Allow-Origin', '*');
|
|
106
|
+
return manifest;
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
console.log('manifest URL: ' + new URL(manifest.manifestUrl, manifest.appUrl).href)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function playHooks() {
|
|
113
|
+
hooks.forEach(hook => {
|
|
114
|
+
const routePath = join('/api/hooks', hook.path);
|
|
115
|
+
hook.subscribedEvent.hookUrl = new URL(routePath, manifest.appUrl).href;
|
|
116
|
+
getApp().route({
|
|
117
|
+
method: 'POST',
|
|
118
|
+
url: routePath,
|
|
119
|
+
preHandler: verifyAccessToken,
|
|
120
|
+
handler: hook.handler
|
|
121
|
+
})
|
|
122
|
+
console.log('subscribed event configured: ', routePath, hook.subscribedEvent);
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function playFrontend() {
|
|
127
|
+
if (existsSync(config.staticFrontend.root)) {
|
|
128
|
+
getApp().register(require('@fastify/static'), config.staticFrontend);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function playEndpoints() {
|
|
133
|
+
if (!endpoints.size) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
getApp().register(cookie, {
|
|
137
|
+
parseOptions: {
|
|
138
|
+
maxAge: 1000 * 60 * 30, // 30 MINUTES,
|
|
139
|
+
secure: true,
|
|
140
|
+
httpOnly: true,
|
|
141
|
+
sameSite: config.dev ? 'none' : true
|
|
142
|
+
}
|
|
143
|
+
} as FastifyCookieOptions);
|
|
144
|
+
getApp().route(getFrontendAuthorizationRoute());
|
|
145
|
+
getApp().route(getFrontendUnAuthorizationRoute());
|
|
146
|
+
endpoints.forEach((routeOptions, path) => {
|
|
147
|
+
getApp().route({
|
|
148
|
+
...routeOptions,
|
|
149
|
+
preHandler: path.startsWith(manifest.apiPath) ? verifyAccessToken : verifyCookieToken
|
|
150
|
+
});
|
|
151
|
+
})
|
|
152
|
+
}
|