biz-a-cli 2.3.57 → 2.3.59
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/acert/cert.pem +30 -0
- package/acert/key.pem +27 -0
- package/acert/root.pem +29 -0
- package/bin/app.js +182 -283
- package/bin/debug.log +8 -0
- package/bin/deployEvent.js +105 -0
- package/bin/directHubEvent.js +46 -25
- package/bin/hub.js +5 -6
- package/bin/hubEvent.js +5 -2
- package/bin/script.js +125 -0
- package/bin/uploadApp.js +1 -1
- package/debug.log +2 -0
- package/log/debug.log +280 -0
- package/log/error.log +281 -0
- package/log/exception.log +101 -0
- package/log/info.log +279 -0
- package/package.json +8 -5
- package/tests/app.test.js +92 -28
- package/tests/debug.log +4 -0
- package/tests/deployment.test.js +351 -0
- package/tests/hub.test.js +8 -7
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { prepareScript, encryptScript } from './script.js';
|
|
3
|
+
import { IDLE_SOCKET_TIMEOUT_MILLISECONDS } from './hubEvent.js';
|
|
4
|
+
import { CLIENT_ROOM } from './directHubEvent.js';
|
|
5
|
+
|
|
6
|
+
export async function getAppData(apiOpts){
|
|
7
|
+
return await axios.request({
|
|
8
|
+
timeout : IDLE_SOCKET_TIMEOUT_MILLISECONDS,
|
|
9
|
+
baseURL : `${apiOpts['secure']==true ? 'https://' : 'http://'}${apiOpts['hostname']}:${apiOpts['port']}`,
|
|
10
|
+
url : 'fina/rest/TOrmMethod/%22list%22',
|
|
11
|
+
method : 'POST',
|
|
12
|
+
"data" : {
|
|
13
|
+
"dbIndex": apiOpts['dbindex'],
|
|
14
|
+
"object":{
|
|
15
|
+
"columns":[
|
|
16
|
+
{"title":"app", "data":"SYS$APPS.APPNAME"},
|
|
17
|
+
{"title":"metadata", "data":"SYS$APPS.METADATA"}
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
.then(response=>{
|
|
23
|
+
return {error: null, apps: JSON.parse(response.data.data)};
|
|
24
|
+
})
|
|
25
|
+
.catch(err=>{
|
|
26
|
+
return {"error": ((err && (err instanceof Error)) ? err.message : err), apps: []};
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
async function getDeployScript(serverUrl, appList, data){
|
|
31
|
+
let script = await prepareScript(data.fileName, data.script, false);
|
|
32
|
+
if (script) {
|
|
33
|
+
script = await axios.request({
|
|
34
|
+
timeout : IDLE_SOCKET_TIMEOUT_MILLISECONDS,
|
|
35
|
+
baseURL : serverUrl,
|
|
36
|
+
url : 'api/acquirerKey',
|
|
37
|
+
method : 'POST',
|
|
38
|
+
"data" : {"metadata": JSON.stringify(JSON.parse((appList.find((app)=>app['SYS$APPS.APPNAME']===data.appName))['SYS$APPS.METADATA'])['acquirer'])},
|
|
39
|
+
})
|
|
40
|
+
.then(response=>encryptScript(script, response.data).toString('base64'));
|
|
41
|
+
};
|
|
42
|
+
return script;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export async function onScriptChangeFromVsCode(sock, serverUrl, appList, data){
|
|
46
|
+
let script;
|
|
47
|
+
try {
|
|
48
|
+
script = await getDeployScript(serverUrl, appList, data);
|
|
49
|
+
if (script) {
|
|
50
|
+
sock.to(CLIENT_ROOM).emit('scriptDeploy', {...data, ...{script}});
|
|
51
|
+
return {error: null, script};
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
throw new Error('Invalid Script');
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
return {"error": ((err && (err instanceof Error)) ? err.message : err), script};
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const addAppListListener = (sock,argv)=>{
|
|
63
|
+
sock.on('appList', async (data, cb)=>{
|
|
64
|
+
const result = await getAppData(argv);
|
|
65
|
+
cb(result.error, ((result.error) ? [] : result.apps.map((app)=>app['SYS$APPS.APPNAME'])));
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const addOnScriptChangeListener = (sock, argv, deployFn)=>{
|
|
70
|
+
sock.on('scriptChange', async (data, cb)=>{
|
|
71
|
+
const result = await getAppData(argv);
|
|
72
|
+
if (result.error) {
|
|
73
|
+
cb(result);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
const deployResult = await deployFn(result.apps, data);
|
|
77
|
+
cb(deployResult.error, deployResult.script);
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const deploymentListenerForVSCode = (socket, argv)=>{
|
|
83
|
+
addAppListListener(socket,argv);
|
|
84
|
+
addOnScriptChangeListener(socket, argv, async (apps, data)=>{
|
|
85
|
+
return (await onScriptChangeFromVsCode(socket, argv['server'], apps, data));
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export async function onScriptChangeFromHubServer(serverUrl, appList, data){
|
|
90
|
+
let script;
|
|
91
|
+
try {
|
|
92
|
+
script = await getDeployScript(serverUrl, appList, data);
|
|
93
|
+
return {error: (script ? null : 'Invalid Script'), script};
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
return {"error": ((err && (err instanceof Error)) ? err.message : err), script};
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const deploymentListenerForHubServer = (socket, argv)=>{
|
|
101
|
+
addAppListListener(socket, argv);
|
|
102
|
+
addOnScriptChangeListener(socket, argv, async (apps, data)=>{
|
|
103
|
+
return (await onScriptChangeFromHubServer(argv['server'], apps, data));
|
|
104
|
+
});
|
|
105
|
+
};
|
package/bin/directHubEvent.js
CHANGED
|
@@ -1,49 +1,70 @@
|
|
|
1
|
-
import { apiRequestListener } from './hubEvent.js'
|
|
1
|
+
import { apiRequestListener, RECONNECT_SOCKET_DELAY } from './hubEvent.js'
|
|
2
|
+
import { deploymentListenerForVSCode } from './deployEvent.js'
|
|
2
3
|
import { Tunnel as QuickTunnel } from 'cloudflared'
|
|
3
4
|
|
|
5
|
+
export const CLIENT_ROOM = 'clientRoom'
|
|
6
|
+
|
|
4
7
|
export async function localhostTunnel(port, notifier){
|
|
5
|
-
let tunnelUrl = ''
|
|
6
|
-
let qt = QuickTunnel.quick('127.0.0.1:'+port)
|
|
8
|
+
let tunnelUrl = '';
|
|
9
|
+
let qt = QuickTunnel.quick('127.0.0.1:'+port);
|
|
10
|
+
function reconnectTunnel(){
|
|
11
|
+
setTimeout(()=>{qt = localhostTunnel(port, notifier)}, RECONNECT_SOCKET_DELAY);
|
|
12
|
+
};
|
|
7
13
|
qt.on('url', (qtUrl)=>{
|
|
8
14
|
// console.log('qt url', qtUrl)
|
|
9
|
-
tunnelUrl = qtUrl
|
|
15
|
+
tunnelUrl = qtUrl;
|
|
10
16
|
})
|
|
11
|
-
|
|
17
|
+
.on('connected', (conn)=>{
|
|
12
18
|
// console.log('qt connect', conn)
|
|
13
|
-
notifier(tunnelUrl)
|
|
14
|
-
console.log(`${new Date()}: Connected to Direct Hub at public URL`)
|
|
19
|
+
notifier(tunnelUrl);
|
|
20
|
+
console.log(`${new Date()}: Connected to Direct Hub at public URL ${tunnelUrl}`)
|
|
15
21
|
})
|
|
16
|
-
|
|
22
|
+
.on('disconnected', (conn)=>{
|
|
17
23
|
// console.log('qt disconnect', conn)
|
|
18
|
-
notifier('')
|
|
19
|
-
qt.stop
|
|
24
|
+
notifier('');
|
|
25
|
+
qt.stop();
|
|
20
26
|
})
|
|
21
|
-
|
|
27
|
+
.on('error', (err)=>{
|
|
22
28
|
// console.log('qt err', err)
|
|
23
|
-
notifier('')
|
|
24
|
-
qt.stop
|
|
29
|
+
notifier('');
|
|
30
|
+
qt.stop();
|
|
25
31
|
})
|
|
26
|
-
|
|
32
|
+
.on('exit', (code)=>{
|
|
27
33
|
// console.log('qt exit', code)
|
|
28
|
-
notifier('')
|
|
29
|
-
console.log(`${new Date()}: Direct Hub is not available, will try to reinitiate it in
|
|
30
|
-
|
|
31
|
-
})
|
|
32
|
-
//
|
|
34
|
+
notifier('');
|
|
35
|
+
console.log(`${new Date()}: Direct Hub is not available, will try to reinitiate it in ${RECONNECT_SOCKET_DELAY/1000} seconds. Error code : `, code);
|
|
36
|
+
reconnectTunnel();
|
|
37
|
+
// })
|
|
38
|
+
// on('stdout', (data)=>{
|
|
33
39
|
// console.log('qt stdout', data)
|
|
34
40
|
// })
|
|
35
|
-
//
|
|
41
|
+
// on('stderr', (data)=>{
|
|
36
42
|
// console.log('qt stderr', data)
|
|
37
|
-
|
|
43
|
+
});
|
|
38
44
|
return qt
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
export function directHubEvent(serverSocket, argv){
|
|
42
48
|
serverSocket.on('connection', (clientSocket) => {
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
clientSocket
|
|
49
|
+
if (clientSocket.handshake.query.isClient) {
|
|
50
|
+
clientSocket.join(CLIENT_ROOM);
|
|
51
|
+
apiRequestListener(clientSocket, argv);
|
|
46
52
|
}
|
|
47
|
-
|
|
53
|
+
else if (clientSocket.handshake.query.isDeploy) {
|
|
54
|
+
deploymentListenerForVSCode(clientSocket, argv)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// shall not log in production mode
|
|
58
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
59
|
+
const id = `<${clientSocket.handshake?.query?.isClient ? `Client` : clientSocket.handshake?.query?.isDeploy ? 'Deployer' : 'Anonymous'}> ${clientSocket.id}`;
|
|
60
|
+
clientSocket.on('disconnect', (reason)=>{
|
|
61
|
+
console.log(id, `disconnected. Reason : ${reason}`)
|
|
62
|
+
})
|
|
63
|
+
console.log(id, `connected`)
|
|
64
|
+
};
|
|
48
65
|
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function getSocketCORSOrigin(cliIpAddress){
|
|
69
|
+
return ['https://biz-a.id', 'https://test.biz-a.id', /\.biz-a\.id$/, 'vscode-file://vscode-app', /\.vscode-cdn\.net$/].concat((process.env.NODE_ENV === 'production') ? [] : [`http://${cliIpAddress}:4200`, 'http://localhost:4200'])
|
|
49
70
|
}
|
package/bin/hub.js
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import yargs from 'yargs';
|
|
4
4
|
import { io as ioClient } from "socket.io-client";
|
|
5
|
-
import { streamEvent, hubEvent } from './hubEvent.js'
|
|
5
|
+
import { streamEvent, hubEvent, RECONNECT_SOCKET_DELAY } from './hubEvent.js'
|
|
6
6
|
import { createLogger, transports, format } from "winston";
|
|
7
7
|
import { Server as ioServer } from 'socket.io'
|
|
8
8
|
import os from 'node:os'
|
|
9
|
-
import { directHubEvent, localhostTunnel }from './directHubEvent.js'
|
|
9
|
+
import { directHubEvent, localhostTunnel, getSocketCORSOrigin }from './directHubEvent.js'
|
|
10
10
|
import { env } from "../envs/env.js"
|
|
11
11
|
|
|
12
12
|
const logger = createLogger({
|
|
@@ -149,16 +149,15 @@ await streamEvent(ioClient(argv['server'], {query: {isSockStream: true }}), argv
|
|
|
149
149
|
|
|
150
150
|
// as socket client to BizA HUB
|
|
151
151
|
if (argv.hub) {
|
|
152
|
-
hubEvent(ioClient(argv['hub'], { reconnectionDelay:
|
|
152
|
+
hubEvent(ioClient(argv['hub'], { reconnectionDelay: RECONNECT_SOCKET_DELAY, reconnectionDelayMax: RECONNECT_SOCKET_DELAY, query: {isCLI: true, room: argv['subdomain']} }), argv, (url)=>{
|
|
153
153
|
if (url!==argv.connectedHubUrl) {
|
|
154
154
|
argv.connectedHubUrl = url
|
|
155
155
|
}
|
|
156
156
|
})
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
// as socket server
|
|
160
|
-
|
|
161
|
-
directHubEvent(new ioServer(server, {cors: {origin: serverCORSOrigin}}), argv);
|
|
159
|
+
// as socket server for BizA Client and BizA devTools
|
|
160
|
+
directHubEvent(new ioServer(server, {cors: {origin: getSocketCORSOrigin(argv.cliAddress().ip)}}), argv);
|
|
162
161
|
if (argv.publish==true) {
|
|
163
162
|
localhostTunnel(argv.serverport, (url)=>{ // publish CLI
|
|
164
163
|
if (url!==argv.connectedPublicUrl) {
|
package/bin/hubEvent.js
CHANGED
|
@@ -6,8 +6,10 @@ const require = createRequire(import.meta.url);
|
|
|
6
6
|
const ss = require('socket.io-stream'); //SCY: Temporary, next will be replaced with import
|
|
7
7
|
import { Transform } from 'node:stream'
|
|
8
8
|
// import { pipeline } from 'node:stream'
|
|
9
|
+
import { deploymentListenerForHubServer } from './deployEvent.js';
|
|
9
10
|
|
|
10
|
-
const IDLE_SOCKET_TIMEOUT_MILLISECONDS = 1000 * 30;
|
|
11
|
+
export const IDLE_SOCKET_TIMEOUT_MILLISECONDS = 1000 * 30;
|
|
12
|
+
export const RECONNECT_SOCKET_DELAY = 60 * 1000;
|
|
11
13
|
const DISCONNECT_REASON_BY_SOCKET_SERVER = 'io server disconnect'
|
|
12
14
|
|
|
13
15
|
export const socketAgent = isUsingHttps=>(isUsingHttps==true) ? tls : net
|
|
@@ -156,7 +158,8 @@ export const hubEvent = (socket, argv, notifier)=>{
|
|
|
156
158
|
notifier('')
|
|
157
159
|
console.log(`${new Date()}: ${getIdText(id)}reconnecting to BizA Hub`)
|
|
158
160
|
})
|
|
159
|
-
apiRequestListener(socket, argv)
|
|
161
|
+
apiRequestListener(socket, argv);
|
|
162
|
+
deploymentListenerForHubServer(socket, argv);
|
|
160
163
|
}
|
|
161
164
|
|
|
162
165
|
export const apiRequestListener = (socket, argv)=>{
|
package/bin/script.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { runInNewContext } from "vm"
|
|
2
|
+
import uglify from "uglify-js"
|
|
3
|
+
import * as vm from 'node:vm'
|
|
4
|
+
import { randomBytes, createCipheriv } from "node:crypto"
|
|
5
|
+
|
|
6
|
+
export const prepareScript = async (file, script, shallLog=false) => {
|
|
7
|
+
|
|
8
|
+
const printInfo = (msg) => {
|
|
9
|
+
if (shallLog) {
|
|
10
|
+
console.log(msg)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const minifyiedWithUglify = (fileName, scriptText)=>{
|
|
15
|
+
const minifyResult = uglify.minify(scriptText, {compress: false, mangle: false})
|
|
16
|
+
if (minifyResult.error ) {throw (`${fileName}:${minifyResult.error.line}:${minifyResult.error.col}: ` + minifyResult.error)}
|
|
17
|
+
|
|
18
|
+
let jsMinData = minifyResult.code
|
|
19
|
+
jsMinData = jsMinData.replace('module.exports=get;', '') // Ex : at "executeBlockLib.js" of Imamatek App, will throw error. We need this line code for testing or debugging
|
|
20
|
+
|
|
21
|
+
const minifiedBuffer = Buffer.from(jsMinData)
|
|
22
|
+
printInfo(['Minify : \n', minifiedBuffer.toString()].join(''))
|
|
23
|
+
|
|
24
|
+
return minifiedBuffer.toString()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const isJsonFile = (fileName)=>{
|
|
28
|
+
return fileName.split('.').pop().toLowerCase().match(/^(json)$/)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const jsonReplacer = (key, value) =>{
|
|
32
|
+
|
|
33
|
+
// // with line break
|
|
34
|
+
// if (typeof value == 'function') {
|
|
35
|
+
// let arr = value.toString().replace(/(\r\n|\n|\r)/gm, "°").split("°");
|
|
36
|
+
// if (arr.length < 3) throw 'Function must be minimal 3 lines';
|
|
37
|
+
// return [
|
|
38
|
+
// 'window.Function',
|
|
39
|
+
// getParam(arr[0]),
|
|
40
|
+
// arr.slice(1, arr.length - 1)
|
|
41
|
+
// ];
|
|
42
|
+
// } else {
|
|
43
|
+
// return value;
|
|
44
|
+
// }
|
|
45
|
+
|
|
46
|
+
// without line break
|
|
47
|
+
if (typeof value == 'function') {
|
|
48
|
+
const fnScript = value.toString()
|
|
49
|
+
let params, body = ''
|
|
50
|
+
if (fnScript.indexOf('{')==-1) {
|
|
51
|
+
const arr = fnScript.split('=>')
|
|
52
|
+
params = arr[0]
|
|
53
|
+
body = arr.slice(1).join()
|
|
54
|
+
} else {
|
|
55
|
+
params = fnScript.split('{')[0]
|
|
56
|
+
body = fnScript.substring(fnScript.indexOf('{')+1, fnScript.lastIndexOf('}'))
|
|
57
|
+
}
|
|
58
|
+
params = params.replace(/(\s|=>|\(|\)|function)/gim, '')
|
|
59
|
+
printInfo(['window.Function', params, body])
|
|
60
|
+
return ['window.Function', params, body]
|
|
61
|
+
} else {
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const compileScriptWithNodeVM = (fileName, scriptText)=>{
|
|
67
|
+
try {
|
|
68
|
+
printInfo('Running script with VM')
|
|
69
|
+
const minifiedScript = minifyiedWithUglify(fileName, scriptText)
|
|
70
|
+
if (isJsonFile(fileName)) {
|
|
71
|
+
const vmResult = runInNewContext(minifiedScript)
|
|
72
|
+
return vmResult ? JSON.stringify((typeof vmResult=='function') ? vmResult() : (vmResult || ''), jsonReplacer) : ''
|
|
73
|
+
} else {
|
|
74
|
+
// for handling "get" function in local scope (let, var, const)
|
|
75
|
+
const sandbox = vm.createContext({'script': ''});
|
|
76
|
+
vm.runInContext(
|
|
77
|
+
minifiedScript + "\n script = (typeof get=='undefined') ? '' : (typeof get=='function') ? get() : (get||'')",
|
|
78
|
+
sandbox
|
|
79
|
+
)
|
|
80
|
+
return JSON.stringify(sandbox.script, jsonReplacer)
|
|
81
|
+
}
|
|
82
|
+
} catch (err){
|
|
83
|
+
printInfo((err.toString().indexOf(fileName)===-1 ? `${fileName} : ` : '') + err) // Do not log it as error, we will try to compile the script using ES6 Import
|
|
84
|
+
return ''
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const compileScriptWithESImport = async (fileName, scriptText)=>{
|
|
89
|
+
try {
|
|
90
|
+
printInfo('Running script with Import function')
|
|
91
|
+
// const lib = await import(`file://${process.cwd()}\\${fileName}`, isJsonFile(fileName) ? {with: {type: "json"}} : {}) // we can not use file import if script in memory
|
|
92
|
+
const lib = await import(`data:text/javascript,${scriptText}`, isJsonFile(fileName) ? {with: {type: "json"}} : {}) // used data import if script in memory
|
|
93
|
+
return JSON.stringify((typeof lib.default=='function') ? lib.default() : (lib.default || ''), jsonReplacer) // remove trailing whitespace
|
|
94
|
+
// stringifyData = stringifyData.replace(/\\r\\n/g,'') // remove line break. We can not do this because "inline css" still requires line breaks
|
|
95
|
+
} catch (error){
|
|
96
|
+
throw(`${fileName} : ` + error)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const isEmptyScript = (scriptText) => {
|
|
101
|
+
return ((typeof scriptText=='undefined') || (scriptText===null) || (scriptText.trim()==='""') || (typeof scriptText=='string' && scriptText.trim().length==0))
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
printInfo(`===================\n${file.toUpperCase()}\n===================`)
|
|
105
|
+
let stringifyData = ''
|
|
106
|
+
try {
|
|
107
|
+
stringifyData = compileScriptWithNodeVM(file, script)
|
|
108
|
+
stringifyData = isEmptyScript(stringifyData) ? await compileScriptWithESImport(file, script) : stringifyData
|
|
109
|
+
if (isEmptyScript(stringifyData)) {
|
|
110
|
+
throw(`${file} : ` + 'Failed to compile template script.\nPlease make sure the script is correct and not returning empty result')
|
|
111
|
+
} else {
|
|
112
|
+
printInfo('Array function :')
|
|
113
|
+
printInfo(['Stringify : \n', stringifyData].join(''))
|
|
114
|
+
}
|
|
115
|
+
return Buffer.from(stringifyData)
|
|
116
|
+
} finally {
|
|
117
|
+
printInfo(`===================\nEOF ${file.toUpperCase()}\n===================`)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export const encryptScript = (data, encryptKey)=>{
|
|
122
|
+
const initializeVector = randomBytes(16) // "iv" is unique for each template file
|
|
123
|
+
const cipher = createCipheriv('aes-256-cbc', Buffer.from(encryptKey, 'base64'), initializeVector)
|
|
124
|
+
return Buffer.concat([initializeVector, cipher.update(data), cipher.final()]) // put "iv" at beginning of cipherText, must seperate it when doing decryption
|
|
125
|
+
}
|
package/bin/uploadApp.js
CHANGED
|
@@ -121,7 +121,7 @@ const getFileMinifiedData = async (fileName) => {
|
|
|
121
121
|
const lib = await import(fn)
|
|
122
122
|
printInfo('Array function :')
|
|
123
123
|
stringifyData = JSON.stringify((typeof lib.default=='function') ? lib.default() : lib.default, replacer)
|
|
124
|
-
stringifyData = stringifyData.replace(/
|
|
124
|
+
stringifyData = stringifyData.replace(/ /g,'') // remove trailing whitespace
|
|
125
125
|
// stringifyData = stringifyData.replace(/\\r\\n/g,'') // remove line break. We don't do this because "inline css" still requires line breaks
|
|
126
126
|
printInfo(['Stringify : \n', stringifyData].join(''))
|
|
127
127
|
} catch (error){
|
package/debug.log
ADDED