Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions app/src/components/accounts/login.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,23 @@
const askEmail = location.hostname.endsWith('localhost')
let isIncognito
onMount(async () => {
if (userData) {
if (userData || !askEmail) {
// we dont ask for session name or org in the current operation mode, but if we ask for email anyways we can use this for testing
login()
return
// document.loginForm.submit()
}
if ('storage' in navigator && 'estimate' in navigator.storage) {
const {usage, quota} = await navigator.storage.estimate?.()
const { usage, quota } = await navigator.storage.estimate?.()

if(quota < 1200000000){
isIncognito = true
}
}
})

let sideWidth = '440'
let contentMin
// let sideWidth = '440'
// let contentMin

let saveToDevice = true

Expand All @@ -44,9 +46,19 @@

function login () {
const loginData = { email }

const sParams = new URLSearchParams(location.search)

// if org is passed from parent component use it, otherwise check and use the url params
if (org) {
loginData.org = org
} else {
const orgName = sParams.get('orgName')
if (orgName) {
loginData.org = orgName
}
}

if (isIncognito) {
loginData.isIncognito = isIncognito
}
Expand All @@ -56,11 +68,22 @@
if (sessionName) {
loginData.sessionName = sessionName
}
const cont = (new URLSearchParams(location.search)).get('continue')

const cont = sParams.get('continue')
if (cont) {
loginData.continue = cont
}

const projectName = sParams.get('projectName')
if (projectName) {
loginData.projectName = projectName
}

const startDemoProject = sParams.get('startDemoProject')
if (startDemoProject) {
loginData.startDemoProject = startDemoProject
}

let searchParams = new URLSearchParams(loginData)
let loginUrl = `/_api/_session?login&${searchParams.toString()}`
location.href = loginUrl
Expand Down
85 changes: 60 additions & 25 deletions app/src/make-pouch.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ async function rateRetryFetch (url, opts, awaitable, count = 1) {
await activePush
}

// @ts-ignore -- fix pouch type error
const res = await PouchDB.fetch(url, opts)

if (res.status === 429 && count < 4) {
Expand All @@ -34,9 +35,12 @@ export default async function ({
sessionId,
preload
}) {
// @ts-ignore -- fix pouch type error
PouchDB.prefix = '_ayu_'
// PouchDB.plugin({ bulkDocs: function () { return { self:this, args: arguments }; }})
// PouchDB.plugin({ test: function () { return { self:this, args: arguments }; }})

// @ts-ignore -- fix pouch type error
const pouch = new PouchDB(clientDbName, { revs_limit: 200, auto_compaction: true, deterministic_revs: true })
let couch
let sync
Expand All @@ -63,10 +67,18 @@ export default async function ({
return acc
}, {})
}

if (seedDoc.filters) {
seedDoc.filters = Object.entries(seedDoc.filters).reduce((acc, [name, filterFun]) => {
acc[name] = filterFun?.toString()
return acc
}, {})
}
return seedDoc
}) || []) ]).catch(() => {})

if (hasCouch) {
// @ts-ignore -- check if pouch type error or type error here?
couch = new PouchDB(`${location.origin}/_api/_couch/${serverDbName}`, {
fetch: async (url, opts) => {
opts.redirect = 'error'
Expand Down Expand Up @@ -96,7 +108,7 @@ export default async function ({
if (idSuffix) {
const checkpointDocId = '_local/' + decodeURIComponent(idSuffix)
// console.log(opts.method, {checkpointDocId, checkpointCache})
if (checkpointDocId === sync.pull.replicationId || checkpointDocId === sync.push.replicationId) {
if (checkpointDocId === sync?.pull?.replicationId || checkpointDocId === sync?.push?.replicationId) {
checkpointReqKey = checkpointDocId

if (opts.method === 'GET' || !opts.method) {
Expand All @@ -114,6 +126,7 @@ export default async function ({

return rateRetryFetch(url, opts, awaitable).then(async res => {
if (res.status === 401 || res.redirected || res.type === 'opaqueredirect') {
// @ts-ignore -- add type setup for global session object or better move to better object handling and encapsulation
self.session?.refresh()
}

Expand Down Expand Up @@ -194,27 +207,45 @@ export default async function ({
})
}

return includeDocs ? docs : true
return docs
}

const [ sessionDoc ] = await pullDocs([sessionId], { includeDocs: true }) // await couch.get(sessionId)

if (!sessionDoc.replications) {
if (preload?.length > 0) {
// first db is user db by convention, further dbs are org dbs for org user belongs to
const replicationConf = sessionDoc.dbs.find(db => db.dbName === serverDbName)

// on first pull, replicate the preloads
if (!replicationConf.pull) {
if (preload?.length > 0 || typeof preload === 'function') { // TODO: prefix support and functions?
// TODO: handle updates
// Use batch instead
console.log('preloading docs to new pouch...', preload)
await PouchDB.replicate(couch, pouch, { doc_ids: preload })

if (typeof preload === 'string' || typeof preload === 'function') {
// @ts-ignore -- fix pouch type error
await PouchDB.replicate(couch, pouch, { filter: preload }).catch(err => {
console.error('preload error', err)
throw err
})
} else {
// @ts-ignore -- fix pouch type error
await PouchDB.replicate(couch, pouch, { doc_ids: preload }).catch(err => {
console.error('preload error', err)
throw err
})
}
}

inited = new Promise((resolve) => { initResolver = resolve })
}

if (!sessionDoc.startSeq) {
if (!replicationConf.startSeq) {
console.warn('missing session doc start seq, fallback to fullsync', sessionDoc)
}

// FIXME: batching sync out not working
// @ts-ignore -- fix pouch type error
sync = PouchDB.sync(pouch, couch, {
live: true,
sse: true,
Expand All @@ -227,7 +258,7 @@ export default async function ({
batch_size: 50,
conflicts: true, // TODO
pull: {
since: sessionDoc.startSeq,
since: replicationConf.startSeq,
filter: (doc, _opts) => {
if (doc._conflicts) {
console.warn(doc._conflicts)
Expand Down Expand Up @@ -301,32 +332,36 @@ export default async function ({
init?.()
})

/**
* Internal initialization function that updates replication IDs in the session document.
* This function sets itself to null after execution to ensure it only runs once.
* @type {(()=>Promise<void>)|null}
*/
let init = async () => {
init = null
// console.log('initting changes session doc')
if (sync.pull.replicationId && sync.push.replicationId) {
let updateReplications = false
if (sessionDoc.replications) {
if (sessionDoc.replications.pull !== sync.pull.replicationId) {
console.error('pull replication id cahnged', sessionDoc, sync.pull)
// TODO: remove old doc
updateReplications = true
}
if (sessionDoc.replications.push !== sync.push.replicationId) {
console.error('push replication id cahnged', sessionDoc, sync.push)
// TODO: remove old doc
updateReplications = true
}
if (replicationConf.pull !== sync.pull.replicationId) {
// console.error('pull replication id changed', sessionDoc, sync.pull)
// TODO: remove old doc
updateReplications = true
}

if (!sessionDoc.replications || updateReplications) {
// console.log('writing replications to session...')
sessionDoc.replications = {
pull: sync.pull.replicationId,
push: sync.push.replicationId
}
await pouch.put(sessionDoc)
if (replicationConf.push !== sync.push.replicationId) {
// console.error('push replication id changed', sessionDoc, sync.push)
// TODO: remove old doc
updateReplications = true
}

if (!replicationConf.pull || updateReplications) {
replicationConf.pull = sync.pull.replicationId
}

if (!replicationConf.push || updateReplications) {
replicationConf.push = sync.push.replicationId
}
await pouch.put(sessionDoc)
}
}

Expand Down
2 changes: 2 additions & 0 deletions app/src/service-worker/handlers/ipfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export default async function ({ url, origUrl, event, ipfsGateway = '/'}) {
contentTypeOverride = 'image/png'
} else if (path.endsWith('.svg')) {
contentTypeOverride = 'image/svg+xml'
} else if (path.endsWith('.html')) {
contentTypeOverride = 'text/html; charset=utf-8'
}

if (cache.then) {
Expand Down
21 changes: 13 additions & 8 deletions app/src/service-worker/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import defaultPaths from '../schema/default-routes.js'
// TODO: support addtional dataSources
export default function ({
dbConf = {},
dataSources,
schema,
dataSources = null,
schema = null,
onChange,
clientDbSeeds,
proxiedDomains,
handlers: appHandlers,
debug
debug = false
} = {}) {
if (dataSources) {
console.warn('Additional data sources not implemented yet.')
Expand Down Expand Up @@ -112,7 +112,12 @@ export default function ({
})

// console.log('making falcor server')
self.session.falcorServer = makeFalcorServer({ dbs: self.session.dbs, schema, session: newSession, debug })
self.session.falcorServer = makeFalcorServer({
dbs: self.session.dbs,
schema,
session: newSession,
debug
})

if (newSession.userId && !self.session.loaded) {
redirectOtherClients = 'continue'
Expand All @@ -137,18 +142,18 @@ export default function ({
}
} else {
let cont = ''
if (url.pathname.length > 1 || url.hash || url.search > 0) {
if (url.pathname.length > 1 || url.hash || url.search.length > 0) {
if (query.get('continue')) {
cont = `continue=${query.get('continue')}`
} else {
cont = `continue=${encodeURIComponent(url.pathname + url.search + url.hash)}`
}
}
if (!url.pathname.startsWith('/_ayu/accounts') && !url.pathname.startsWith('/_api/_session?login')) {
const url = `/_ayu/accounts/?${cont}` // `/_api/_session?login${cont}`
console.log('redirecting client', url, newSession, client)
const newPath = url.hostname.endsWith('localhost') ? `/_ayu/accounts/?${cont}` : `/_api/_session?login${cont}`
console.log('redirecting client', newPath, newSession, client)

client.postMessage('navigate:' + url)
client.postMessage('navigate:' + newPath)
return waitForNavigation(client)
// after safari support: client.navigate().catch(err => console.error(err))
}
Expand Down
Loading