@iebh/tera-fy 1.7.4 → 1.9.0

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.
@@ -0,0 +1,115 @@
1
+ import {create as createDomain} from 'node:domain';
2
+ import detectPort from 'detect-port';
3
+ import Proxy from 'http-proxy';
4
+
5
+ export class TeraProxy {
6
+ /**
7
+ * Setup a local loopback proxy for TERA-tools.com
8
+ *
9
+ * @param {Object} [options] Additional options to mutate behaviour
10
+ * @param {Boolean} [options.force=false] Restart the server even if its apparently running
11
+ * @param {Boolean} [options.autoStart=true] Automatically start the proxy without calling `Plugin.start()`
12
+ * @param {String} [options.host='0.0.0.0'] Host IP to listen on
13
+ * @param {Number} [options.port=7334] Host port to listen on
14
+ * @param {String} [options.targetProtocol='https'] Target protocol to forward to
15
+ * @param {String} [options.targetHost='tera-tools.com'] Target host to forward to
16
+ * @param {Number} [options.targetPort=443] Target port to forward to
17
+ * @param {'ignore'|'throw'} [options.portConflict='ignore'] Action to take when something is already listening on the allocated port
18
+ * @param {Function} [options.onLog=console.log] Function to call with any logging output. Defaults to using console.log. Called as `(level:'INFO|'WARN', ...msg:any)`
19
+ *
20
+ * @returns {VitePlugin}
21
+ */
22
+ settings = {
23
+ autoStart: true,
24
+ force: false,
25
+ host: '0.0.0.0',
26
+ port: 7334,
27
+ targetProtocol: 'https',
28
+ targetHost: 'tera-tools.com',
29
+ targetPort: 443,
30
+ portConflict: 'ignore',
31
+ onLog: (level, ...msg) => console.log(...msg),
32
+ }
33
+
34
+
35
+ /**
36
+ * Eventual proxy server when the plugin has booted
37
+ * @type {ProxyServer}
38
+ */
39
+ proxyServer;
40
+
41
+
42
+ /**
43
+ * Boot the proxy
44
+ *
45
+ * @returns {Promise} A promise which resolves when the operation has completed
46
+ */
47
+ start() {
48
+ if (this.proxyServer && !this.settings.force) return Promise.resolve(); // Server already running skip
49
+
50
+ return Promise.resolve()
51
+ .then(()=> detectPort(this.settings.port))
52
+ .then(gotPort => gotPort != this.settings.port && Promise.reject('PORT-CONFLICT'))
53
+ .then(() => this.proxyServer = Proxy.createProxyServer({ // Create proxy pass-thru
54
+ changeOrigin: true,
55
+ target: {
56
+ protocol: this.settings.targetProtocol + ':',
57
+ host: this.settings.targetHost,
58
+ port: this.settings.targetPort,
59
+ },
60
+ }))
61
+ .then(()=> new Promise((resolve, reject) => {
62
+ // Wrap listener in a domain so we can correctly catch EADDRINUSE
63
+ let domain = createDomain();
64
+ domain.on('error', err => {
65
+ if (err.code == 'EADDRINUSE') {
66
+ throw 'PORT-CONFLICT';
67
+ } else {
68
+ throw err;
69
+ }
70
+ });
71
+ this.proxyServer.listen(this.settings.port, ()=> {
72
+ this.settings.onLog('INFO', 'Routing TERA traffic from', `http://${this.settings.host}:${this.settings.port}`, '→', `${this.settings.targetProtocol}://${this.settings.targetHost}:${this.settings.targetPort}`);
73
+ resolve();
74
+ })
75
+ }))
76
+ .catch(e => {
77
+ if (e === 'PORT-CONFLICT') {
78
+ if (this.settings.portConflict == 'ignore') {
79
+ this.settings.onLog('WARN', 'Port', this.settings.port, 'is already allocated - assuming TERA is already running locally and skipping proxy');
80
+ return false; // Do nothing
81
+ } else {
82
+ throw err;
83
+ }
84
+ } else {
85
+ throw e; // Re-throw everything else
86
+ }
87
+ })
88
+ }
89
+
90
+
91
+ /**
92
+ * Stop the proxy server
93
+ * @returns {Promise} A promise which will resolve when the close operation has completed
94
+ */
95
+ stop() {
96
+ return Promise.resolve()
97
+ .then(()=> this.proxyServer && new Promise(resolve => this.proxyServer.close(()=> resolve())))
98
+ }
99
+
100
+
101
+ constructor(options) {
102
+ if (options) Object.assign(this.settings, options);
103
+
104
+ // Auto start?
105
+ if (options?.autoStart ?? true) this.start();
106
+ }
107
+ }
108
+
109
+
110
+ /**
111
+ * Utility function to return a new TeraProxy instance
112
+ */
113
+ export default function(options) {
114
+ return new TeraProxy(options);
115
+ }
@@ -327,6 +327,17 @@ export default class TeraFyServer {
327
327
  payload: args,
328
328
  });
329
329
  }
330
+
331
+
332
+ /**
333
+ * RPC callback to set the server verbostiy level
334
+ *
335
+ * @param {Number} verbosity The desired server verbosity level
336
+ */
337
+ setServerVerbosity(verbosity) {
338
+ this.settinigs.verbosity = +verbosity;
339
+ this.debug('INFO', 1, 'Server verbosity set to', this.settinigs.verbosity);
340
+ }
330
341
  // }}}
331
342
 
332
343
  // Session / User - getUser(), requireUser() {{{
@@ -1345,7 +1356,7 @@ export default class TeraFyServer {
1345
1356
  }
1346
1357
  // }}}
1347
1358
 
1348
- // UI - uiAlert() {{{
1359
+ // UI - uiAlert(), uiProgress(), uiWindow(), uiSplat() {{{
1349
1360
  /**
1350
1361
  * Display simple text within TERA
1351
1362
  *
@@ -1380,6 +1391,63 @@ export default class TeraFyServer {
1380
1391
  }
1381
1392
 
1382
1393
 
1394
+ /**
1395
+ * Display, update or dispose of windows for long running tasks
1396
+ * All options are cumulative - i.e. they are merged with other options previously provided
1397
+ *
1398
+ * @param {Object|Boolean} [options] Additional options to mutate behaviour, if boolean false `{close: true}` is assumed
1399
+ * @param {String} [options.title='TERA'] Window title, can only be set on the initial call
1400
+ * @param {String} [options.body=''] Window body text, can only be set on the initial call
1401
+ * @param {Boolean} [options.bodyHtml=false] Treat body text as HTML
1402
+ * @param {Boolean} [options.close=false] Close the existing dialog, if true the dialog is disposed and options reset
1403
+ *
1404
+ * @FIXME None of the below have been implemented yet
1405
+ * @param {String} [options.text] The text of the task being conducted
1406
+ * @param {Number} [options.progress] The current progress of the task being conducted, this is assumed to be a value less than `maxProgress`
1407
+ * @param {Number} [options.maxProgress] The maximum value that the progress can be
1408
+ *
1409
+ * @returns {Promise} A promise which resolves when the dialog has been updated
1410
+ */
1411
+ uiProgress(options) {
1412
+ if (options === false) { // Close existing ui progress window
1413
+ uiProgressOptions.close = true;
1414
+ } else if (!this.uiProgressOptions) { // New uiProgress window
1415
+ this.uiProgressOptions = {
1416
+ title: 'TERA',
1417
+ body: '',
1418
+ bodyHtml: false,
1419
+ close: false,
1420
+ ...options,
1421
+ };
1422
+ } else { // Merge options with existing uiProgress window
1423
+ Object.assign(this.uiProgressOptions, options);
1424
+ }
1425
+
1426
+ console.log('FIXME: UI PROGRESS - is unfinished', {options: this.uiProgressOptions});
1427
+
1428
+ if (!this.uiProgressPromise && !this.uiProgressOptions.close) { // Not created the dialog yet
1429
+ this.uiProgressPromise = this.requestFocus(()=>
1430
+ app.service('$prompt').dialog({
1431
+ title: this.uiProgressOptions.title,
1432
+ body: this.uiProgressOptions.body,
1433
+ isHtml: this.uiProgressOptions.bodyHtml,
1434
+ })
1435
+ );
1436
+ return Promise.resolve();
1437
+ } else if (!this.uiProgressOptions.close) { // Asked to close the dialog
1438
+ return Promise.resolve()
1439
+ .then(()=> this.uiProgressPromise && app.service('$prompt').close(true)) // Close the dialog if its open
1440
+ .then(()=> { // Release state
1441
+ this.uiProgressOptions = {};
1442
+ this.uiProgressPromise = null;
1443
+ })
1444
+ }
1445
+ }
1446
+
1447
+ uiProgressOptions;
1448
+ uiProgressPromise;
1449
+
1450
+
1383
1451
  /**
1384
1452
  * Open a popup window containing a new site
1385
1453
  *
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@iebh/tera-fy",
3
- "version": "1.7.4",
3
+ "version": "1.9.0",
4
4
  "description": "TERA website worker",
5
5
  "scripts": {
6
6
  "dev": "esbuild --platform=browser --format=esm --bundle lib/terafy.client.js --outfile=dist/terafy.js --minify --serve --servedir=.",
7
7
  "build": "concurrently 'npm:build:*'",
8
8
  "build:client": "esbuild --platform=browser --format=esm --bundle lib/terafy.client.js --outfile=dist/terafy.js --minify",
9
9
  "build:client:es2019": "esbuild --platform=browser --format=esm --target=es2019 --bundle lib/terafy.client.js --outfile=dist/terafy.es2019.js --minify",
10
- "build:plugins-vue2:es2019": "esbuild --platform=browser --format=esm --target=es2019 --bundle plugins/vue2.js --outfile=dist/plugin.vue2.es2019.js --minify",
10
+ "build:plugins:vue2:es2019": "esbuild --platform=browser --format=esm --target=es2019 --bundle plugins/vue2.js --outfile=dist/plugin.vue2.es2019.js --minify",
11
11
  "build:docs:api": "documentation build lib/terafy.client.js lib/projectFile.js --format html --config documentation.yml --output docs/",
12
12
  "build:docs:markdown": "documentation build lib/terafy.client.js lib/projectFile.js --format md --markdown-toc --output api.md",
13
13
  "lint": "eslint lib plugins utils widgets",
@@ -28,6 +28,7 @@
28
28
  },
29
29
  "./dist/*": "./dist/*",
30
30
  "./projectFile": "./lib/projectFile.js",
31
+ "./proxy": "./lib/terafy.proxy.js",
31
32
  "./server": "./lib/terafy.server.js",
32
33
  "./plugins/*": "./plugins/*.js",
33
34
  "./widgets/*": "./widgets/*"
@@ -68,7 +69,9 @@
68
69
  "node": ">=18"
69
70
  },
70
71
  "dependencies": {
72
+ "detect-port": "^1.6.1",
71
73
  "filesize": "^10.1.1",
74
+ "http-proxy": "^1.18.1",
72
75
  "just-diff": "^6.0.2",
73
76
  "lodash-es": "^4.17.21",
74
77
  "mitt": "^3.0.1",
@@ -0,0 +1,18 @@
1
+ import TeraProxy from '../lib/terafy.proxy.js';
2
+
3
+ /**
4
+ * Setup a Vite local loopback
5
+ *
6
+ * @see lib/terafy.proxy.js
7
+ *
8
+ * @returns {VitePlugin}
9
+ */
10
+ export default function vitePluginTeraFy(options) {
11
+ TeraProxy(options);
12
+
13
+ // Vite output
14
+ return {
15
+ name: 'tera-fy',
16
+ apply: 'dev', // Only run on dev-serve-mode rather than each build
17
+ }
18
+ }
package/plugins/vue2.js CHANGED
@@ -17,7 +17,7 @@ import TeraFyPluginBase from './base.js';
17
17
  * import TerafyVue from '@iebh/tera-fy/plugins/vue2';
18
18
  * let terafy = new TeraFy()
19
19
  * .set('devMode', true) // Uncomment this line if you want TeraFy to be chatty
20
- * .set('siteUrl', 'http://localhost:8000/embed') // Uncomment this line if running TERA locally
20
+ * .set('siteUrl', 'http://localhost:7334/embed') // Uncomment this line if running TERA locally
21
21
  * .use(TerafyVue, { // Add the Vue plugin
22
22
  * vue: window.Vue, // Assumes Vue is available on the window object
23
23
  * })
package/plugins/vue3.js CHANGED
@@ -14,7 +14,7 @@ import {reactive, watch} from 'vue';
14
14
  * import TerafyVue from '@iebh/tera-fy/plugins/vue';
15
15
  * let terafy = new TeraFy()
16
16
  * .set('devMode', import.meta.env.DEV)
17
- * .set('siteUrl', 'http://localhost:8000/embed') // Uncomment this line if running TERA locally
17
+ * .set('siteUrl', 'http://localhost:7334/embed') // Uncomment this line if running TERA locally
18
18
  * .use(TerafyVue) // Add the Vue plugin
19
19
  *
20
20
  * terafy.init(); // Initialize everything