@live-change/vue3-ssr 0.1.5 → 0.1.9

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/Api.js ADDED
@@ -0,0 +1,247 @@
1
+ import { DaoProxy, DaoPrerenderCache, DaoCache, Path } from "@live-change/dao"
2
+ import validators from '@live-change/framework/lib/utils/validators.js'
3
+ import { hashCode, encodeNumber, uidGenerator } from '@live-change/uid'
4
+ import { ref, computed, watch } from "vue"
5
+
6
+ function guid() {
7
+ function s4() {
8
+ return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1)
9
+ }
10
+ return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
11
+ s4() + '-' + s4() + s4() + s4()
12
+ }
13
+
14
+ class Api extends DaoProxy {
15
+ constructor(source, settings = {}) {
16
+ super()
17
+ this.source = source
18
+ this.settings = settings
19
+
20
+ this.uidGenerator = () => { throw new Error("uid generator not initialized yet") }
21
+
22
+ this.createReactiveObject = this.settings.createReactiveObject
23
+
24
+ this.preFetchComponents = []
25
+ this.afterPreFetch = []
26
+
27
+ this.validators = validators
28
+
29
+ this.globals = {
30
+ $validators: validators
31
+ }
32
+ this.globalInstances = []
33
+ }
34
+
35
+ setup(settings = this.settings) {
36
+ this.settings = settings
37
+ this.createReactiveObject = this.settings.createReactiveObject
38
+ this.setupCaches()
39
+ this.setupMetadata()
40
+ }
41
+
42
+ guid() {
43
+ return guid()
44
+ }
45
+
46
+ setupCaches() {
47
+ let dao = this.source
48
+ if(this.settings.cache) {
49
+ const cacheSettings = (typeof this.settings.cache) == 'object' ? this.settings.cache : {}
50
+ this.dataCache = new DaoCache(dao, cacheSettings)
51
+ dao = this.dataCache
52
+ }
53
+ if(this.settings.ssr) {
54
+ this.prerenderCache = new DaoPrerenderCache(dao)
55
+ dao = this.prerenderCache
56
+ if(typeof window == 'undefined') {
57
+ this.prerenderCache.mode = 'save'
58
+ } else {
59
+ this.prerenderCache.mode = 'load'
60
+ this.prerenderCache.setCache(window[this.settings.ssrCacheGlobal || '__DAO_CACHE__'])
61
+ }
62
+ }
63
+ this.setDao(dao)
64
+ }
65
+
66
+ setupMetadata() {
67
+ const api = ref()
68
+ this.apiObservable = this.observable(['metadata', 'api'])
69
+ this.apiObservable.bindProperty(api, 'value')
70
+ const version = ref()
71
+ this.versionObservable = this.observable(['version', 'version'])
72
+ this.versionObservable.bindProperty(version, 'value')
73
+ const softwareVersion = computed(() => {
74
+ if(typeof window == 'undefined') return
75
+ return window[this.settings.ssrVersionGlobal || '__VERSION__']
76
+ })
77
+ const versionMismatch = computed(() => {
78
+ if(!version) return
79
+ if(!softwareVersion) return
80
+ return version.value != softwareVersion.value
81
+ })
82
+ const client = computed(() => {
83
+ return api?.value?.client
84
+ })
85
+ watch(() => api, (api) => {
86
+ console.log("API CHANGE!", api)
87
+ if(!api) return
88
+ console.log("API CHANGE!", api)
89
+ api.generateServicesApi()
90
+ })
91
+ this.metadata = {
92
+ api, version,
93
+ softwareVersion,
94
+ versionMismatch,
95
+ client
96
+ }
97
+ this.afterPreFetch.push(() => this.generateServicesApi())
98
+ }
99
+
100
+ generateServicesApi() {
101
+ const api = this
102
+ let apiInfo = api.metadata.api?.value
103
+ if(!apiInfo) {
104
+ const cachePath = '["metadata","api"]'
105
+ if(typeof window != 'undefined') {
106
+ const ssrCache = window[this.settings.ssrCacheGlobal || '__DAO_CACHE__']
107
+ if(ssrCache) {
108
+ for(const [daoPath, value] of ssrCache) {
109
+ if(daoPath == cachePath) apiInfo = value
110
+ }
111
+ }
112
+ } else {
113
+ apiInfo = this.prerenderCache.cache.get(cachePath)
114
+ }
115
+ }
116
+ console.log("GENERATE SERVICES API", apiInfo)
117
+ const definitions = apiInfo?.services
118
+ if(JSON.stringify(definitions) == JSON.stringify(api.servicesApiDefinitions)) return
119
+ if(!definitions) throw new Error("API DEFINITIONS NOT FOUND! UNABLE TO GENERATE API!")
120
+ api.uidGenerator = uidGenerator(apiInfo.client.user || apiInfo.client.session.slice(0, 16), 1)
121
+ //console.log("GENERATE API DEFINITIONS", definitions)
122
+ api.servicesApiDefinitions = definitions
123
+ let globalViews = {}
124
+ let globalFetch = (...args) => new Path(...args)
125
+ let globalActions = {}
126
+ for(const serviceDefinition of definitions) {
127
+ let views = { }
128
+ globalViews[serviceDefinition.name] = views
129
+ for(const viewName in serviceDefinition.views) {
130
+ views[viewName] = (params) => [serviceDefinition.name, viewName, params]
131
+ views[viewName].definition = serviceDefinition.views[viewName]
132
+ }
133
+ let fetch = { }
134
+ globalFetch[serviceDefinition.name] = fetch
135
+ for(const viewName in serviceDefinition.views) {
136
+ fetch[viewName] = (params) => new Path([serviceDefinition.name, viewName, params])
137
+ fetch[viewName].definition = serviceDefinition.views[viewName]
138
+ }
139
+ let actions = { }
140
+ globalActions[serviceDefinition.name] = actions
141
+ for(const actionName in serviceDefinition.actions) {
142
+ actions[actionName] = (params) => api.command([serviceDefinition.name, actionName], params)
143
+ actions[actionName].definition = serviceDefinition.actions[actionName]
144
+ }
145
+ }
146
+
147
+ api.views = globalViews
148
+ api.fetch = globalFetch
149
+ api.actions = globalActions
150
+ api.client = this.metadata.client
151
+ api.uid = api.uidGenerator
152
+
153
+ api.globals.$lc = api
154
+
155
+ /// Deprecated:
156
+ api.globals.$api = this
157
+ api.globals.$views = this.views
158
+ api.globals.$actions = this.actions
159
+ api.globals.$fetch = this.fetch
160
+
161
+ for(const glob of this.globalInstances) {
162
+ this.installInstanceProperties(glob)
163
+ }
164
+ }
165
+
166
+ addGlobalInstance(globalProperties) {
167
+ this.globalInstances.push(globalProperties)
168
+ this.installInstanceProperties(globalProperties)
169
+ }
170
+
171
+ installInstanceProperties(globalProperties) {
172
+ for(const key in this.globals) {
173
+ globalProperties[key] = this.globals[key]
174
+ }
175
+ }
176
+
177
+ async preFetch() {
178
+ let preFetchPromises = []
179
+ for(const component of this.preFetchComponents) {
180
+ if(component.$options.reactivePreFetch) {
181
+ const paths = component.$options.reactivePreFetch.apply(this.globals)
182
+ console.log("PREFETCH PATHS", JSON.stringify(paths))
183
+ const promise = this.get({ paths })/*.then(results => {
184
+ for(let { what, data } of results) {
185
+ this.prerenderCache.set(what, data)
186
+ }
187
+ })*/// It's useless because DaoPrerenderCache support paths
188
+ preFetchPromises.push(promise)
189
+ }
190
+ }
191
+ preFetchPromises.push(this.get({ paths: [
192
+ { what: ['metadata', 'api'] },
193
+ { what: ['version', 'version'] }
194
+ ]}))
195
+ console.log("PREFETCH WAIT!")
196
+ // const apiPromise = this.apiObservable.wait()
197
+ // apiPromise.then(res => console.log("API RES", res))
198
+ // const versionPromise = this.versionObservable.wait()
199
+ // versionPromise.then(res => console.log("VERSION RES", res))
200
+ // if(this.apiObservable.getValue() === undefined) preFetchPromises.push(apiPromise)
201
+ // if(this.versionObservable.getValue() === undefined) preFetchPromises.push(versionPromise)
202
+ await Promise.all(preFetchPromises)
203
+ console.log("PREFETCHED", this.metadata.api, this.metadata.version)
204
+ for(const afterPreFetch of this.afterPreFetch) {
205
+ afterPreFetch()
206
+ }
207
+ }
208
+
209
+ async preFetchRoute(route, router) {
210
+ let preFetchPromises = []
211
+ for(const matched of route.value.matched) {
212
+ for(const name in matched.components) {
213
+ const component = matched.components[name]
214
+ if(component.reactivePreFetch) {
215
+ let paths = component.reactivePreFetch.call(this.globals, route.value, router)
216
+ //console.log("ROUTE", route, "PREFETCH PATHS", JSON.stringify(paths))
217
+ const promise = this.get({ paths }).then(results => {
218
+ for(let { what, data } of results) {
219
+ this.prerenderCache.set(what, data)
220
+ }
221
+ })
222
+ preFetchPromises.push(promise)
223
+ }
224
+ }
225
+ }
226
+ return Promise.all(preFetchPromises)
227
+ }
228
+
229
+ command(method, args = {}) {
230
+ const _commandId = args._commandId || guid()
231
+ console.trace("COMMAND "+_commandId+":"+JSON.stringify(method))
232
+ return this.request(method, { ...args, _commandId })
233
+ }
234
+
235
+ reverseRange(range) {
236
+ return {
237
+ gt: range.lt,
238
+ gte: range.lte,
239
+ lt: range.gt == '' ? '\xFF\xFF\xFF\xFF' : range.gt,
240
+ lte: range.gte,
241
+ limit: range.limit,
242
+ reverse: !range.reverse
243
+ }
244
+ }
245
+ }
246
+
247
+ export default Api
package/clientApi.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { createReactiveObject } from '@live-change/vue3-components'
2
- import * as lcapi from '@live-change/vue-api'
3
2
  import * as lcdao from '@live-change/dao'
4
3
  import { reactiveMixin, reactivePrefetchMixin, ReactiveObservableList } from '@live-change/dao-vue3'
5
- import { SockJsConnection } from '@live-change/dao-sockjs'
4
+ import SockJsConnection from '@live-change/dao-sockjs'
5
+ import Api from "./Api.js"
6
6
 
7
7
  function clientApi(settings = {}) {
8
8
  const dao = new lcdao.Dao(window.__CREDENTIALS__, {
@@ -13,9 +13,9 @@ function clientApi(settings = {}) {
13
13
 
14
14
  ...settings,
15
15
 
16
- fastAuth: !window.hasOwnProperty('__CREDENTIALS__'),
17
-
18
16
  connectionSettings: {
17
+ fastAuth: !window.hasOwnProperty('__CREDENTIALS__'),
18
+
19
19
  queueRequestsWhenDisconnected: true,
20
20
  requestSendTimeout: Infinity,
21
21
  requestTimeout: Infinity,
@@ -37,9 +37,10 @@ function clientApi(settings = {}) {
37
37
  }
38
38
  })
39
39
 
40
- const api = new lcapi.Api(dao)
40
+ const api = new Api(dao)
41
41
  api.setup({
42
42
  ssr: true,
43
+ cache: true,
43
44
  createReactiveObject(definition) {
44
45
  //console.log("CREATE REACTIVE OBJECT", definition)
45
46
  return createReactiveObject(definition, reactiveMixin(api), reactivePrefetchMixin(api) )
package/index.js CHANGED
@@ -1,35 +1,75 @@
1
- import { getCurrentInstance } from 'vue'
2
- import { live as d3live } from '@live-change/dao-vue3'
1
+ import { getCurrentInstance, onUnmounted } from 'vue'
2
+ import { live as d3live, RangeBuckets } from '@live-change/dao-vue3'
3
3
 
4
4
  function path(app) {
5
5
  app = app || getCurrentInstance()
6
- return app.appContext.config.globalProperties.$fetch
6
+ return app.appContext.config.globalProperties.$lc.fetch
7
7
  }
8
8
 
9
9
  function api(app) {
10
10
  app = app || getCurrentInstance()
11
- return app.appContext.config.globalProperties.$api
11
+ return app.appContext.config.globalProperties.$lc
12
12
  }
13
13
 
14
14
  function view(app) {
15
15
  app = app || getCurrentInstance()
16
- return app.appContext.config.globalProperties.$view
16
+ return app.appContext.config.globalProperties.$lc.view
17
17
  }
18
18
 
19
19
  function actions(app) {
20
20
  app = app || getCurrentInstance()
21
- return app.appContext.config.globalProperties.$actions
21
+ return app.appContext.config.globalProperties.$lc.actions
22
22
  }
23
23
 
24
24
  function live(path) {
25
25
  const app = getCurrentInstance()
26
- const api = app.appContext.config.globalProperties.$api
26
+ const api = app.appContext.config.globalProperties.$lc
27
27
  return d3live(api, path)
28
28
  }
29
29
 
30
+ async function rangeBuckets(pathFunction, options, app) {
31
+ app = app || getCurrentInstance()
32
+ const api = app.appContext.config.globalProperties.$lc
33
+ const extendedPathFunction = (range) => pathFunction(range, api.fetch)
34
+ const buckets = new RangeBuckets(api, extendedPathFunction, options)
35
+ if(app) {
36
+ onUnmounted(() => {
37
+ buckets.dispose()
38
+ })
39
+ } else {
40
+ console.error("live fetch outside component instance - possible memory leak")
41
+ }
42
+ await buckets.wait()
43
+ return {
44
+ buckets: buckets.buckets,
45
+ loadTop: () => buckets.loadTop(),
46
+ loadBottom: () => buckets.loadBottom(),
47
+ dropTop: () => buckets.dropTop(),
48
+ dropBottom: () => buckets.dropBottom(),
49
+ canLoadTop: () => buckets.isTopLoadPossible(),
50
+ canLoadBottom: () => buckets.isBottomLoadPossible(),
51
+ }
52
+ }
53
+
54
+ function reverseRange(range) {
55
+ return {
56
+ gt: range.lt,
57
+ gte: range.lte,
58
+ lt: range.gt == '' ? '\xFF\xFF\xFF\xFF' : range.gt,
59
+ lte: range.gte,
60
+ limit: range.limit,
61
+ reverse: !range.reverse
62
+ }
63
+ }
64
+
30
65
  function client(app) {
31
66
  app = app || getCurrentInstance()
32
- return app.appContext.config.globalProperties.$client
67
+ return app.appContext.config.globalProperties.$lc.client
68
+ }
69
+
70
+ function uid(app) {
71
+ app = app || getCurrentInstance()
72
+ return app.appContext.config.globalProperties.$lc.uid
33
73
  }
34
74
 
35
- export { path, api, view, actions, live, client }
75
+ export { path, api, view, actions, live, client, uid, rangeBuckets, reverseRange }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/vue3-ssr",
3
- "version": "0.1.5",
3
+ "version": "0.1.9",
4
4
  "description": "Live Change Framework - vue components",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -22,6 +22,7 @@
22
22
  "homepage": "https://github.com/live-change/vue3-ssr",
23
23
  "dependencies": {
24
24
  "debug": "^4.3.2",
25
- "vue": "^3.2.21"
25
+ "vue": "^3.2.21",
26
+ "@live-change/uid": "^0.1.3"
26
27
  }
27
28
  }
package/serverApi.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createReactiveObject } from '@live-change/vue3-components'
2
- import { Api } from '@live-change/vue-api'
2
+ import Api from './Api.js'
3
3
  import { reactiveMixin, reactivePrefetchMixin } from '@live-change/dao-vue3'
4
4
 
5
5
 
package/generateUuid.js DELETED
@@ -1,21 +0,0 @@
1
- const crypto = require('crypto')
2
- function uuidFromBytes(rnd) {
3
- rnd[6] = (rnd[6] & 0x0f) | 0x40
4
- rnd[8] = (rnd[8] & 0x3f) | 0x80
5
- rnd = rnd.toString('hex').match(/(.{8})(.{4})(.{4})(.{4})(.{12})/)
6
- rnd.shift()
7
- return rnd.join('-')
8
- }
9
-
10
- function genUuid(callback) {
11
- if (typeof(callback) !== 'function') {
12
- return uuidFromBytes(crypto.randomBytes(16))
13
- }
14
- crypto.randomBytes(16, function(err, rnd) {
15
- if (err) return callback(err)
16
- callback(null, uuidFromBytes(rnd))
17
- })
18
- }
19
-
20
- module.exports = genUuid
21
-
package/getIp.js DELETED
@@ -1,12 +0,0 @@
1
- function getIp(connection) {
2
- let ip =
3
- connection.headers['x-real-ip'] ||
4
- connection.headers['x-forwarded-for'] ||
5
- connection.remoteAddress ||
6
- (connection.connection && connection.connection.remoteAddress)
7
- ip = ip.split(',')[0]
8
- ip = ip.split(':').slice(-1)[0] //in case the ip returned in a format: "::ffff:146.xxx.xxx.xxx"
9
- return ip
10
- }
11
-
12
- module.exports = getIp
package/serverDao.js DELETED
@@ -1,56 +0,0 @@
1
- const { Dao } = require("@live-change/dao")
2
- const DaoWebsocket = require("@live-change/dao-websocket")
3
-
4
- function reactiveObservableListConstructor(reactive) {
5
- class ReactiveObservableList extends Dao.ObservableList {
6
- constructor(value, what, dispose) {
7
- super(value, what, dispose, (data) => {
8
- if(data && typeof data == 'object') {
9
- const activated = reactive(data)
10
- return activated
11
- }
12
- return data
13
- })
14
- }
15
- }
16
- return ReactiveObservableList
17
- }
18
-
19
- function serverDao(credentials, ip, settings) {
20
- const serverHost = settings.remoteUrl || process.env.API_SERVER || "localhost:" + (process.env.API_PORT || 8002)
21
- const wsServer = `ws://${serverHost}/api/ws`
22
-
23
- return new Dao(credentials, {
24
- remoteUrl: wsServer,
25
- protocols: {
26
- 'ws': DaoWebsocket.client
27
- },
28
-
29
- ...settings,
30
-
31
- connectionSettings: {
32
- headers: {
33
- 'X-real-ip': ip,
34
- 'X-forwarded-for': ip
35
- },
36
- queueRequestsWhenDisconnected: true,
37
- requestSendTimeout: 2300,
38
- requestTimeout: 10000,
39
- queueActiveRequestsOnDisconnect: false,
40
- autoReconnectDelay: 200,
41
- logLevel: 1,
42
- /*connectionMonitorFactory: (connection) =>
43
- new ReactiveDao.ConnectionMonitorPinger(connection, {
44
- pingInterval: 50,
45
- pongInterval: 200
46
- })*/
47
- ...(settings && settings.connectionSettings)
48
- },
49
- defaultRoute: {
50
- type: "remote",
51
- generator: settings.reactive ? reactiveObservableListConstructor(settings.reactive) : Dao.ObservableList
52
- }
53
- })
54
- }
55
-
56
- module.exports = serverDao