@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.
Files changed (36) hide show
  1. package/README.md +9 -4
  2. package/api.md +445 -431
  3. package/dist/terafy.js +2 -2
  4. package/dist/terafy.js.map +4 -4
  5. package/docs/assets/anchor.js +350 -0
  6. package/docs/assets/bass-addons.css +12 -0
  7. package/docs/assets/bass.css +544 -0
  8. package/docs/assets/fonts/EOT/SourceCodePro-Bold.eot +0 -0
  9. package/docs/assets/fonts/EOT/SourceCodePro-Regular.eot +0 -0
  10. package/docs/assets/fonts/LICENSE.txt +93 -0
  11. package/docs/assets/fonts/OTF/SourceCodePro-Bold.otf +0 -0
  12. package/docs/assets/fonts/OTF/SourceCodePro-Regular.otf +0 -0
  13. package/docs/assets/fonts/TTF/SourceCodePro-Bold.ttf +0 -0
  14. package/docs/assets/fonts/TTF/SourceCodePro-Regular.ttf +0 -0
  15. package/docs/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff +0 -0
  16. package/docs/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff +0 -0
  17. package/docs/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff +0 -0
  18. package/docs/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff +0 -0
  19. package/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2 +0 -0
  20. package/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2 +0 -0
  21. package/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2 +0 -0
  22. package/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2 +0 -0
  23. package/docs/assets/fonts/source-code-pro.css +23 -0
  24. package/docs/assets/github.css +123 -0
  25. package/docs/assets/site.js +168 -0
  26. package/docs/assets/split.css +15 -0
  27. package/docs/assets/split.js +782 -0
  28. package/docs/assets/style.css +147 -0
  29. package/docs/index.html +3636 -0
  30. package/{index.html → docs/playground.html} +48 -12
  31. package/documentation.yml +12 -0
  32. package/lib/terafy.client.js +230 -6
  33. package/lib/terafy.server.js +192 -10
  34. package/package.json +7 -6
  35. package/plugins/vue2.js +173 -0
  36. 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.8",
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": "jsdoc2md --files lib/terafy.*.js plugins/*.js >api.md",
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
- "esbuild": "^0.19.5",
73
- "eslint": "^8.47.0",
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",
@@ -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: false, // already handled this
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
- let diff = diff(newVal, oldVal);
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
- // TODO: It would be nice if this was responsive to remote changes
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
  ]))