Skip to content

Commit

Permalink
new npm release, bump version, breaking: refactore datastore depeneci…
Browse files Browse the repository at this point in the history
…es, fix $not, await call and call result bugs in data store, fix ipfs handler aborting before cache put finished, support for non service worker setups, working sveltekit support, breaking: auto add falcor tags on empty path tags, initial ssr support and precache, HMR support, fix autowrapper for path results,
  • Loading branch information
lucidNTR committed Sep 22, 2023
1 parent a54f07b commit 96389e8
Show file tree
Hide file tree
Showing 29 changed files with 30,505 additions and 7,459 deletions.
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "convoi dev setup",
"image": "ghcr.io/cloudless-hq/atreyu:0.9.52",
"image": "ghcr.io/cloudless-hq/atreyu:0.9.54",

"settings": {
"deno.enable": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import { Observable } from '../../build/deps/falcor-observable.js' // @graphistry ?
// eslint-disable-next-line no-restricted-imports
import { Router } from '../../build/deps/falcor-router.js' // @graphistry ?
import { addPathTags } from '../schema/helpers.js'
import defaultPaths from '../schema/default-routes.js'

import { urlLogger } from '../lib/url-logger.js'
import * as systemHandlers from '../schema/falcor-handlers/index.js'
Expand All @@ -11,7 +13,7 @@ export function falcorTags (routes) {
Object.keys(routes).forEach(key => {
Object.keys(routes[key]).forEach(method => {
const tags = routes[key][method].tags
routes[key][method].tags = tags ? tags.push('falcor') : ['falcor']
routes[key][method].tags = tags ? tags : ['falcor'] // FIXME: how to add to existing tags ? .push?.('falcor')
})
})

Expand Down Expand Up @@ -46,7 +48,7 @@ export function toFalcorRoutes (schema) {
const handlers = {}

Object.entries(handlerArgs).forEach(([handlerType, handlerConf]) => {
if (handlerConf.tags?.includes('falcor')) {
if (handlerConf.tags?.includes?.('falcor')) {
if (!['get', 'set', 'call'].includes(handlerType)) {
console.error('unsupported falcor handler type ' + handlerType)
}
Expand All @@ -59,6 +61,7 @@ export function toFalcorRoutes (schema) {
arguments[0].session = this.session
arguments[0].Observable = this.Observable
arguments[0].req = this.req
arguments[0].fetch = this.fetch
arguments[0].model = this.model
/* eslint-enable functional/no-this-expression */

Expand All @@ -70,12 +73,19 @@ export function toFalcorRoutes (schema) {
const pathArg = arguments[0]

const auoWrap = (paAr, res) => {
if (res.jsonGraph) {
return res
}
if (res?.length && res?.[0]?.path) {
return res
}
if (['boolean', 'undefined', 'number', 'string'].includes(typeof res) || (!res.value && !res.path)) {
res = { value: { $type: 'atom', value: res } }
}
if (res.value !== undefined && !res.path) {
res.path = paAr.length ? [ ...paAr ] : [ paAr ]
}

return res
}

Expand Down Expand Up @@ -104,9 +114,21 @@ export function toFalcorRoutes (schema) {
return routes
}

export function makeRouter (dataRoutes) {
export function makeRouter ({ dataRoutes, schema }) {
// TODO: gobally precompile schema on build time
if (!dataRoutes && schema) {
if (typeof schema === 'function') {
schema = schema({ defaultPaths, addPathTags })
} else if (schema) {
// (allow omission of tags fro falcor routes)
schema.paths = { ...defaultPaths, ...falcorTags(schema.paths) }
}

dataRoutes = toFalcorRoutes(schema)
}

class AtreyuRouter extends Router.createClass(dataRoutes) { // eslint-disable-line functional/no-class
constructor ({ session, dbs }) {
constructor ({ session, dbs, fetch: internalFetch }) {
super({
// FIXME: check why debug flag and path errors dont work!
debug: false,
Expand Down Expand Up @@ -175,6 +197,7 @@ export function makeRouter (dataRoutes) {
this.session = session
this.dbs = dbs
this.req = req
this.fetch = internalFetch
this.Observable = Observable
/* eslint-enable functional/no-this-expression */
}
Expand Down
74 changes: 74 additions & 0 deletions app/src/falcor/schedulers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
const empty = {
dispose: function () {}
}
function ImmediateScheduler () {}
ImmediateScheduler.prototype.schedule = function schedule (action) {
action()
return empty
}
ImmediateScheduler.prototype.scheduleWithState = function scheduleWithState (state, action) {
action(this, state)
return empty
}


function TimeoutScheduler (delay = 1) {
this.delay = delay
}
const TimerDisposable = function TimerDisposable (id) {
this.id = id
this.disposed = false
}
TimeoutScheduler.prototype.schedule = function schedule (action) {
const id = setTimeout(action, this.delay)
return new TimerDisposable(id)
}
TimeoutScheduler.prototype.scheduleWithState = function scheduleWithState (state, action) {
const self = this
const id = setTimeout(function () {
action(self, state)
}, this.delay)

return new TimerDisposable(id)
}
TimerDisposable.prototype.dispose = function () {
if (this.disposed) {
return
}
clearTimeout(this.id)
this.disposed = true
}

/* eslint-disable functional/no-this-expression, functional/no-class */
class FrameScheduler {
schedule (action) {
let id = requestAnimationFrame(action)

return {
dispose: () => {
if (id) {
cancelAnimationFrame(id)
id = null
}
}
}
}
scheduleWithState (state, action) {
const self = this
let id = requestAnimationFrame(() => {
action(self, state)
})
return {
dispose: () => {
if (id) {
cancelAnimationFrame(id)
id = null
}
}
}
}
}
/* eslint-enable functional/no-this-expression, functional/no-class */

export { ImmediateScheduler, TimeoutScheduler, FrameScheduler }

Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/* eslint-disable functional/no-this-expression */
/* eslint-disable functional/no-class */
import { makeRouter, toFalcorRoutes } from './falcor-router.js'
import { makeRouter, toFalcorRoutes } from './router.js'
import { falcor } from '/_ayu/build/deps/falcor.js'
import { extractFromCache } from '../store/helpers.js'

class WorkerServer {
constructor (dataSource) {
this.dataSource = dataSource
class Server {
constructor (model) {
this.dataSource = model.asDataSource()
this.model = model
}

execute (action) {
Expand All @@ -25,6 +26,7 @@ class WorkerServer {
return this.dataSource.set(jsonGraphEnvelope)._toJSONG()
case 'call':
paths = action[5] || []
console.log({ callPath, args, pathSuffixes, paths })
return this.dataSource.call(callPath, args, pathSuffixes, paths)._toJSONG()
}
}
Expand All @@ -33,13 +35,19 @@ class WorkerServer {
// TODO: userId, additional dataSources
export default function ({
schema,
useAll,

cache,

dbs,
session
session,
fetch
}) {
const FalcorRouter = makeRouter(toFalcorRoutes(schema))
const routerInstance = new FalcorRouter({ dbs, session })
const FalcorRouter = makeRouter(toFalcorRoutes(schema, useAll))
const routerInstance = new FalcorRouter({ dbs, session, fetch })

const serverModel = falcor({
cache,
source: routerInstance,
maxSize: 500000,
collectRatio: 0.75,
Expand All @@ -49,6 +57,9 @@ export default function ({
.boxValues()

routerInstance.model = serverModel.withoutDataSource()


// TODO: move to class
routerInstance.model.getPageKey = function (path, from) {
const listCache = extractFromCache({ path, obj: this._root.cache })

Expand All @@ -60,9 +71,5 @@ export default function ({
return { index: 0 }
}

const dataSource = serverModel.asDataSource()

const workerServer = new WorkerServer(dataSource)

return workerServer
return new Server(serverModel)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,35 @@ import { Observable } from '/_ayu/build/deps/falcor-observable.js'

/* eslint-disable functional/no-this-expression, functional/no-class */
class ServiceWorkerSource {
constructor ({ wake }) {
constructor ({ wake, cache }) {
this._inflight = {}
this._id = 0 // Identifier used to correlate each Request to each response
this._active = 0
this._timer

const init = () => {
this._worker = navigator.serviceWorker.controller
this._worker?.postMessage(JSON.stringify([-1, 'hello mike' ]))
this._worker?.postMessage(JSON.stringify([-1, 'hello mike']))

if (cache) {
this._worker?.postMessage(JSON.stringify({ cache }))
}
}
if (!this._worker) {
init()
}

if (import.meta.hot) {
import.meta.hot.on('vite:beforeFullReload', async () => {
const reg = await navigator.serviceWorker.getRegistration()
// FIXME: maybe needs to wait for activated state event before reloading
// registration.active.onstatechange = e => {console.log(e)}
// registration.onupdatefound = () => {}
// throw 'aborting reload before sw update'
reg?.update()
})
}

navigator.serviceWorker.addEventListener('message', e => {
if (e.data.startsWith('navigate:')) {
return
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// eslint-disable-next-line no-restricted-imports
import PouchDB from '../../build/deps/pouchdb.js'
import PouchDB from '../build/deps/pouchdb.js'
// import findPlugin from 'pouchdb-find'; PouchDB.plugin(findPlugin)
// import req from '../lib/req.js'

Expand Down
8 changes: 5 additions & 3 deletions app/src/service-worker/falcor-worker.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import makePouch from './make-pouch.js'
import makeFalcorServer from './falcor-server.js'
import makePouch from '../make-pouch.js'
import { falcorTags } from '../falcor/router.js'
import makeFalcorServer from '../falcor/server.js'
// import serverSource from '../falcor/direct-source.js'
import { escapeId } from '../lib/helpers.js'
import { addPathTags } from '../schema/helpers.js'
import defaultPaths from '../schema/default-routes.js'
Expand All @@ -20,7 +22,7 @@ export default function ({
if (typeof schema === 'function') {
schema = schema({ defaultPaths, addPathTags })
} else if (schema) {
schema.paths = { ...defaultPaths, ...schema.paths }
schema.paths = { ...defaultPaths, ...falcorTags(schema.paths) }
}

// we use an asynchronous updating object reference to do async initialisation in a synchronous function, this is not really nice practice, but is currently the most performant way to start the service worker without big refactor
Expand Down
4 changes: 2 additions & 2 deletions app/src/service-worker/handlers/ipfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export default async function ({ url, origUrl, event, ipfsGateway = '/'}) {
// }

if (ipfsMapResponse?.ok) { // && !loggedOut
cache.put(manifestName, ipfsMapResponse.clone())
event.waitUntil(cache.put(manifestName, ipfsMapResponse.clone()))
} else {
ipfsMapResponse = await cache.match(manifestName)
}
Expand Down Expand Up @@ -134,7 +134,7 @@ export default async function ({ url, origUrl, event, ipfsGateway = '/'}) {
// }
const clone = response.clone()
clone.headers.set('cache-status', 'sw-cache; hit; stored')
cache.put(hash, clone)
event.waitUntil(cache.put(hash, clone))
}

return response
Expand Down
3 changes: 3 additions & 0 deletions app/src/service-worker/start-worker.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export default async function startWorker ({ reloadAfterInstall, workerPath = '/build/service-worker.js', isModule } = {}) {
if(!('navigator' in window) || !('serviceWorker' in navigator)) {
return
}
let regs
let firstStart = false
try {
Expand Down
6 changes: 3 additions & 3 deletions app/src/service-worker/worker.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import ipfsHandler from './handlers/ipfs.js'
import proxyHandler from './handlers/proxy.js'

import makePouch from './make-pouch.js'
import makeFalcorServer from './falcor-server.js'
import makePouch from '../falcor/make-pouch.js'
import makeFalcorServer from '../falcor/server.js'
import { escapeId } from '../lib/helpers.js'
import { parse, match } from '../lib/routing.js'
import { addPathTags } from '../schema/helpers.js'
import defaultPaths from '../schema/default-routes.js'

// FIXME: LEGACY, replace with importing falcor and fetch workers here!
// FIXME: this is LEGACY, replace with importing falcor and fetch workers seperately here!
// TODO: support addtional dataSources
export default function ({
dbConf = {},
Expand Down
Loading

0 comments on commit 96389e8

Please sign in to comment.