@iebh/tera-fy 1.0.8 → 1.0.10
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 +9 -4
- package/api.md +445 -431
- package/dist/terafy.js +2 -2
- package/dist/terafy.js.map +4 -4
- package/docs/assets/anchor.js +350 -0
- package/docs/assets/bass-addons.css +12 -0
- package/docs/assets/bass.css +544 -0
- package/docs/assets/fonts/EOT/SourceCodePro-Bold.eot +0 -0
- package/docs/assets/fonts/EOT/SourceCodePro-Regular.eot +0 -0
- package/docs/assets/fonts/LICENSE.txt +93 -0
- package/docs/assets/fonts/OTF/SourceCodePro-Bold.otf +0 -0
- package/docs/assets/fonts/OTF/SourceCodePro-Regular.otf +0 -0
- package/docs/assets/fonts/TTF/SourceCodePro-Bold.ttf +0 -0
- package/docs/assets/fonts/TTF/SourceCodePro-Regular.ttf +0 -0
- package/docs/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff +0 -0
- package/docs/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff +0 -0
- package/docs/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff +0 -0
- package/docs/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff +0 -0
- package/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2 +0 -0
- package/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2 +0 -0
- package/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2 +0 -0
- package/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2 +0 -0
- package/docs/assets/fonts/source-code-pro.css +23 -0
- package/docs/assets/github.css +123 -0
- package/docs/assets/site.js +168 -0
- package/docs/assets/split.css +15 -0
- package/docs/assets/split.js +782 -0
- package/docs/assets/style.css +147 -0
- package/docs/index.html +3636 -0
- package/{index.html → docs/playground.html} +48 -12
- package/documentation.yml +12 -0
- package/lib/terafy.client.js +230 -6
- package/lib/terafy.server.js +192 -10
- package/package.json +7 -6
- package/plugins/vue2.js +173 -0
- package/plugins/{vue.js → vue3.js} +20 -11
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iebh/tera-fy",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
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=.",
|
|
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 --sourcemap",
|
|
9
|
-
"build:docs": "
|
|
9
|
+
"build:docs:api": "documentation build lib/terafy.client.js --format html --config documentation.yml --output docs/",
|
|
10
|
+
"build:docs:markdown": "documentation build lib/terafy.client.js --format md --markdown-toc --output api.md",
|
|
10
11
|
"lint": "eslint ."
|
|
11
12
|
},
|
|
12
13
|
"type": "module",
|
|
@@ -59,19 +60,19 @@
|
|
|
59
60
|
"node": ">=18"
|
|
60
61
|
},
|
|
61
62
|
"peerDependencies": {
|
|
62
|
-
"just-diff": "^6.0.2",
|
|
63
63
|
"lodash-es": "^4.17.21",
|
|
64
64
|
"nanoid": "^5.0.2"
|
|
65
65
|
},
|
|
66
66
|
"optionalDependencies": {
|
|
67
|
+
"just-diff": "^6.0.2",
|
|
68
|
+
"just-diff-apply": "^5.5.0",
|
|
67
69
|
"vue": "^3.3.7"
|
|
68
70
|
},
|
|
69
71
|
"devDependencies": {
|
|
70
72
|
"@momsfriendlydevco/eslint-config": "^1.0.7",
|
|
71
73
|
"concurrently": "^8.2.2",
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"jsdoc-to-markdown": "^8.0.0"
|
|
74
|
+
"documentation": "^14.0.2",
|
|
75
|
+
"esbuild": "^0.19.5"
|
|
75
76
|
},
|
|
76
77
|
"eslintConfig": {
|
|
77
78
|
"extends": "@momsfriendlydevco",
|
package/plugins/vue2.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import {cloneDeep} from 'lodash-es';
|
|
2
|
+
import TeraFyPluginBase from './base.js';
|
|
3
|
+
import Vue from 'vue';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Vue2 observables plugin
|
|
7
|
+
* Provides the `bindProjectState()` function for Vue based projects
|
|
8
|
+
*
|
|
9
|
+
* This function is expected to be included via the `terafy.use(MODULE, OPTIONS)` syntax rather than directly
|
|
10
|
+
*
|
|
11
|
+
* @class TeraFyPluginVue
|
|
12
|
+
*
|
|
13
|
+
* @example Implementation within a Vue2 project `src/main.js`:
|
|
14
|
+
* // Include the main Tera-Fy core
|
|
15
|
+
* import TeraFy from '@iebh/tera-fy';
|
|
16
|
+
* import TerafyVue from '@iebh/tera-fy/plugins/vue2';
|
|
17
|
+
* let terafy = new TeraFy()
|
|
18
|
+
* .set('devMode', true) // Uncomment this line if you want TeraFy to be chatty
|
|
19
|
+
* .set('siteUrl', 'http://localhost:8000/embed') // Uncomment this line if running TERA locally
|
|
20
|
+
* .use(TerafyVue) // Add the Vue plugin
|
|
21
|
+
*
|
|
22
|
+
* // Include after app boot
|
|
23
|
+
* const app = new Vue({ ... })
|
|
24
|
+
* app.$mount("#app");
|
|
25
|
+
* await terafy.init({app});
|
|
26
|
+
*/
|
|
27
|
+
export default class TeraFyPluginVue2 extends TeraFyPluginBase {
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Return a Vue Observable object that can be read/written which whose changes will transparently be written back to the TERA server instance
|
|
31
|
+
*
|
|
32
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
33
|
+
* @param {VueComponent} [options.component] Component to use to bind $watch events
|
|
34
|
+
* @param {String} [options.componentKey] Key within the component to attach the state. Defaults to a random string
|
|
35
|
+
* @param {Boolean} [options.autoRequire=true] Run `requireProject()` automatically before continuing
|
|
36
|
+
* @param {String|Boolean} [options.bindKey='project'] If set, creates the binding also as the specified key within the main Tera object, if falsy just returns the observable
|
|
37
|
+
* @param {Boolean} [options.write=true] Allow local reactivity to writes - send these to the server
|
|
38
|
+
*
|
|
39
|
+
* @returns {Promie<VueObservable<Object>>} A Vue.Observable object representing the project state
|
|
40
|
+
*/
|
|
41
|
+
bindProjectState(options) {
|
|
42
|
+
let settings = {
|
|
43
|
+
component: null,
|
|
44
|
+
componentKey: null,
|
|
45
|
+
autoRequire: true,
|
|
46
|
+
write: true,
|
|
47
|
+
...options,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return Promise.resolve()
|
|
51
|
+
.then(()=> Promise.all([
|
|
52
|
+
// Fetch initial state {{{
|
|
53
|
+
this.getProjectState({
|
|
54
|
+
autoRequire: settings.autoRequire,
|
|
55
|
+
}),
|
|
56
|
+
// }}}
|
|
57
|
+
// Allocate component[componentKey] to stash our observable {{{
|
|
58
|
+
(()=> {
|
|
59
|
+
if (settings.componentKey) return; // Already allocated by user
|
|
60
|
+
for (let x = 0; x < 50; x++) {
|
|
61
|
+
let key = `terafy_${x}`;
|
|
62
|
+
if (!Object.hasOwnProperty(settings.component, key)) { // eslint-disable-line
|
|
63
|
+
settings.componentKey = key;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
throw new Error('Unable to find unique key to allocate against Vue2 component');
|
|
68
|
+
})(),
|
|
69
|
+
// }}}
|
|
70
|
+
]))
|
|
71
|
+
.then(([snapshot]) => {
|
|
72
|
+
this.debug('Got project snapshot', snapshot);
|
|
73
|
+
|
|
74
|
+
// Create initial Observable
|
|
75
|
+
let stateObservable = Vue.observable(snapshot);
|
|
76
|
+
|
|
77
|
+
// Allocate to component
|
|
78
|
+
settings.component[settings.componentKey] = stateObservable;
|
|
79
|
+
|
|
80
|
+
// Watch for remote changes and update
|
|
81
|
+
// FIXME: Not yet supported
|
|
82
|
+
|
|
83
|
+
// Watch for local writes and react
|
|
84
|
+
if (settings.write) {
|
|
85
|
+
if (!settings.component) throw new Error('bindProjectState requires a VueComponent specified as `component`');
|
|
86
|
+
|
|
87
|
+
// NOTE: The below $watch function returns two copies of the new value of the observed so we have to keep track
|
|
88
|
+
// of what changed ourselves by initalizing against the snapshot
|
|
89
|
+
let oldVal = cloneDeep(snapshot);
|
|
90
|
+
|
|
91
|
+
settings.component.$watch(
|
|
92
|
+
settings.componentKey,
|
|
93
|
+
newVal => {
|
|
94
|
+
this.createProjectStatePatch(newVal, oldVal);
|
|
95
|
+
oldVal = cloneDeep(snapshot);
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
deep: true,
|
|
99
|
+
},
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Return Vue Reactive
|
|
104
|
+
return stateObservable;
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* List of available projects for the current session
|
|
111
|
+
* @type {VueReactive<Array<Object>>}
|
|
112
|
+
*/
|
|
113
|
+
projects = Vue.observable([]);
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The bound, reactive state of a Vue project
|
|
118
|
+
* When loaded this represents the state of a project as an object
|
|
119
|
+
* @type {Object}
|
|
120
|
+
*/
|
|
121
|
+
state = null;
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Install into Vue@2
|
|
126
|
+
*
|
|
127
|
+
* @param {Object} [options] Additional options to mutate behaviour (defaults to the main teraFy settings)
|
|
128
|
+
* @param {String} [options.globalName='$tera'] Global property to allocate this service as within Vue2
|
|
129
|
+
* @param {Boolean} [options.subscribeState=true] Setup `vm.$tera.state` as a live binding on init
|
|
130
|
+
* @param {Boolean} [options.subscribeList=true] Setup `vm.$tera.projects` as a list of accesible projects on init
|
|
131
|
+
* @param {Objecct} [options.stateOptions] Options passed to `bindProjectState()` when setting up the main state
|
|
132
|
+
*
|
|
133
|
+
* @returns {Promise} A Promise which will resolve when the init process has completed
|
|
134
|
+
*/
|
|
135
|
+
init(options) {
|
|
136
|
+
let settings = {
|
|
137
|
+
globalName: '$tera',
|
|
138
|
+
subscribeState: true,
|
|
139
|
+
subscribeProjects: true,
|
|
140
|
+
stateOptions: {
|
|
141
|
+
write: true,
|
|
142
|
+
},
|
|
143
|
+
...options,
|
|
144
|
+
};
|
|
145
|
+
if (!this.settings.app) throw new Error('Need to specify the root level Vue2 app during init');
|
|
146
|
+
settings.stateOptions.app = this.settings.app;
|
|
147
|
+
|
|
148
|
+
// Make this module available globally
|
|
149
|
+
if (settings.globalName)
|
|
150
|
+
Vue.prototype[settings.globalName] = this;
|
|
151
|
+
|
|
152
|
+
// Bind `state` to the active project
|
|
153
|
+
// Initialize state to null
|
|
154
|
+
this.state = null;
|
|
155
|
+
|
|
156
|
+
// this.statePromisable becomes the promise we are waiting on to resolve
|
|
157
|
+
return Promise.resolve()
|
|
158
|
+
.then(()=> Promise.all([
|
|
159
|
+
// Bind available project and wait on it
|
|
160
|
+
settings.subscribeState && this.bindProjectState({
|
|
161
|
+
...settings.stateOptions,
|
|
162
|
+
component: this.settings.app.$root,
|
|
163
|
+
})
|
|
164
|
+
.then(state => this.state = state)
|
|
165
|
+
.then(()=> this.debug('INFO', 'Loaded project state', this.state)),
|
|
166
|
+
|
|
167
|
+
// Fetch available projects
|
|
168
|
+
settings.subscribeProjects && this.getProjects()
|
|
169
|
+
.then(projects => this.projects = Vue.observable(projects))
|
|
170
|
+
.then(()=> this.debug('INFO', 'Loaded projects', this.projects)),
|
|
171
|
+
]))
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import TeraFyPluginBase from './base.js';
|
|
2
|
-
import {diff} from 'just-diff';
|
|
3
2
|
import {reactive, watch} from 'vue';
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -9,6 +8,20 @@ import {reactive, watch} from 'vue';
|
|
|
9
8
|
* This function is expected to be included via the `terafy.use(MODULE, OPTIONS)` syntax rather than directly
|
|
10
9
|
*
|
|
11
10
|
* @class TeraFyPluginVue
|
|
11
|
+
*
|
|
12
|
+
* @example Implementation within a Vue3 / Vite project within `src/main.js`:
|
|
13
|
+
* import TeraFy from '@iebh/tera-fy';
|
|
14
|
+
* import TerafyVue from '@iebh/tera-fy/plugins/vue';
|
|
15
|
+
* let terafy = new TeraFy()
|
|
16
|
+
* .set('devMode', import.meta.env.DEV)
|
|
17
|
+
* .set('siteUrl', 'http://localhost:8000/embed') // Uncomment this line if running TERA locally
|
|
18
|
+
* .use(TerafyVue) // Add the Vue plugin
|
|
19
|
+
*
|
|
20
|
+
* terafy.init(); // Initialize everything
|
|
21
|
+
*
|
|
22
|
+
* app.use(terafy.vuePlugin({
|
|
23
|
+
* globalName: '$tera', // Install as vm.$tera into every component
|
|
24
|
+
* }));
|
|
12
25
|
*/
|
|
13
26
|
export default class TeraFyPluginVue extends TeraFyPluginBase {
|
|
14
27
|
|
|
@@ -18,7 +31,6 @@ export default class TeraFyPluginVue extends TeraFyPluginBase {
|
|
|
18
31
|
* @param {Object} [options] Additional options to mutate behaviour
|
|
19
32
|
* @param {Boolean} [options.autoRequire=true] Run `requireProject()` automatically before continuing
|
|
20
33
|
* @param {Boolean} [options.write=true] Allow local reactivity to writes - send these to the server
|
|
21
|
-
* @param {Array<String>} Paths to subscribe to e.g. ['/users/'],
|
|
22
34
|
*
|
|
23
35
|
* @returns {Promie<Reactive<Object>>} A reactive object representing the project state
|
|
24
36
|
*/
|
|
@@ -30,10 +42,8 @@ export default class TeraFyPluginVue extends TeraFyPluginBase {
|
|
|
30
42
|
};
|
|
31
43
|
|
|
32
44
|
return Promise.resolve()
|
|
33
|
-
.then(()=> settings.autoRequire && this.requireProject())
|
|
34
45
|
.then(()=> this.getProjectState({
|
|
35
|
-
autoRequire:
|
|
36
|
-
paths: settings.paths,
|
|
46
|
+
autoRequire: settings.autoRequire ,
|
|
37
47
|
}))
|
|
38
48
|
.then(snapshot => {
|
|
39
49
|
this.debug('Got project snapshot', snapshot);
|
|
@@ -49,9 +59,7 @@ export default class TeraFyPluginVue extends TeraFyPluginBase {
|
|
|
49
59
|
watch(
|
|
50
60
|
stateReactive,
|
|
51
61
|
(newVal, oldVal) => {
|
|
52
|
-
|
|
53
|
-
this.debug('APPLY DIFF', diff);
|
|
54
|
-
this.applyProjectStatePatch(diff);
|
|
62
|
+
this.createProojectStatePatch(newVal, oldVal);
|
|
55
63
|
},
|
|
56
64
|
{
|
|
57
65
|
deep: true,
|
|
@@ -121,6 +129,8 @@ export default class TeraFyPluginVue extends TeraFyPluginBase {
|
|
|
121
129
|
let settings = {
|
|
122
130
|
autoInit: true,
|
|
123
131
|
globalName: '$tera',
|
|
132
|
+
subscribeState: true,
|
|
133
|
+
subscribeProjects: true,
|
|
124
134
|
stateOptions: {
|
|
125
135
|
write: true,
|
|
126
136
|
},
|
|
@@ -136,13 +146,12 @@ export default class TeraFyPluginVue extends TeraFyPluginBase {
|
|
|
136
146
|
.then(()=> settings.autoInit && $tera.init())
|
|
137
147
|
.then(()=> Promise.all([
|
|
138
148
|
// Bind available project and wait on it
|
|
139
|
-
$tera.bindProjectState(settings.stateOptions)
|
|
149
|
+
settings.subscribeState && $tera.bindProjectState(settings.stateOptions)
|
|
140
150
|
.then(state => $tera.state = state)
|
|
141
151
|
.then(()=> $tera.debug('INFO', 'Loaded project state', $tera.state)),
|
|
142
152
|
|
|
143
153
|
// Fetch available projects
|
|
144
|
-
|
|
145
|
-
$tera.getProjects()
|
|
154
|
+
settings.subscribeProjects && $tera.getProjects()
|
|
146
155
|
.then(projects => $tera.projects = reactive(projects))
|
|
147
156
|
.then(()=> $tera.debug('INFO', 'Loaded projects', $tera.projects)),
|
|
148
157
|
]))
|