@iebh/tera-fy 1.0.1 → 1.0.2
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/dist/terafy.js +14 -3
- package/dist/terafy.js.map +4 -4
- package/docs/terafy.client.md +114 -85
- package/docs/terafy.server.md +220 -98
- package/index.html +52 -4
- package/lib/terafy.client.js +54 -15
- package/lib/terafy.server.js +197 -51
- package/package.json +2 -1
package/lib/terafy.client.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import {cloneDeep} from 'lodash-es';
|
|
1
2
|
import {nanoid} from 'nanoid';
|
|
2
3
|
import {reactive, watch} from 'vue';
|
|
3
4
|
import diff from 'just-diff';
|
|
4
5
|
|
|
6
|
+
/* globals globalThis */
|
|
7
|
+
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* Main Tera-Fy Client (class singleton) to be used in a frontend browser
|
|
@@ -46,14 +49,14 @@ export default class TeraFy {
|
|
|
46
49
|
* @type {Array<String>}
|
|
47
50
|
*/
|
|
48
51
|
methods = [
|
|
49
|
-
//
|
|
52
|
+
// Messages
|
|
50
53
|
'handshake',
|
|
51
54
|
|
|
52
55
|
// Session
|
|
53
56
|
'getUser',
|
|
54
57
|
|
|
55
58
|
// Projects
|
|
56
|
-
'bindProject', 'getProject', 'getProjects', 'requireProject', 'selectProject',
|
|
59
|
+
'bindProject', 'getProject', 'getProjects', 'setActiveProject', 'requireProject', 'selectProject',
|
|
57
60
|
|
|
58
61
|
// Project state
|
|
59
62
|
'getProjectStateSnapshot', 'applyProjectStatePatch',
|
|
@@ -101,7 +104,7 @@ export default class TeraFy {
|
|
|
101
104
|
{
|
|
102
105
|
TERA: 1,
|
|
103
106
|
id: message.id || nanoid(),
|
|
104
|
-
...message,
|
|
107
|
+
...cloneDeep(message), // Need to clone to resolve promise nasties
|
|
105
108
|
},
|
|
106
109
|
this.settings.restrictOrigin
|
|
107
110
|
);
|
|
@@ -113,6 +116,7 @@ export default class TeraFy {
|
|
|
113
116
|
*
|
|
114
117
|
* @param {String} method The method name to call
|
|
115
118
|
* @param {*} [...] Optional arguments to pass to the function
|
|
119
|
+
*
|
|
116
120
|
* @returns {Promise<*>} The resolved output of the server function
|
|
117
121
|
*/
|
|
118
122
|
rpc(method, ...args) {
|
|
@@ -131,18 +135,36 @@ export default class TeraFy {
|
|
|
131
135
|
*/
|
|
132
136
|
acceptMessage(rawMessage) {
|
|
133
137
|
let message = rawMessage.data;
|
|
134
|
-
if (!message.TERA) return; // Ignore non-TERA signed messages
|
|
138
|
+
if (!message.TERA || !message.id) return; // Ignore non-TERA signed messages
|
|
139
|
+
this.debug('Recieved', message);
|
|
135
140
|
|
|
136
|
-
if (message?.
|
|
141
|
+
if (message?.action == 'response' && this.acceptPostboxes[message.id]) { // Postbox waiting for reply
|
|
137
142
|
if (message.isError === true) {
|
|
138
143
|
this.acceptPostboxes[message.id].reject(message.response);
|
|
139
144
|
} else {
|
|
140
145
|
this.acceptPostboxes[message.id].resolve(message.response);
|
|
141
146
|
}
|
|
147
|
+
} else if (message?.action == 'rpc') {
|
|
148
|
+
return Promise.resolve()
|
|
149
|
+
.then(()=> this[message.method].apply(this, message.args))
|
|
150
|
+
.then(res => this.sendRaw({
|
|
151
|
+
id: message.id,
|
|
152
|
+
action: 'response',
|
|
153
|
+
response: res,
|
|
154
|
+
}))
|
|
155
|
+
.catch(e => {
|
|
156
|
+
console.warn(`TERA-FY client threw on RPC:${message.method}:`, e);
|
|
157
|
+
this.sendRaw({
|
|
158
|
+
id: message.id,
|
|
159
|
+
action: 'response',
|
|
160
|
+
isError: true,
|
|
161
|
+
response: e.toString(),
|
|
162
|
+
});
|
|
163
|
+
})
|
|
142
164
|
} else if (message?.id) {
|
|
143
|
-
|
|
165
|
+
this.debug(`Ignoring message ID ${message.id} - was meant for someone else?`);
|
|
144
166
|
} else {
|
|
145
|
-
|
|
167
|
+
this.debug('Unexpected incoming TERA-FY CLIENT message', {message});
|
|
146
168
|
}
|
|
147
169
|
}
|
|
148
170
|
|
|
@@ -209,7 +231,7 @@ export default class TeraFy {
|
|
|
209
231
|
// Queue up event chain when document loads
|
|
210
232
|
this.dom.iframe.setAttribute('sandbox', 'allow-downloads allow-scripts allow-same-origin');
|
|
211
233
|
this.dom.iframe.addEventListener('load', ()=> {
|
|
212
|
-
|
|
234
|
+
this.debug('TERA EMBED FRAME READY');
|
|
213
235
|
});
|
|
214
236
|
|
|
215
237
|
// Start document load sequence + append to DOM
|
|
@@ -250,7 +272,7 @@ export default class TeraFy {
|
|
|
250
272
|
'}',
|
|
251
273
|
|
|
252
274
|
// Fullscreen functionality {{{
|
|
253
|
-
'body.tera-fy-
|
|
275
|
+
'body.tera-fy-focus {',
|
|
254
276
|
'overflow: hidden;',
|
|
255
277
|
|
|
256
278
|
'& #tera-fy {',
|
|
@@ -279,7 +301,23 @@ export default class TeraFy {
|
|
|
279
301
|
}
|
|
280
302
|
// }}}
|
|
281
303
|
|
|
282
|
-
//
|
|
304
|
+
// Utility - debug(), bindProjectState(), toggleFullscreen() {{{
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Debugging output function
|
|
308
|
+
* This function will only act if `settings.devMode` is truthy
|
|
309
|
+
*
|
|
310
|
+
* @param {String} [msg...] Output to show
|
|
311
|
+
*/
|
|
312
|
+
debug(...msg) {
|
|
313
|
+
if (!this.settings.devMode) return;
|
|
314
|
+
console.log(
|
|
315
|
+
'%c[TERA-FY CLIENT]',
|
|
316
|
+
'font-weight: bold; color: #ff5722;',
|
|
317
|
+
...msg,
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
|
|
283
321
|
|
|
284
322
|
/**
|
|
285
323
|
* Return a Vue reactive object that can be read/written which whose changes will transparently be written back to the TERA server instance
|
|
@@ -317,7 +355,7 @@ export default class TeraFy {
|
|
|
317
355
|
stateReactive,
|
|
318
356
|
(newVal, oldVal) => {
|
|
319
357
|
let diff = diff(newVal, oldVal);
|
|
320
|
-
|
|
358
|
+
this.debug('APPLY DIFF', diff);
|
|
321
359
|
this.applyProjectStatePatch(diff);
|
|
322
360
|
},
|
|
323
361
|
{
|
|
@@ -333,12 +371,13 @@ export default class TeraFy {
|
|
|
333
371
|
|
|
334
372
|
|
|
335
373
|
/**
|
|
336
|
-
* Fit the nested TERA server to a full-screen
|
|
374
|
+
* Fit the nested TERA server to a full-screen
|
|
337
375
|
* This is usually because the server component wants to perform some user activity like calling $prompt
|
|
338
|
-
* @param {String|Boolean} [
|
|
376
|
+
* @param {String|Boolean} [isFocused='toggle'] Whether to fullscreen the embedded component
|
|
339
377
|
*/
|
|
340
|
-
|
|
341
|
-
|
|
378
|
+
toggleFocus(isFocused = 'toggle') {
|
|
379
|
+
this.debug('Request focus', {isFocused});
|
|
380
|
+
globalThis.document.body.classList.toggle('tera-fy-focus', isFocused === 'toggle' ? undefined : isFocused);
|
|
342
381
|
}
|
|
343
382
|
|
|
344
383
|
// }}}
|
package/lib/terafy.server.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {cloneDeep} from 'lodash-es';
|
|
2
|
+
import {nanoid} from 'nanoid';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* Server-side functions available to the Tera-Fy client library
|
|
3
6
|
*
|
|
@@ -18,7 +21,102 @@ export default class TeraFyServer {
|
|
|
18
21
|
restrictOrigin: '*',
|
|
19
22
|
};
|
|
20
23
|
|
|
21
|
-
//
|
|
24
|
+
// Contexts - createContext(), messageEvent, senderRpc() {{{
|
|
25
|
+
/**
|
|
26
|
+
* Create a context based on a shallow copy of this instance + additional functionality for the incoming MessageEvent
|
|
27
|
+
* This is used by acceptMessage to provide a means to reply / send messages to the originator
|
|
28
|
+
*
|
|
29
|
+
* @param {MessageEvent} e Original message event to base the new context on
|
|
30
|
+
*
|
|
31
|
+
* @returns {Object} A context, which is this instance extended with additional properties
|
|
32
|
+
*/
|
|
33
|
+
createContext(e) {
|
|
34
|
+
// Rather ugly shallow-copy-of instance hack from https://stackoverflow.com/a/44782052/1295040
|
|
35
|
+
return Object.assign(Object.create(Object.getPrototypeOf(this)), this, {
|
|
36
|
+
messageEvent: e,
|
|
37
|
+
sendRaw(message) { // Override sendRaw because we can't do this inline for security reasons
|
|
38
|
+
this.debug('Send to message source', e.origin, {message});
|
|
39
|
+
e.source.postMessage(
|
|
40
|
+
{
|
|
41
|
+
TERA: 1,
|
|
42
|
+
...cloneDeep(message), // Need to clone to resolve promise nasties
|
|
43
|
+
},
|
|
44
|
+
this.settings.restrictOrigin
|
|
45
|
+
);
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* MessageEvent context
|
|
53
|
+
* Only available if the context was created via `createContext()`
|
|
54
|
+
*
|
|
55
|
+
* @type {MessageEvent}
|
|
56
|
+
*/
|
|
57
|
+
messageEvent = null;
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Request an RPC call from the original sender of a mesasge
|
|
62
|
+
* This function only works if the context was sub-classed via `createContext()`
|
|
63
|
+
*
|
|
64
|
+
* @param {String} method The method name to call
|
|
65
|
+
* @param {*} [...] Optional arguments to pass to the function
|
|
66
|
+
*
|
|
67
|
+
* @returns {Promise<*>} The resolved output of the server function
|
|
68
|
+
*/
|
|
69
|
+
senderRpc(method, ...args) {
|
|
70
|
+
if (!this.messageEvent) throw new Error('senderRpc() can only be used if given a context from `createContext()`');
|
|
71
|
+
|
|
72
|
+
return this.send({
|
|
73
|
+
action: 'rpc',
|
|
74
|
+
method,
|
|
75
|
+
args,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
// }}}
|
|
79
|
+
|
|
80
|
+
// Messages - handshake(), sendRaw(), acceptMessage(), requestFocus() {{{
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Return basic server information as a form of validation
|
|
84
|
+
*
|
|
85
|
+
* @returns {Promise<Object>} Basic promise result
|
|
86
|
+
* @property {Date} date Server date
|
|
87
|
+
*/
|
|
88
|
+
handshake() {
|
|
89
|
+
return {
|
|
90
|
+
date: new Date(),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Send a message + wait for a response object
|
|
97
|
+
*
|
|
98
|
+
* @param {Object} message Message object to send
|
|
99
|
+
* @returns {Promise<*>} A promise which resolves when the operation has completed with the remote reply
|
|
100
|
+
*/
|
|
101
|
+
send(message) {
|
|
102
|
+
if (!this.messageEvent) throw new Error('send() can only be used if given a context from `createContext()`');
|
|
103
|
+
|
|
104
|
+
let id = nanoid();
|
|
105
|
+
|
|
106
|
+
this.acceptPostboxes[id] = {}; // Stub for the deferred promise
|
|
107
|
+
this.acceptPostboxes[id].promise = new Promise((resolve, reject) => {
|
|
108
|
+
Object.assign(this.acceptPostboxes[id], {
|
|
109
|
+
resolve, reject,
|
|
110
|
+
});
|
|
111
|
+
this.sendRaw({
|
|
112
|
+
id,
|
|
113
|
+
...message,
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return this.acceptPostboxes[id].promise;
|
|
118
|
+
}
|
|
119
|
+
|
|
22
120
|
|
|
23
121
|
/**
|
|
24
122
|
* Send raw message content to the client
|
|
@@ -26,10 +124,11 @@ export default class TeraFyServer {
|
|
|
26
124
|
* @param {Object} message Message object to send
|
|
27
125
|
*/
|
|
28
126
|
sendRaw(message) {
|
|
127
|
+
this.debug('SendRaw', {message});
|
|
29
128
|
globalThis.parent.postMessage(
|
|
30
129
|
{
|
|
31
130
|
TERA: 1,
|
|
32
|
-
...message,
|
|
131
|
+
...cloneDeep(message), // Need to clone to resolve promise nasties
|
|
33
132
|
},
|
|
34
133
|
this.settings.restrictOrigin
|
|
35
134
|
);
|
|
@@ -44,15 +143,21 @@ export default class TeraFyServer {
|
|
|
44
143
|
acceptMessage(rawMessage) {
|
|
45
144
|
let message = rawMessage.data;
|
|
46
145
|
if (!message.TERA) return; // Ignore non-TERA signed messages
|
|
47
|
-
|
|
146
|
+
this.debug('Recieved', message);
|
|
48
147
|
|
|
49
148
|
Promise.resolve()
|
|
50
149
|
.then(()=> {
|
|
51
|
-
if (message
|
|
150
|
+
if (message?.action == 'response' && this.acceptPostboxes[message.id]) { // Postbox waiting for reply
|
|
151
|
+
if (message.isError === true) {
|
|
152
|
+
this.acceptPostboxes[message.id].reject(message.response);
|
|
153
|
+
} else {
|
|
154
|
+
this.acceptPostboxes[message.id].resolve(message.response);
|
|
155
|
+
}
|
|
156
|
+
} else if (message.action == 'rpc') { // Relay RPC calls
|
|
52
157
|
if (!this[message.method]) throw new Error(`Unknown RPC method "${message.method}"`);
|
|
53
|
-
return this[message.method].
|
|
158
|
+
return this[message.method].apply(this.createContext(rawMessage), message.args);
|
|
54
159
|
} else {
|
|
55
|
-
|
|
160
|
+
this.debug('Unexpected incoming TERA-FY SERVER message', {message});
|
|
56
161
|
throw new Error('Unknown message format');
|
|
57
162
|
}
|
|
58
163
|
})
|
|
@@ -71,23 +176,32 @@ export default class TeraFyServer {
|
|
|
71
176
|
});
|
|
72
177
|
})
|
|
73
178
|
}
|
|
74
|
-
|
|
75
|
-
// Basics - handshake() {{{
|
|
179
|
+
|
|
76
180
|
|
|
77
181
|
/**
|
|
78
|
-
*
|
|
182
|
+
* Listening postboxes, these correspond to outgoing message IDs that expect a response
|
|
183
|
+
*/
|
|
184
|
+
acceptPostboxes = {};
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Wrapper function which runs a callback after the frontend UI has obtained focus
|
|
189
|
+
* This is to fix the issue where the front-end needs to switch between a regular webpage and a focused TERA iFrame wrapper
|
|
190
|
+
* Any use of $prompt or other UI calls should be wrapped here
|
|
79
191
|
*
|
|
80
|
-
* @
|
|
81
|
-
*
|
|
192
|
+
* @param {Function} cb Async function to run in focused mode
|
|
193
|
+
*
|
|
194
|
+
* @returns {Promise<*>} A promise which resolves with the resulting inner callback payload
|
|
82
195
|
*/
|
|
83
|
-
|
|
84
|
-
return
|
|
85
|
-
|
|
86
|
-
|
|
196
|
+
requestFocus(cb) {
|
|
197
|
+
return Promise.resolve()
|
|
198
|
+
.then(()=> this.senderRpc('toggleFocus', true))
|
|
199
|
+
.then(()=> cb.call(this))
|
|
200
|
+
.finally(()=> this.senderRpc('toggleFocus', false))
|
|
87
201
|
}
|
|
88
202
|
// }}}
|
|
89
203
|
|
|
90
|
-
// Session /
|
|
204
|
+
// Session / User - getUser() {{{
|
|
91
205
|
|
|
92
206
|
/**
|
|
93
207
|
* User / active session within TERA
|
|
@@ -175,14 +289,37 @@ export default class TeraFyServer {
|
|
|
175
289
|
}
|
|
176
290
|
|
|
177
291
|
|
|
292
|
+
/**
|
|
293
|
+
* Set the currently active project within TERA
|
|
294
|
+
*
|
|
295
|
+
* @param {Object|String} project The project to set as active - either the full Project object or its ID
|
|
296
|
+
*/
|
|
297
|
+
setActiveProject(project) {
|
|
298
|
+
return app.service('$projects').setActive(project)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
|
|
178
302
|
/**
|
|
179
303
|
* Ask the user to select a project from those available - if one isn't already active
|
|
180
304
|
* Note that this function will percist in asking the uesr even if they try to cancel
|
|
181
305
|
*
|
|
306
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
307
|
+
* @param {Boolean} [options.autoSetActiveProject=true] After selecting a project set that project as active in TERA
|
|
308
|
+
* @param {String} [options.title="Select a project to work with"] The title of the dialog to display
|
|
309
|
+
* @param {String} [options.noSelectTitle='Select project'] Dialog title when warning the user they need to select something
|
|
310
|
+
* @param {String} [options.noSelectBody='A project needs to be selected to continue'] Dialog body when warning the user they need to select something
|
|
311
|
+
*
|
|
182
312
|
* @returns {Promise<Project>} The active project
|
|
183
313
|
*/
|
|
184
|
-
requireProject() {
|
|
185
|
-
let
|
|
314
|
+
requireProject(options) {
|
|
315
|
+
let settings = {
|
|
316
|
+
autoSetActiveProject: true,
|
|
317
|
+
title: 'Select a project to work with',
|
|
318
|
+
noSelectTitle: 'Select project',
|
|
319
|
+
noSelectBody: 'A project needs to be selected to continue',
|
|
320
|
+
...options,
|
|
321
|
+
};
|
|
322
|
+
|
|
186
323
|
return this.getProject()
|
|
187
324
|
.then(active => {
|
|
188
325
|
if (active) return active; // Use active project
|
|
@@ -195,18 +332,25 @@ export default class TeraFyServer {
|
|
|
195
332
|
.then(project => resolve(project))
|
|
196
333
|
.catch(e => {
|
|
197
334
|
if (e == 'cancel') {
|
|
198
|
-
return
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
335
|
+
return this.requestFocus(()=>
|
|
336
|
+
app.service('$prompt').dialog({
|
|
337
|
+
title: settings.noSelectTitle,
|
|
338
|
+
body: settings.noSelectBody,
|
|
339
|
+
buttons: ['ok'],
|
|
340
|
+
})
|
|
341
|
+
)
|
|
203
342
|
.then(()=> askProject())
|
|
204
343
|
.catch(reject)
|
|
205
344
|
} else {
|
|
206
345
|
reject(e);
|
|
207
346
|
}
|
|
208
347
|
})
|
|
209
|
-
|
|
348
|
+
askProject(); // Kick off intial project loop
|
|
349
|
+
})
|
|
350
|
+
.then(async (project) => {
|
|
351
|
+
if (settings.autoSetActiveProject) await this.setActiveProject(project);
|
|
352
|
+
return project;
|
|
353
|
+
})
|
|
210
354
|
})
|
|
211
355
|
}
|
|
212
356
|
|
|
@@ -226,21 +370,21 @@ export default class TeraFyServer {
|
|
|
226
370
|
allowCancel: true,
|
|
227
371
|
...options,
|
|
228
372
|
};
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
373
|
+
|
|
374
|
+
return app.service('$projects').promise()
|
|
375
|
+
.then(()=> this.requestFocus(()=>
|
|
376
|
+
app.service('$prompt').dialog({
|
|
377
|
+
title: settings.title,
|
|
378
|
+
component: 'projectsSelect',
|
|
379
|
+
buttons: settings.allowCancel && ['cancel'],
|
|
380
|
+
})
|
|
381
|
+
))
|
|
238
382
|
}
|
|
239
383
|
|
|
240
384
|
|
|
241
385
|
// }}}
|
|
242
386
|
|
|
243
|
-
// Project State {{{
|
|
387
|
+
// Project State - getProjectStateSnapshot(), applyProjectStatePatch() {{{
|
|
244
388
|
|
|
245
389
|
/**
|
|
246
390
|
* Return the current, full snapshot state of the active project
|
|
@@ -267,12 +411,12 @@ export default class TeraFyServer {
|
|
|
267
411
|
* Apply a computed `just-diff` patch to the current project state
|
|
268
412
|
*/
|
|
269
413
|
applyProjectStatePatch(patch) {
|
|
270
|
-
|
|
414
|
+
this.debug('Applying sever state patch', {patch});
|
|
271
415
|
}
|
|
272
416
|
|
|
273
417
|
// }}}
|
|
274
418
|
|
|
275
|
-
// Project Libraries {{{
|
|
419
|
+
// Project Libraries - getProjectLibrary(), setProjectLibrary() {{{
|
|
276
420
|
|
|
277
421
|
/**
|
|
278
422
|
* Fetch the active projects citation library
|
|
@@ -336,27 +480,29 @@ export default class TeraFyServer {
|
|
|
336
480
|
|
|
337
481
|
|
|
338
482
|
/**
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
* @param {String|Boolean} [devModeEnabled='toggle'] Optional boolean to force dev mode
|
|
342
|
-
*
|
|
343
|
-
* @returns {TeraFy} This chainable terafy instance
|
|
483
|
+
* Initialize the browser listener
|
|
344
484
|
*/
|
|
345
|
-
|
|
346
|
-
this.
|
|
347
|
-
? !this.settings.devMode
|
|
348
|
-
: devModeEnabled;
|
|
349
|
-
|
|
350
|
-
return this;
|
|
485
|
+
init() {
|
|
486
|
+
globalThis.addEventListener('message', this.acceptMessage.bind(this));
|
|
351
487
|
}
|
|
488
|
+
// }}}
|
|
352
489
|
|
|
490
|
+
// Utility - debug() {{{
|
|
353
491
|
|
|
354
492
|
/**
|
|
355
|
-
*
|
|
493
|
+
* Debugging output function
|
|
494
|
+
* This function will only act if `settings.devMode` is truthy
|
|
495
|
+
*
|
|
496
|
+
* @param {String} [msg...] Output to show
|
|
356
497
|
*/
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
498
|
+
debug(...msg) {
|
|
499
|
+
if (!this.settings.devMode) return;
|
|
500
|
+
console.log(
|
|
501
|
+
'%c[TERA-FY SERVER]',
|
|
502
|
+
'font-weight: bold; color: #4d659c;',
|
|
503
|
+
...msg,
|
|
504
|
+
);
|
|
360
505
|
}
|
|
506
|
+
|
|
361
507
|
// }}}
|
|
362
508
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iebh/tera-fy",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
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 --sourcemap --serve --servedir=.",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"node": ">=18"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
+
"lodash-es": "^4.17.21",
|
|
56
57
|
"just-diff": "^6.0.2",
|
|
57
58
|
"nanoid": "^5.0.2",
|
|
58
59
|
"vue": "^3.3.7"
|