@aerogel/plugin-local-first 0.0.0-next.004d5deedf15bedf609a660bfd4543d3c0df9d9d
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/dist/aerogel-plugin-local-first.d.ts +299 -0
- package/dist/aerogel-plugin-local-first.js +1661 -0
- package/dist/aerogel-plugin-local-first.js.map +1 -0
- package/package.json +50 -0
- package/src/components/Account.vue +9 -0
- package/src/components/AccountLoggedIn.vue +85 -0
- package/src/components/AccountLoggedOut.vue +26 -0
- package/src/components/AccountLoginModal.vue +36 -0
- package/src/components/AccountModal.vue +206 -0
- package/src/components/index.ts +5 -0
- package/src/components/settings/PurgeData.vue +43 -0
- package/src/components/settings/index.ts +10 -0
- package/src/index.css +1 -0
- package/src/index.ts +33 -0
- package/src/jobs/Backup.ts +98 -0
- package/src/jobs/Migrate.test.ts +217 -0
- package/src/jobs/Migrate.ts +186 -0
- package/src/jobs/Sync.test.ts +1198 -0
- package/src/jobs/Sync.ts +696 -0
- package/src/jobs/mixins/LoadsChildren.ts +229 -0
- package/src/jobs/mixins/LoadsTypeIndex.ts +25 -0
- package/src/jobs/mixins/TracksLocalModels.ts +32 -0
- package/src/lib/SyncQueue.ts +94 -0
- package/src/lib/inference.ts +124 -0
- package/src/lib/mirroring.ts +352 -0
- package/src/lib/utils.ts +21 -0
- package/src/services/Cloud.state.ts +111 -0
- package/src/services/Cloud.ts +494 -0
- package/src/services/DocumentsCache.ts +39 -0
- package/src/testing/cloud.ts +193 -0
- package/src/testing/mocks/Solid.mock.ts +34 -0
- package/src/testing/setup.ts +33 -0
- package/src/testing/stubs/LegacyTask.schema.ts +15 -0
- package/src/testing/stubs/Movie.schema.ts +15 -0
- package/src/testing/stubs/Movie.ts +3 -0
- package/src/testing/stubs/MoviesContainer.ts +20 -0
- package/src/testing/stubs/Person.schema.ts +9 -0
- package/src/testing/stubs/Person.ts +18 -0
- package/src/testing/stubs/Post.schema.ts +17 -0
- package/src/testing/stubs/Post.ts +18 -0
- package/src/testing/stubs/Task.schema.ts +12 -0
- package/src/testing/stubs/Task.ts +3 -0
- package/src/testing/stubs/TasksList.ts +20 -0
- package/src/testing/stubs/Workspace.ts +15 -0
- package/src/types/shims.d.ts +7 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aerogel-plugin-local-first.js","sources":["../src/services/DocumentsCache.ts","../src/lib/inference.ts","../src/lib/SyncQueue.ts","../src/lib/mirroring.ts","../src/jobs/Backup.ts","../src/lib/utils.ts","../src/jobs/mixins/LoadsChildren.ts","../src/jobs/mixins/LoadsTypeIndex.ts","../src/jobs/mixins/TracksLocalModels.ts","../src/jobs/Migrate.ts","../src/jobs/Sync.ts","../src/services/Cloud.state.ts","../src/services/Cloud.ts","../src/components/settings/PurgeData.vue","../src/components/settings/index.ts","../src/components/AccountModal.vue","../src/components/AccountLoggedIn.vue","../src/index.ts"],"sourcesContent":["import { Events, Service, appNamespace } from '@aerogel/core';\nimport { IndexedDBMap, facade } from '@noeldemartin/utils';\n\nexport class DocumentsCacheService extends Service {\n\n private cache = new IndexedDBMap<{ modifiedAt: number }>(`${appNamespace()}-documents-cache`);\n\n public async isFresh(documentUrl: string, modifiedAt: Date | number): Promise<boolean> {\n const meta = await this.cache.get(documentUrl);\n const modifiedAtTime = typeof modifiedAt !== 'number' ? modifiedAt.getTime() : modifiedAt;\n\n return !!meta?.modifiedAt && meta.modifiedAt >= modifiedAtTime;\n }\n\n public async remember(documentUrl: string, modifiedAt: Date | number): Promise<void> {\n await this.cache.set(documentUrl, {\n modifiedAt: typeof modifiedAt !== 'number' ? modifiedAt.getTime() : modifiedAt,\n });\n }\n\n public async forget(documentUrl: string): Promise<void> {\n await this.cache.delete(documentUrl);\n }\n\n public async clear(): Promise<void> {\n await this.cache.clear();\n }\n\n protected override async boot(): Promise<void> {\n Events.on('auth:logout', async () => {\n await this.cache.clear();\n\n this.cache.close();\n });\n }\n\n}\n\nexport default facade(DocumentsCacheService);\n","import {\n Metadata,\n Operation,\n SolidACLAuthorization,\n SolidContainer,\n SolidContainsRelation,\n SolidDocument,\n SolidModel,\n isContainerClass,\n isSolidDocumentRelation,\n} from 'soukai-solid';\nimport { arrayFilter, isInstanceOf } from '@noeldemartin/utils';\n\nimport type { SolidContainerConstructor, SolidModelConstructor } from 'soukai-solid';\n\nconst containerRelations: WeakMap<typeof SolidModel, string[]> = new WeakMap();\nconst sameDocumentRelations: WeakMap<typeof SolidModel, string[]> = new WeakMap();\n\nexport function getContainerRegisteredClasses(modelClass: SolidContainerConstructor): SolidModelConstructor[] {\n return arrayFilter(\n getContainerRelations(modelClass).map((relation) => {\n const relatedClass = modelClass.instance().requireRelation<SolidContainsRelation>(relation).relatedClass;\n\n if (isContainerClass(relatedClass)) {\n return false;\n }\n\n return relatedClass;\n }),\n );\n}\n\nexport function getContainerRelations(modelClass: typeof SolidModel): string[] {\n if (!containerRelations.has(modelClass)) {\n containerRelations.set(\n modelClass,\n modelClass.relations.filter((relation) => {\n if (SolidModel.reservedRelations.includes(relation)) {\n return false;\n }\n\n const relationInstance = modelClass.instance().requireRelation(relation);\n\n return relationInstance instanceof SolidContainsRelation;\n }),\n );\n }\n\n return containerRelations.get(modelClass) ?? [];\n}\n\nexport function getContainedModels(model: SolidContainer): SolidModel[] {\n const relations = getContainerRelations(model.static());\n\n return relations.reduce(\n (models, relation) => models.concat(model.getRelationModels(relation) ?? []),\n [] as SolidModel[],\n );\n}\n\nexport function getRelatedClasses(modelClass: SolidModelConstructor): SolidModelConstructor[] {\n const relatedClasses = new Set<SolidModelConstructor>();\n const instance = modelClass.instance();\n\n relatedClasses.add(modelClass);\n\n for (const relation of modelClass.relations) {\n if (modelClass.reservedRelations.includes(relation)) {\n continue;\n }\n\n relatedClasses.add(instance.requireRelation(relation).relatedClass);\n }\n\n return [...relatedClasses.values()];\n}\n\nexport function getRelatedAppModels(model: SolidModel): SolidModel[] {\n return model\n .getRelatedModels()\n .filter(\n (related) =>\n !isInstanceOf(related, SolidACLAuthorization) &&\n !isInstanceOf(related, SolidDocument) &&\n !isInstanceOf(related, Metadata) &&\n !isInstanceOf(related, Operation) &&\n related.static() !== SolidContainer,\n );\n}\n\nexport function getSameDocumentRelations(modelClass: typeof SolidModel): string[] {\n if (!sameDocumentRelations.has(modelClass)) {\n sameDocumentRelations.set(\n modelClass,\n modelClass.relations.filter((relation) => {\n if (SolidModel.reservedRelations.includes(relation)) {\n return false;\n }\n\n const relationInstance = modelClass.instance().requireRelation(relation);\n\n return isSolidDocumentRelation(relationInstance) && relationInstance.useSameDocument;\n }),\n );\n }\n\n return sameDocumentRelations.get(modelClass) ?? [];\n}\n\nexport function isDirtyOrHasDirtyChildren(model: SolidModel): boolean {\n if (model.isDirty()) {\n return true;\n }\n\n if (!(model instanceof SolidContainer)) {\n return false;\n }\n\n const relationHasDirtyModels = (relation: string) => {\n return model.getRelationModels(relation)?.some((relatedModel) => isDirtyOrHasDirtyChildren(relatedModel));\n };\n\n return getContainerRelations(model.static()).some(relationHasDirtyModels);\n}\n","import { after, arrayRemove, facade, required } from '@noeldemartin/utils';\nimport { App } from '@aerogel/core';\nimport { type SolidModel, isContainer } from 'soukai-solid';\n\nimport { getContainedModels } from '@aerogel/plugin-local-first/lib/inference';\n\nconst Cloud = required(() => App.service('$cloud'));\n\nclass SyncQueue {\n\n private models: Set<SolidModel> = new Set();\n private promises: Promise<unknown>[] = [];\n\n public push(model: SolidModel): void {\n this.models.add(model);\n this.syncAfter(after({ seconds: 1 }));\n }\n\n public clear(models?: SolidModel[]): void {\n if (!models) {\n this.models = new Set();\n\n return;\n }\n\n for (const model of models) {\n this.models.delete(model);\n }\n }\n\n protected async syncAfter<T = void>(operationOrPromise: Promise<T> | (() => Promise<T>)): Promise<T> {\n const promise = typeof operationOrPromise === 'function' ? operationOrPromise() : operationOrPromise;\n\n this.promises.push(promise);\n\n promise.then(() => arrayRemove(this.promises, promise));\n\n if (this.promises.length === 1) {\n this.schedule();\n }\n\n return promise as Promise<T>;\n }\n\n private schedule(): void {\n Promise.all(this.promises)\n .then(() => after())\n .then(() => {\n if (this.promises.length !== 0) {\n this.schedule();\n\n return;\n }\n\n const models = this.consume();\n\n if (models.length === 0) {\n return;\n }\n\n Cloud.syncIfOnline(models);\n });\n }\n\n private consume(): SolidModel[] {\n const models: SolidModel[] = [];\n const children: Set<SolidModel> = new Set();\n\n for (const model of this.models) {\n if (!isContainer(model)) {\n continue;\n }\n\n this.models.delete(model);\n getContainedModels(model).forEach((child) => children.add(child));\n models.push(model);\n }\n\n for (const model of this.models) {\n this.models.delete(model);\n\n if (children.has(model)) {\n continue;\n }\n\n models.push(model);\n }\n\n return models;\n }\n\n}\n\nexport default facade(SyncQueue);\n","import { bootModels } from 'soukai';\nimport {\n fail,\n objectWithout,\n requireUrlParentDirectory,\n required,\n tap,\n urlResolveDirectory,\n urlRoute,\n} from '@noeldemartin/utils';\nimport { App } from '@aerogel/core';\nimport { getTrackedModels, trackModelsCollection as trackSoukaiModelsCollection } from '@aerogel/plugin-soukai';\nimport { Solid } from '@aerogel/plugin-solid';\nimport { PropertyOperation, SolidContainer, SolidContainsRelation, Tombstone, isContainerClass } from 'soukai-solid';\nimport type { ObjectsMap } from '@noeldemartin/utils';\nimport type { Attributes } from 'soukai';\nimport type { Operation, SolidModel, SolidModelConstructor, SolidSchemaDefinition } from 'soukai-solid';\n\nimport DocumentsCache from '@aerogel/plugin-local-first/services/DocumentsCache';\nimport SyncQueue from '@aerogel/plugin-local-first/lib/SyncQueue';\nimport { getContainerRelations, getRelatedAppModels } from '@aerogel/plugin-local-first/lib/inference';\n\ninterface CloneOptions {\n clean?: boolean;\n}\n\nconst Cloud = required(() => App.service('$cloud'));\nconst remoteClasses: WeakMap<SolidModelConstructor, SolidModelConstructor> = new WeakMap();\nconst localClasses: WeakMap<SolidModelConstructor, SolidModelConstructor> = new WeakMap();\n\nfunction cleanRemoteModelClone(remoteModel: SolidModel): void {\n const relatedModels = remoteModel.getRelatedModels().concat([remoteModel]);\n\n for (const relatedModel of relatedModels) {\n relatedModel.cleanDirty(true);\n }\n}\n\nfunction fixRemoteModelClone(remoteModel: SolidModel): void {\n const relatedModels = getRelatedAppModels(remoteModel).concat([remoteModel]);\n\n for (const relatedModel of relatedModels) {\n if (!relatedModel.operations || relatedModel.operations.length === 0) {\n continue;\n }\n\n const operations = (relatedModel.operations ?? []).filter((operation) => {\n return (\n !(operation instanceof PropertyOperation) ||\n !relatedModel.ignoreRdfPropertyHistory(operation.property, true)\n );\n });\n\n if (!operations.some((operation) => !operation.isInception(relatedModel))) {\n relatedModel.setRelationModels('operations', []);\n\n continue;\n }\n\n relatedModel.setRelationModels('operations', operations);\n }\n}\n\nexport async function createRemoteModel(localModel: SolidModel): Promise<void> {\n Cloud.setState({\n localModelUpdates: {\n ...Cloud.localModelUpdates,\n [localModel.url]: 1,\n },\n });\n\n if (isRegisteredModelClass(localModel.static())) {\n await trackModelsCollection(localModel.static(), requireUrlParentDirectory(localModel.url));\n }\n\n if (Cloud.autoPush && Cloud.ready && !Cloud.syncing) {\n SyncQueue.push(localModel);\n }\n}\n\nexport async function trackModelsCollection(modelClass: SolidModelConstructor, collection: string): Promise<void> {\n if (Cloud.modelCollections[modelClass.modelName]?.includes(collection)) {\n return;\n }\n\n Cloud.setState('modelCollections', {\n ...Cloud.modelCollections,\n [modelClass.modelName]: (Cloud.modelCollections[modelClass.modelName] ?? []).concat(collection),\n });\n\n if (!Cloud.modelCollections[modelClass.modelName]?.includes(modelClass.collection)) {\n modelClass.collection = collection;\n }\n\n await trackSoukaiModelsCollection(modelClass, collection);\n}\n\nexport async function updateRemoteModel(localModel: SolidModel): Promise<void> {\n if (ignoreModelUpdates(localModel)) {\n return;\n }\n\n const modelUpdates = Cloud.localModelUpdates[localModel.url] ?? 0;\n\n Cloud.setState({\n localModelUpdates: localModel.isSoftDeleted()\n ? objectWithout(Cloud.localModelUpdates, localModel.url)\n : {\n ...Cloud.localModelUpdates,\n [localModel.url]: modelUpdates + 1,\n },\n });\n\n await DocumentsCache.forget(localModel.requireDocumentUrl());\n\n if (Cloud.autoPush && Cloud.ready && !Cloud.syncing) {\n SyncQueue.push(localModel);\n }\n}\n\nexport function clearLocalModelUpdates(syncedModelUrls: Set<string>, documentsWithErrors?: Set<string>): void {\n const localModelUpdates = {} as Record<string, number>;\n const syncedModelUrlsArray = Array.from(syncedModelUrls);\n\n for (const [url, count] of Object.entries(Cloud.localModelUpdates)) {\n const documentUrl = urlRoute(url);\n const wasSynced =\n syncedModelUrls.has(url) ||\n syncedModelUrlsArray.some((modelUrl) => modelUrl.endsWith('/') && url.startsWith(modelUrl));\n\n if (wasSynced && !documentsWithErrors?.has(documentUrl)) {\n continue;\n }\n\n localModelUpdates[url] = count;\n }\n\n Cloud.setState({ localModelUpdates });\n}\n\nexport function cloneLocalModel(localModel: SolidModel, options: CloneOptions = {}): SolidModel {\n const localModelClasses = new Set<typeof SolidModel>();\n\n localModelClasses.add(localModel.static());\n\n if (localModel instanceof SolidContainer) {\n for (const relation of getContainerRelations(localModel.static())) {\n localModelClasses.add(localModel.requireRelation<SolidContainsRelation>(relation).relatedClass);\n }\n }\n\n const constructors = [...localModelClasses.values()].map(\n (localClass) => [localClass, getRemoteClass(localClass)] as [typeof SolidModel, typeof SolidModel],\n );\n\n return tap(localModel.clone({ constructors }), (model) => {\n fixRemoteModelClone(model);\n\n options.clean && cleanRemoteModelClone(model);\n });\n}\n\nexport function cloneRemoteModel(remoteModel: SolidModel): SolidModel {\n const remoteModelClasses = new Set<typeof SolidModel>();\n\n remoteModelClasses.add(remoteModel.static());\n\n if (remoteModel instanceof SolidContainer) {\n for (const relation of getContainerRelations(remoteModel.static())) {\n remoteModelClasses.add(remoteModel.requireRelation<SolidContainsRelation>(relation).relatedClass);\n }\n }\n\n const constructors = [...remoteModelClasses.values()].map(\n (remoteClass) => [remoteClass, getLocalClass(remoteClass)] as [typeof SolidModel, typeof SolidModel],\n );\n\n return remoteModel.clone({ constructors });\n}\n\nexport async function completeRemoteModels(\n localModels: SolidModel[],\n remoteModels: SolidModel[],\n documentsWithErrors: Set<string>,\n): Promise<SolidModel[]> {\n const RemoteTombstone = getRemoteClass(Tombstone);\n const remoteModelUrls = remoteModels.map((remoteModel) => remoteModel.url);\n const missingModelDocumentUrls = localModels\n .filter((localModel) => !remoteModelUrls.includes(localModel.url))\n .map((localModel) => localModel.requireDocumentUrl())\n .filter((documentUrl) => !documentsWithErrors.has(documentUrl));\n const tombstones = await RemoteTombstone.all({ $in: missingModelDocumentUrls });\n\n return remoteModels.concat(tombstones);\n}\n\nexport function ignoreModelUpdates(localModel: SolidModel): boolean {\n const documentModels = localModel.getDocumentModels();\n const documentOperations = documentModels.flatMap(\n (model) => model.operations?.map((operation) => [model, operation] as [SolidModel, Operation]) ?? [],\n );\n const updatedAt = Math.max(...documentModels.map((model) => model.metadata?.updatedAt?.getTime() ?? 0));\n\n return !documentOperations.some(([model, operation]) => {\n if (operation.date.getTime() !== updatedAt) {\n return false;\n }\n\n if (!(operation instanceof PropertyOperation)) {\n return true;\n }\n\n return !model.ignoreRdfPropertyHistory(operation.property, true);\n });\n}\n\nexport function getLocalModel(remoteModel: SolidModel, localModels: ObjectsMap<SolidModel>): SolidModel {\n return localModels.get(remoteModel.url) ?? cloneRemoteModel(remoteModel);\n}\n\nexport function getLocalModels(): SolidModel[] {\n return [...Cloud.registeredModels]\n .map(({ modelClass }) => getTrackedModels(modelClass, { includeSoftDeleted: true }))\n .flat();\n}\n\nexport function getSchemaMigrations(): Map<SolidModelConstructor, SolidModelConstructor | SolidSchemaDefinition> {\n return Cloud.schemaMigrations;\n}\n\nexport function clearSchemaMigrations(): void {\n Cloud.schemaMigrations.clear();\n}\n\nexport function getSchemaMigration(\n modelClass: SolidModelConstructor,\n): SolidModelConstructor | SolidSchemaDefinition | undefined {\n return Cloud.schemaMigrations.get(modelClass);\n}\n\nexport function getRemoteClass<T extends SolidModelConstructor>(localClass: T): T {\n return (remoteClasses.get(localClass) as T) ?? makeRemoteClass(localClass);\n}\n\nexport function getRemoteContainersCollection(modelClass: SolidModelConstructor, path?: string): string {\n const rootStorage = Solid.requireUser().storageUrls[0];\n const containedClass =\n isContainerClass(modelClass) &&\n getContainerRelations(modelClass)\n .map((relation) => {\n const relatedClass = modelClass\n .instance()\n .requireRelation<SolidContainsRelation>(relation).relatedClass;\n\n if (isContainerClass(relatedClass)) {\n return null;\n }\n\n return relatedClass;\n })\n .filter(Boolean)[0];\n\n path ??= `/${(containedClass || modelClass).modelName.toLowerCase()}s/`;\n\n return urlResolveDirectory((path.startsWith('/') ? rootStorage.slice(0, -1) : rootStorage) + path);\n}\n\nexport function getRemoteModel(localModel: SolidModel, remoteModels: ObjectsMap<SolidModel>): SolidModel {\n return remoteModels.get(localModel.url) ?? cloneLocalModel(localModel);\n}\n\nexport function isRegisteredModel(model: SolidModel): boolean {\n for (const { modelClass } of Cloud.registeredModels) {\n const models = getTrackedModels(modelClass);\n\n if (models.some((registeredModel) => registeredModel.url === model.url)) {\n return true;\n }\n }\n\n return false;\n}\n\nexport function isRemoteModel(model: SolidModel): boolean {\n return localClasses.has(model.static());\n}\n\nexport function isLocalModel(model: SolidModel): boolean {\n return !isRemoteModel(model);\n}\n\nexport function isRegisteredModelClass(modelClass: SolidModelConstructor): boolean {\n return Cloud.registeredModels.some(({ modelClass: registeredModelClass }) => registeredModelClass === modelClass);\n}\n\nexport function makeRemoteClass<T extends SolidModelConstructor>(localClass: T): T {\n const LocalClass = localClass as typeof SolidModel;\n const withLocalHistoryConfig = (modelClass: typeof SolidModel, operation: () => unknown) => {\n modelClass.timestamps = LocalClass.timestamps;\n modelClass.history = LocalClass.history;\n\n operation();\n\n modelClass.timestamps = [];\n modelClass.history = false;\n };\n const RemoteClass = class extends LocalClass {\n\n public static override timestamps = false;\n public static override history = false;\n\n protected override initialize(attributes: Attributes, exists: boolean): void {\n withLocalHistoryConfig(this._proxy.static(), () => super.initialize(attributes, exists));\n }\n\n protected override initializeRelations(): void {\n super.initializeRelations();\n\n for (const relation of Object.values(this._relations)) {\n if (!(relation instanceof SolidContainsRelation)) {\n continue;\n }\n\n relation.relatedClass = getRemoteClass(relation.relatedClass);\n }\n }\n\n public override fixMalformedAttributes(): void {\n withLocalHistoryConfig(this.static(), () => super.fixMalformedAttributes());\n }\n \n } as unknown as T;\n\n remoteClasses.set(LocalClass, RemoteClass);\n localClasses.set(RemoteClass, LocalClass);\n\n LocalClass.on('schema-updated', async (schema) => {\n await RemoteClass.updateSchema({\n ...schema,\n timestamps: false,\n history: false,\n });\n });\n\n bootModels({ [`Remote${localClass.modelName}`]: RemoteClass });\n\n return RemoteClass;\n}\n\nexport function getLocalClass<T extends SolidModelConstructor>(remoteClass: T): T {\n return (localClasses.get(remoteClass) as T) ?? fail(`Couldn't find local class for ${remoteClass.modelName}`);\n}\n","import { Job } from '@aerogel/core';\nimport { requireEngine } from 'soukai';\nimport { requireUrlParentDirectory } from '@noeldemartin/utils';\nimport { ignoreModelsCollection, trackModelsCollection } from '@aerogel/plugin-soukai';\nimport type { EngineDocument, IndexedDBEngine } from 'soukai';\nimport type { SolidModelConstructor } from 'soukai-solid';\n\ninterface Migration {\n modelClass: SolidModelConstructor;\n local: string;\n remote: string;\n}\n\nexport default class Backup extends Job {\n\n private urlMigrations: Migration[] = [];\n private collectionMigrations: Migration[] = [];\n\n public migrateUrl(modelClass: SolidModelConstructor, local: string, remote: string): void {\n this.urlMigrations.push({\n modelClass,\n local,\n remote,\n });\n }\n\n public migrateCollection(modelClass: SolidModelConstructor, local: string, remote: string): void {\n this.collectionMigrations.push({\n modelClass,\n local,\n remote,\n });\n }\n\n protected async run(): Promise<void> {\n const engine = requireEngine<IndexedDBEngine>();\n const collections = await engine.getCollections();\n\n for (const collection of collections) {\n const documents = await engine.readMany(collection);\n\n for (const [id, document] of Object.entries(documents)) {\n const url = this.replaceUrl(id);\n\n await engine.create(requireUrlParentDirectory(url), this.replaceDocumentUrls(document), url);\n await engine.delete(collection, id);\n }\n }\n\n for (const { modelClass, remote } of this.urlMigrations) {\n trackModelsCollection(modelClass, requireUrlParentDirectory(remote), { refresh: false });\n }\n\n for (const { modelClass, local, remote } of this.collectionMigrations) {\n ignoreModelsCollection(modelClass, local);\n trackModelsCollection(modelClass, remote, { refresh: false });\n }\n }\n\n protected replaceDocumentUrls(document: EngineDocument): EngineDocument {\n for (const [key, value] of Object.entries(document)) {\n if (key === '@id' && typeof value === 'string') {\n document[key] = this.replaceUrl(value);\n\n continue;\n }\n\n if (typeof value !== 'object' || value === null) {\n continue;\n }\n\n document[key] = this.replaceDocumentUrls(value as EngineDocument);\n }\n\n return document;\n }\n\n protected replaceUrl(url: string): string {\n for (const { local, remote } of this.urlMigrations) {\n if (!url.startsWith(local)) {\n continue;\n }\n\n return url.replace(local, remote);\n }\n\n for (const { local, remote } of this.collectionMigrations) {\n if (!url.startsWith(local)) {\n continue;\n }\n\n return url.replace(local, remote);\n }\n\n return url;\n }\n\n}\n","export function mapFromArray<K, V>(items: [K, V][]): Map<K, V> {\n const itemsMap = new Map();\n\n for (const [key, value] of items) {\n itemsMap.set(key, value);\n }\n\n return itemsMap;\n}\n\nexport function lazy<T>(getter: () => Promise<T>): () => Promise<T> {\n const result: { value?: T } = {};\n\n return async () => {\n if (!('value' in result)) {\n result.value = await getter();\n }\n\n return result.value as T;\n };\n}\n","import { arrayChunk, arrayFrom, isInstanceOf, map, required } from '@noeldemartin/utils';\nimport { DocumentNotFound } from 'soukai';\nimport { Tombstone } from 'soukai-solid';\nimport type { JobStatus } from '@aerogel/core';\nimport type { ObjectsMap } from '@noeldemartin/utils';\nimport type { SolidContainer, SolidContainsRelation, SolidDocument, SolidModel } from 'soukai-solid';\n\nimport DocumentsCache from '@aerogel/plugin-local-first/services/DocumentsCache';\nimport { cloneLocalModel, isLocalModel } from '@aerogel/plugin-local-first/lib/mirroring';\nimport { getContainerRelations } from '@aerogel/plugin-local-first/lib/inference';\nimport { lazy } from '@aerogel/plugin-local-first/lib/utils';\n\nexport interface ResourceJobStatus extends JobStatus {\n documentUrl?: string;\n children?: ResourceJobStatus[];\n}\n\nexport default class LoadsChildren {\n\n declare protected localModels?: ObjectsMap<SolidModel>;\n\n protected async loadContainedModels(\n model: SolidContainer,\n options: {\n ignoreTombstones?: boolean;\n status?: ResourceJobStatus;\n onDocumentsLoaded?: (urls: string[]) => unknown;\n onDocumentError?: (error: unknown) => unknown;\n onDocumentRead?: (document: SolidDocument) => unknown;\n } = {},\n ): Promise<SolidModel[]> {\n if (isLocalModel(model)) {\n const children = [];\n\n for (const relation of getContainerRelations(model.static())) {\n const relationModels =\n (await model.loadRelationIfUnloaded<SolidModel | SolidModel[] | null>(relation)) ?? [];\n\n children.push(...arrayFrom(relationModels));\n }\n\n return children;\n }\n\n const children: Record<string, SolidModel[]> = {};\n const tombstones: Tombstone[] = [];\n const documents = map(model.documents, 'url');\n const documentUrlChunks = arrayChunk(model.resourceUrls, 10);\n const statusChildren = documentUrlChunks.flat().map((url) => ({\n documentUrl: url,\n completed: false,\n }));\n const statusChildrenMap = map(statusChildren, 'documentUrl');\n\n if (options.status) {\n options.status.children = statusChildren;\n }\n\n for (const documentUrls of documentUrlChunks) {\n await Promise.all(\n documentUrls.map(async (documentUrl) => {\n const { children: documentChildren, tombstones: documentTombstones } =\n await this.loadDocumentChildren(\n model,\n documentUrl,\n documents,\n options.onDocumentError,\n options.onDocumentRead,\n );\n\n tombstones.push(...documentTombstones);\n\n for (const [relation, documentModels] of Object.entries(documentChildren)) {\n const relationChildren = (children[relation] ??= []);\n\n relationChildren.push(...documentModels);\n }\n }),\n );\n\n for (const documentUrl of documentUrls) {\n if (documentUrl.endsWith('/')) {\n continue;\n }\n\n required(statusChildrenMap.get(documentUrl)).completed = true;\n }\n\n await options.onDocumentsLoaded?.(documentUrls);\n }\n\n for (const [relation, relationModels] of Object.entries(children)) {\n model.setRelationModels(relation, relationModels);\n }\n\n const childrenArray = options.ignoreTombstones\n ? Object.values(children).flat()\n : Object.values(children).flat().concat(tombstones);\n\n if (options.status) {\n options.status.children = childrenArray.map((child) => {\n return required(statusChildrenMap.get(child.requireDocumentUrl()));\n });\n }\n\n return childrenArray;\n }\n\n protected async loadDocumentChildren(\n model: SolidContainer,\n documentUrl: string,\n documents: ObjectsMap<SolidDocument>,\n onDocumentError?: (error: unknown) => unknown,\n onDocumentRead?: (document: SolidDocument) => unknown,\n ): Promise<{ children: Record<string, SolidModel[]>; tombstones: Tombstone[] }> {\n const document = documents.get(documentUrl);\n\n if (\n document &&\n document.updatedAt &&\n (await DocumentsCache.isFresh(document.url, document.updatedAt)) &&\n this.localModels?.hasKey(model.url)\n ) {\n return {\n children: await this.loadDocumentChildrenFromLocal(model, document),\n tombstones: [],\n };\n }\n\n return this.loadDocumentChildrenFromRemote(model, documentUrl, onDocumentError, onDocumentRead);\n }\n\n protected async loadDocumentChildrenFromLocal(\n model: SolidModel,\n document: SolidDocument,\n ): Promise<Record<string, SolidModel[]>> {\n const children: Record<string, SolidModel[]> = {};\n\n for (const relation of getContainerRelations(model.static())) {\n const relationInstance = model.requireRelation<SolidContainsRelation>(relation);\n\n if (relationInstance.loaded) {\n children[relation] = relationInstance.getLoadedModels();\n\n continue;\n }\n\n const relatedLocalModels = this.localModels?.get(model.url)?.getRelationModels(relation) ?? [];\n\n children[relation] = relatedLocalModels\n .filter((relatedLocalModel) => relatedLocalModel.getDocumentUrl() === document.url)\n .map((relatedLocalModel) => cloneLocalModel(relatedLocalModel, { clean: true }));\n }\n\n return children;\n }\n\n protected async loadDocumentChildrenFromRemote(\n model: SolidContainer,\n documentUrl: string,\n onDocumentError?: (error: unknown) => unknown,\n onDocumentRead?: (document: SolidDocument) => unknown,\n ): Promise<{ children: Record<string, SolidModel[]>; tombstones: Tombstone[] }> {\n const children: Record<string, SolidModel[]> = {};\n const tombstones: Tombstone[] = [];\n const readDocument = lazy(async () => {\n try {\n const documentModel = model.documents.find((document) => document.url === documentUrl);\n const document = await model.requireEngine().readOne(model.static('collection'), documentUrl);\n const documentTombstones = await Tombstone.createManyFromEngineDocuments({\n [documentUrl]: document,\n });\n\n tombstones.push(...documentTombstones);\n\n if (documentModel) {\n onDocumentRead?.(documentModel);\n }\n\n return document;\n } catch (error) {\n if (isInstanceOf(error, DocumentNotFound)) {\n return null;\n }\n\n if (!onDocumentError) {\n throw error;\n }\n\n onDocumentError(error);\n\n return null;\n }\n });\n\n for (const relation of getContainerRelations(model.static())) {\n const relationInstance = model.requireRelation<SolidContainsRelation>(relation);\n\n if (relationInstance.loaded) {\n children[relation] = relationInstance.getLoadedModels();\n\n continue;\n }\n\n const document = await readDocument();\n\n if (!document) {\n continue;\n }\n\n try {\n const documentChildren = await relationInstance.relatedClass.createManyFromEngineDocuments({\n [documentUrl]: document,\n });\n\n children[relation] = documentChildren;\n } catch (error) {\n if (!onDocumentError) {\n throw error;\n }\n\n onDocumentError(error);\n }\n }\n\n return { children, tombstones };\n }\n\n}\n","import { Solid } from '@aerogel/plugin-solid';\nimport type { SolidTypeIndex } from 'soukai-solid';\nimport type { SolidUserProfile } from '@noeldemartin/solid-utils';\n\nconst typeIndexes: WeakMap<SolidUserProfile, SolidTypeIndex | null> = new WeakMap();\n\nexport default class LoadsTypeIndex {\n\n protected async loadTypeIndex(options?: { create?: false; fresh?: boolean }): Promise<SolidTypeIndex | null>;\n protected async loadTypeIndex(options?: { create?: true; fresh?: boolean }): Promise<SolidTypeIndex>;\n protected async loadTypeIndex(options: { create?: boolean; fresh?: boolean } = {}): Promise<SolidTypeIndex | null> {\n const user = Solid.requireUser();\n\n if (options.fresh || !typeIndexes.has(user)) {\n typeIndexes.set(user, await Solid.findPrivateTypeIndex({ fresh: options.fresh }));\n }\n\n if (options.create && !typeIndexes.get(user)) {\n typeIndexes.set(user, await Solid.findOrCreatePrivateTypeIndex());\n }\n\n return typeIndexes.get(user) ?? null;\n }\n\n}\n","import type { ObjectsMap } from '@noeldemartin/utils';\nimport type { SolidModel } from 'soukai-solid';\n\nimport { getContainerRelations } from '@aerogel/plugin-local-first/lib/inference';\n\nexport default class TracksLocalModels {\n\n declare protected localModels: ObjectsMap<SolidModel>;\n\n protected async indexLocalModels(models: SolidModel[]): Promise<void> {\n for (const localModel of models) {\n await this.addLocalModel(localModel);\n }\n }\n\n protected async addLocalModel(localModel: SolidModel): Promise<void> {\n if (this.localModels.hasKey(localModel.url)) {\n return;\n }\n\n this.localModels.add(localModel);\n\n for (const relation of getContainerRelations(localModel.static())) {\n await localModel.loadRelationIfUnloaded(relation);\n }\n\n for (const relatedModel of localModel.getRelatedModels()) {\n this.localModels.add(relatedModel);\n }\n }\n\n}\n","import { PropertyOperation, isContainer } from 'soukai-solid';\nimport { Job } from '@aerogel/core';\nimport { isInstanceOf, map, mixed, objectMap, tap } from '@noeldemartin/utils';\nimport type { JobListener, JobStatus } from '@aerogel/core';\nimport type { Nullable } from '@noeldemartin/utils';\nimport type { SolidModel, SolidTypeIndex } from 'soukai-solid';\n\nimport {\n clearSchemaMigrations,\n getRemoteClass,\n getSchemaMigration,\n getSchemaMigrations,\n} from '@aerogel/plugin-local-first/lib/mirroring';\nimport { getContainerRegisteredClasses } from '@aerogel/plugin-local-first/lib/inference';\n\nimport LoadsChildren from './mixins/LoadsChildren';\nimport LoadsTypeIndex from './mixins/LoadsTypeIndex';\nimport TracksLocalModels from './mixins/TracksLocalModels';\n\nconst BaseJob = Job as typeof Job<JobListener, MigrateJobStatus, MigrateJobStatus>;\n\nexport interface MigrateJobStatus extends JobStatus {\n children?: MigrateModelJobStatus[];\n}\n\nexport interface MigrateModelJobStatus extends JobStatus {\n modelUrl: string;\n children?: MigrateModelJobStatus[];\n}\n\nexport default class Migrate extends mixed(BaseJob, [LoadsChildren, LoadsTypeIndex, TracksLocalModels]) {\n\n public static restore(status: MigrateJobStatus): Migrate {\n return tap(new Migrate(), (job) => {\n job.status = status;\n });\n }\n\n constructor() {\n super();\n\n this.localModels = map([], 'url');\n }\n\n protected _models?: SolidModel[];\n\n public get models(): SolidModel[] | undefined {\n return this._models;\n }\n\n public set models(models: SolidModel[] | undefined) {\n if (!models) {\n delete this._models;\n\n this.localModels = map([], 'url');\n\n return;\n }\n\n const childrenStatus = objectMap(this.status.children ?? [], 'modelUrl');\n\n this._models = models;\n this.localModels = map([], 'url');\n this.status.children = models.map(\n (model) =>\n childrenStatus[model.url] ?? {\n modelUrl: model.url,\n completed: false,\n },\n );\n }\n\n protected async run(): Promise<void> {\n if (!this.models) {\n throw new Error('Cant start migration without models');\n }\n\n await this.indexLocalModels(this.models);\n\n const modelStatuses = this.status.children ?? [];\n const typeIndex = await this.loadTypeIndex();\n\n for (const modelStatus of modelStatuses) {\n const model = this.models.find(({ url }) => modelStatus.modelUrl === url);\n\n if (!model || modelStatus.completed) {\n continue;\n }\n\n await this.migrateRegisteredModel(model, modelStatus, typeIndex);\n await this.updateProgress(() => (modelStatus.completed = true));\n }\n\n for (const [modelClass, schema] of getSchemaMigrations()) {\n await modelClass.updateSchema(schema);\n }\n\n clearSchemaMigrations();\n }\n\n protected async migrateRegisteredModel(\n model: SolidModel,\n status: MigrateModelJobStatus,\n typeIndex?: Nullable<SolidTypeIndex>,\n ): Promise<void> {\n await this.migrate(model, status);\n\n if (!isContainer(model)) {\n return;\n }\n\n const registeredClasses = getContainerRegisteredClasses(model.static());\n const registration = typeIndex?.registrations.find(({ instanceContainer }) => instanceContainer === model.url);\n\n if (!typeIndex || !registration || registeredClasses.length === 0) {\n return;\n }\n\n registration.setAttribute(\n 'forClass',\n registeredClasses\n .map((modelClass) => getSchemaMigration(modelClass)?.rdfsClasses ?? modelClass.rdfsClass)\n .flat(),\n );\n\n await typeIndex.save();\n }\n\n protected async migrate(localModel: SolidModel, status: MigrateModelJobStatus): Promise<void> {\n this.assertNotCancelled();\n\n await this.migrateChildren(localModel, status);\n\n const schema = getSchemaMigration(localModel.static());\n\n if (!schema) {\n return;\n }\n\n const remoteModel = await getRemoteClass(localModel.static()).find(localModel.url);\n const migratedModel = await remoteModel?.migrateSchema(schema);\n\n await localModel.migrateSchema(schema, {\n mintOperationUrl: (operation) => {\n return migratedModel?.operations?.find((migratedOperation) => {\n if (\n !isInstanceOf(operation, PropertyOperation) ||\n !isInstanceOf(migratedOperation, PropertyOperation)\n ) {\n return false;\n }\n\n return (\n operation.property === migratedOperation.property &&\n operation.date.getTime() === migratedOperation.date.getTime()\n );\n })?.url;\n },\n });\n }\n\n protected async migrateChildren(localModel: SolidModel, status: MigrateModelJobStatus): Promise<void> {\n if (!isContainer(localModel)) {\n return;\n }\n\n const children = await this.loadContainedModels(localModel, { ignoreTombstones: true });\n\n status.children ??= children.map((child) => ({\n modelUrl: child.url,\n completed: false,\n }));\n\n for (const childStatus of status.children) {\n const child = children.find(({ url }) => childStatus.modelUrl === url);\n\n if (!child || childStatus.completed) {\n continue;\n }\n\n await this.migrate(child, childStatus);\n await this.updateProgress(() => (childStatus.completed = true));\n }\n }\n\n}\n","import {\n isInstanceOf,\n map,\n mixed,\n requireUrlParentDirectory,\n required,\n round,\n toString,\n urlRoute,\n} from '@noeldemartin/utils';\nimport { App, Errors, Job } from '@aerogel/core';\nimport { InvalidModelAttributes, requireBootedModel } from 'soukai';\nimport { MalformedSolidDocumentError } from '@noeldemartin/solid-utils';\nimport { Solid } from '@aerogel/plugin-solid';\nimport { SolidContainer, SolidModel, Tombstone, isContainer, isContainerClass } from 'soukai-solid';\nimport type { ObjectsMap } from '@noeldemartin/utils';\nimport type { JobListener, JobStatus } from '@aerogel/core';\nimport type { SolidContainsRelation, SolidEngine, SolidTypeIndex } from 'soukai-solid';\n\nimport {\n clearLocalModelUpdates,\n cloneLocalModel,\n cloneRemoteModel,\n completeRemoteModels,\n getLocalModel,\n getLocalModels,\n getRemoteClass,\n getRemoteModel,\n isRegisteredModel,\n isRemoteModel,\n trackModelsCollection,\n} from '@aerogel/plugin-local-first/lib/mirroring';\nimport {\n getContainerRegisteredClasses,\n getContainerRelations,\n getRelatedAppModels,\n isDirtyOrHasDirtyChildren,\n} from '@aerogel/plugin-local-first/lib/inference';\nimport DocumentsCache from '@aerogel/plugin-local-first/services/DocumentsCache';\n\nimport LoadsChildren from './mixins/LoadsChildren';\nimport LoadsTypeIndex from './mixins/LoadsTypeIndex';\nimport TracksLocalModels from './mixins/TracksLocalModels';\nimport type { ResourceJobStatus } from './mixins/LoadsChildren';\n\nconst Cloud = required(() => App.service('$cloud'));\nconst BaseJob = Job as typeof Job<JobListener, SyncJobStatus, SyncJobStatus>;\n\ninterface SyncJobStatus extends JobStatus {\n root: true;\n children: [SyncPullJobStatus, JobStatus];\n}\n\ninterface SyncPullJobStatus extends JobStatus {\n children?: ResourceJobStatus[];\n}\n\nfunction isRootStatus(status?: JobStatus): status is SyncJobStatus {\n return !!status && 'root' in status;\n}\n\nexport default class Sync extends mixed(BaseJob, [LoadsChildren, LoadsTypeIndex, TracksLocalModels]) {\n\n protected models?: SolidModel[];\n protected dirtyRemoteModels?: SolidModel[];\n protected rootLocalModels: SolidModel[];\n protected tombstones: ObjectsMap<Tombstone>;\n protected documentsWithErrors: Set<string>;\n protected syncedModelUrls: Set<string>;\n protected documentsModifiedAt: Record<string, Date>;\n protected screenLock: Promise<void | { release(): Promise<void> }> | null = null;\n protected override localModels: ObjectsMap<SolidModel>;\n\n constructor(models?: SolidModel[]) {\n super();\n\n this.models = models;\n this.rootLocalModels = [];\n this.localModels = map([], 'url');\n this.tombstones = map([], 'resourceUrl');\n this.documentsWithErrors = new Set();\n this.syncedModelUrls = new Set();\n this.documentsModifiedAt = {};\n }\n\n protected async run(): Promise<void> {\n const engine = Solid.requireAuthenticator().engine as SolidEngine;\n const updateDocumentDate = (url: string, { headers }: { headers?: Headers }, fallbackDate?: Date) => {\n const date = headers?.get('last-modified') ?? fallbackDate;\n\n if (!date || url.endsWith('/')) {\n return;\n }\n\n this.documentsModifiedAt[url] = new Date(date);\n };\n const clearListener = engine.listeners.add({\n onDocumentRead: (url, metadata) => updateDocumentDate(url, metadata),\n onDocumentUpdated: (url, metadata) => updateDocumentDate(url, metadata, new Date()),\n });\n\n try {\n this.lockScreen();\n this.rootLocalModels = this.models ?? getLocalModels();\n\n await this.indexLocalModels(this.rootLocalModels);\n await this.pullChanges();\n await this.pushChanges();\n } finally {\n this.releaseScreen();\n clearListener();\n }\n }\n\n protected lockScreen(): void {\n const typedNavigator = navigator as {\n wakeLock?: { request(type?: 'screen'): Promise<{ release(): Promise<void> }> };\n };\n\n if (!typedNavigator.wakeLock) {\n return;\n }\n\n try {\n this.screenLock = typedNavigator.wakeLock.request('screen').catch((error) => {\n Errors.reportDevelopmentError(error, 'Could not request screen wake lock');\n });\n } catch (error) {\n Errors.reportDevelopmentError(error, 'Could not request screen wake lock');\n }\n }\n\n protected releaseScreen(): void {\n if (!this.screenLock) {\n return;\n }\n\n this.screenLock.then((lock) => lock?.release());\n this.screenLock = null;\n }\n\n protected override getInitialStatus(): SyncJobStatus {\n return {\n root: true,\n completed: false,\n children: [{ completed: false }, { completed: false }],\n };\n }\n\n protected override calculateCurrentProgress(status?: JobStatus): number {\n status ??= this.status;\n\n if (isRootStatus(status)) {\n return round(\n this.calculateCurrentProgress(status.children[0]) * 0.9 +\n this.calculateCurrentProgress(status.children[1]) * 0.1,\n 2,\n );\n }\n\n return super.calculateCurrentProgress(status);\n }\n\n private async pullChanges(): Promise<void> {\n const remoteModelsArray = this.models\n ? await this.fetchRemoteModelsForLocal(this.models)\n : await this.fetchRemoteModels();\n const remoteModels = map(remoteModelsArray, (model) => {\n if (model instanceof Tombstone) {\n return model.resourceUrl;\n }\n\n return model.url;\n });\n\n this.dirtyRemoteModels = await this.synchronizeModels(remoteModels);\n\n await this.updateProgress((status) => (status.children[0].completed = true));\n }\n\n private async pushChanges(): Promise<void> {\n const remoteModels = this.dirtyRemoteModels ?? [];\n const childrenStatus = (this.status.children[1].children = remoteModels.map(() => ({ completed: false })));\n\n for (let index = 0; index < remoteModels.length; index++) {\n const remoteModel = remoteModels[index] as SolidModel;\n const childStatus = childrenStatus[index] as JobStatus;\n\n if (remoteModel.isSoftDeleted()) {\n remoteModel.enableHistory();\n remoteModel.enableTombstone();\n\n await remoteModel.forceDelete();\n await this.updateProgress(() => (childStatus.completed = true));\n\n return;\n }\n\n await this.saveModelAndChildren(remoteModel, childStatus);\n await this.updateTypeRegistrations(remoteModel);\n await this.updateProgress(() => (childStatus.completed = true));\n }\n\n for (const [documentUrl, modifiedAt] of Object.entries(this.documentsModifiedAt)) {\n await DocumentsCache.remember(documentUrl, modifiedAt);\n }\n\n clearLocalModelUpdates(this.syncedModelUrls, this.documentsWithErrors);\n\n await this.updateProgress((status) => (status.children[1].completed = true));\n }\n\n private async fetchRemoteModels(): Promise<SolidModel[]> {\n const pullStatus = this.status.children[0];\n const typeIndex = await this.loadTypeIndex({ fresh: true });\n\n if (!typeIndex) {\n return [];\n }\n\n const remoteModels: SolidModel[] = [];\n const registrations = this.getTypeRegistrations(typeIndex);\n\n pullStatus.children = registrations.map(() => ({ completed: false }));\n\n for (let index = 0; index < registrations.length; index++) {\n await this.ignoringDocumentErrors(async () => {\n const { registration, registeredModel } = required(registrations[index]);\n const remoteClass = getRemoteClass(registeredModel.modelClass);\n\n if (!registration.instanceContainer) {\n return;\n }\n\n if (isContainerClass(remoteClass)) {\n await trackModelsCollection(\n registeredModel.modelClass,\n requireUrlParentDirectory(registration.instanceContainer),\n );\n\n const container = await remoteClass.find(registration.instanceContainer);\n\n if (container) {\n await this.loadChildren(container, required(pullStatus.children?.[index]));\n\n remoteModels.push(container);\n }\n\n await this.updateProgress(() => (required(pullStatus.children?.[index]).completed = true));\n\n return;\n }\n\n await trackModelsCollection(registeredModel.modelClass, registration.instanceContainer);\n\n remoteModels.push(...(await remoteClass.from(registration.instanceContainer).all()));\n\n await this.updateProgress(() => (required(pullStatus.children?.[index]).completed = true));\n });\n }\n\n return completeRemoteModels(this.rootLocalModels, remoteModels, this.documentsWithErrors);\n }\n\n private async fetchRemoteModelsForLocal(models: SolidModel[]): Promise<SolidModel[]> {\n const remoteModels = [] as SolidModel[];\n const statusChildren = (this.status.children[0].children = models.map(() => ({ completed: false })));\n\n for (let index = 0; index < models.length; index++) {\n await this.ignoringDocumentErrors(async () => {\n const localModel = models[index] as SolidModel;\n const childStatus = statusChildren[index] as JobStatus;\n const remoteModel = await getRemoteClass(localModel.static()).find(localModel.url);\n\n if (!remoteModel) {\n await this.updateProgress(() => (childStatus.completed = true));\n\n return;\n }\n\n isContainer(remoteModel) && (await this.loadChildren(remoteModel, childStatus));\n\n remoteModels.push(remoteModel);\n\n await this.updateProgress(() => (childStatus.completed = true));\n });\n }\n\n return completeRemoteModels(models, remoteModels, this.documentsWithErrors);\n }\n\n private getTypeRegistrations(typeIndex: SolidTypeIndex) {\n const processedContainerUrls = new Set();\n const registeredModels = [...Cloud.registeredModels].map(({ modelClass }) => {\n const registeredChildren = isContainerClass(modelClass) ? getContainerRegisteredClasses(modelClass) : [];\n\n return {\n modelClass,\n rdfsClasses:\n registeredChildren.length > 0\n ? registeredChildren.map((childrenClass) => childrenClass.rdfsClasses).flat()\n : modelClass.rdfsClasses,\n };\n });\n const registrations = typeIndex.registrations\n .map((registration) => {\n const registeredModel = registeredModels.find(\n ({ rdfsClasses }) =>\n !!registration.instanceContainer &&\n rdfsClasses.some((rdfsClass) => registration.forClass.includes(rdfsClass)),\n );\n\n if (\n !registeredModel ||\n !registration.instanceContainer ||\n processedContainerUrls.has(registration.instanceContainer)\n ) {\n return null;\n }\n\n processedContainerUrls.add(registration.instanceContainer);\n\n return { registration, registeredModel };\n })\n .filter((match) => !!match);\n\n // Removed nested registrations.\n const containerUrls = registrations.map(({ registration }) => registration.instanceContainer);\n\n return registrations.filter(({ registration }) => {\n return !containerUrls.some(\n (containerUrl) =>\n containerUrl &&\n containerUrl !== registration.instanceContainer &&\n registration.instanceContainer?.startsWith(containerUrl),\n );\n });\n }\n\n private async updateTypeRegistrations(remoteModel: SolidModel): Promise<void> {\n if (!isRegisteredModel(remoteModel)) {\n return;\n }\n\n const registeredChildren = isContainer(remoteModel)\n ? getContainerRegisteredClasses(remoteModel.static())\n : [remoteModel.static()];\n\n const RemoteSolidContainer = getRemoteClass(SolidContainer);\n const container = isContainer(remoteModel)\n ? remoteModel\n : new RemoteSolidContainer({ url: remoteModel.requireContainerUrl() });\n\n if (registeredChildren.length === 0) {\n return;\n }\n\n const typeIndex = await this.loadTypeIndex({ create: true });\n\n if (typeIndex.registrations.some((registration) => registration.instanceContainer === remoteModel.url)) {\n return;\n }\n\n await container.register(typeIndex, registeredChildren);\n }\n\n private async loadChildren(model: SolidModel, childStatus?: JobStatus): Promise<void> {\n this.assertNotCancelled();\n\n if (!isContainer(model)) {\n return;\n }\n\n const children = await this.loadContainedModels(model, {\n status: childStatus,\n onDocumentError: (error) => this.handleDocumentError(error),\n onDocumentRead: (document) => {\n if (document.url.endsWith('/') || !document.updatedAt || document.url in this.documentsModifiedAt) {\n return;\n }\n\n this.documentsModifiedAt[document.url] = document.updatedAt;\n },\n onDocumentsLoaded: async () => {\n this.assertNotCancelled();\n\n await this.updateProgress();\n },\n });\n\n for (let index = 0; index < children.length; index++) {\n const child = children[index] as SolidModel;\n\n if (child instanceof Tombstone) {\n this.tombstones.add(child);\n\n continue;\n }\n\n if (this.tombstones.hasKey(child.url)) {\n await this.deleteChild(model, child);\n\n continue;\n }\n\n await this.loadChildren(child, childStatus?.children?.[index]);\n\n if (childStatus?.children?.[index]) {\n await this.updateProgress(() => (required(childStatus.children?.[index]).completed = true));\n }\n }\n }\n\n private async deleteChild(model: SolidModel, child: SolidModel): Promise<void> {\n for (const relation of model.static('relations')) {\n const relationInstance = model.requireRelation(relation);\n\n if (!relationInstance.related) {\n continue;\n }\n\n if (Array.isArray(relationInstance.related)) {\n relationInstance.related = relationInstance.related.filter((relatedModel) => relatedModel !== child);\n\n continue;\n }\n\n if (relationInstance.related === child) {\n relationInstance.related = null;\n\n continue;\n }\n }\n\n await child.forceDelete();\n }\n\n private async saveModelAndChildren(model: SolidModel, status?: JobStatus): Promise<void> {\n this.assertNotCancelled();\n\n if (isRemoteModel(model) && model.isSoftDeleted()) {\n model.enableHistory();\n model.enableTombstone();\n\n await model.forceDelete();\n\n return;\n }\n\n if (this.documentsWithErrors.has(model.requireDocumentUrl())) {\n return;\n }\n\n const wasDirty = model.isDirty();\n\n await model.save();\n\n if (wasDirty || isRemoteModel(model)) {\n this.syncedModelUrls.add(model.url);\n }\n\n if (!isContainer(model)) {\n if (isRemoteModel(model)) {\n const documentUrl = model.requireDocumentUrl();\n const modifiedAt = this.documentsModifiedAt[documentUrl];\n\n if (modifiedAt) {\n await DocumentsCache.remember(documentUrl, modifiedAt);\n\n delete this.documentsModifiedAt[documentUrl];\n }\n }\n\n return;\n }\n\n const children = getContainerRelations(model.static())\n .map((relation) => model.getRelationModels(relation) ?? [])\n .flat();\n\n const childrenStatuses = status ? children.map(() => ({ completed: false })) : [];\n\n if (status) {\n status.children = childrenStatuses;\n }\n\n for (let index = 0; index < children.length; index++) {\n const child = children[index] as SolidModel;\n const childStatus = childrenStatuses[index];\n\n await this.saveModelAndChildren(child, childStatus);\n\n if (childStatus) {\n await this.updateProgress(() => (childStatus.completed = true));\n }\n }\n }\n\n private async synchronizeModels(remoteModels: ObjectsMap<SolidModel>): Promise<SolidModel[]> {\n const synchronizedModelUrls = new Set<string>();\n const deletedModels = new Set<SolidModel>();\n\n for (const remoteModel of remoteModels.items()) {\n if (remoteModel instanceof Tombstone) {\n const localModel = this.localModels.get(remoteModel.resourceUrl);\n\n if (localModel) {\n await localModel.forceDelete();\n\n deletedModels.add(localModel);\n }\n\n continue;\n }\n\n const localModel = getLocalModel(remoteModel, this.localModels);\n\n if (!localModel.exists()) {\n this.syncedModelUrls.add(localModel.url);\n }\n\n await this.loadChildren(localModel);\n await SolidModel.synchronize(localModel, remoteModel);\n await this.reconcileInconsistencies(localModel, remoteModel);\n await this.saveModelAndChildren(localModel);\n await this.addLocalModel(localModel);\n\n this.rootLocalModels.push(localModel);\n synchronizedModelUrls.add(localModel.url);\n }\n\n for (const localModel of this.rootLocalModels) {\n if (deletedModels.has(localModel) || synchronizedModelUrls.has(localModel.url)) {\n continue;\n }\n\n await this.loadChildren(localModel);\n\n const remoteModel = getRemoteModel(localModel, remoteModels);\n\n await SolidModel.synchronize(localModel, remoteModel);\n\n remoteModels.add(remoteModel);\n }\n\n const dirtyRemoteModels = [];\n\n for (const remoteModel of remoteModels.getItems()) {\n if (isDirtyOrHasDirtyChildren(remoteModel)) {\n dirtyRemoteModels.push(remoteModel);\n\n continue;\n }\n\n await this.rememberModelDocuments(remoteModel);\n }\n\n return dirtyRemoteModels;\n }\n\n private async reconcileInconsistencies(\n localModel: SolidModel,\n remoteModel: SolidModel,\n processedModels?: Set<SolidModel>,\n ): Promise<void> {\n localModel.rebuildAttributesFromHistory();\n localModel.setAttributes(remoteModel.getAttributes(true));\n\n processedModels ??= new Set();\n processedModels.add(localModel);\n\n for (const relation of getContainerRelations(localModel.static())) {\n await this.synchronizeContainerDocuments(\n localModel.requireRelation<SolidContainsRelation>(relation),\n remoteModel.requireRelation<SolidContainsRelation>(relation),\n );\n }\n\n const remoteRelatedModels = map(getRelatedAppModels(remoteModel), 'url');\n\n for (const localRelatedModel of getRelatedAppModels(localModel)) {\n if (\n processedModels.has(localRelatedModel) ||\n !localRelatedModel.isRelationLoaded('operations') ||\n !remoteRelatedModels.hasKey(localRelatedModel.url)\n ) {\n continue;\n }\n\n await this.reconcileInconsistencies(\n localRelatedModel,\n remoteRelatedModels.require(localRelatedModel.url),\n processedModels,\n );\n }\n\n if (localModel.isDirty()) {\n await SolidModel.synchronize(localModel, remoteModel);\n }\n }\n\n private async synchronizeContainerDocuments(\n localRelation: SolidContainsRelation,\n remoteRelation: SolidContainsRelation,\n ): Promise<void> {\n const localModels = map(localRelation.related ?? [], 'url');\n const remoteModels = map(remoteRelation.related ?? [], 'url');\n const newLocalModelUrls = localModels\n .getKeys()\n .filter((url) => !remoteModels.hasKey(url) && !remoteModels.hasKey(encodeURI(url)));\n const newRemoteModelUrls = remoteModels\n .getKeys()\n .filter((url) => !localModels.hasKey(url) && !localModels.hasKey(encodeURI(url)));\n\n for (const url of newLocalModelUrls) {\n const localModel = localModels.require(url);\n const remoteModel = cloneLocalModel(localModel);\n\n remoteRelation.addRelated(remoteModel);\n remoteModels.add(remoteModel);\n }\n\n for (const url of newRemoteModelUrls) {\n const remoteModel = remoteModels.require(url);\n const localModel = cloneRemoteModel(remoteModel);\n\n localRelation.addRelated(localModel);\n localModels.add(localModel);\n this.syncedModelUrls.add(localModel.url);\n }\n\n for (const localModel of localModels.items()) {\n const remoteModel = remoteModels.require(localModel.url);\n\n await SolidModel.synchronize(localModel, remoteModel);\n await this.saveModelAndChildren(localModel);\n }\n }\n\n private async rememberModelDocuments(model: SolidModel): Promise<void> {\n if (!isContainer(model)) {\n const documentUrl = model.requireDocumentUrl();\n const modifiedAt = this.documentsModifiedAt[documentUrl];\n\n if (modifiedAt) {\n await DocumentsCache.remember(documentUrl, modifiedAt);\n\n delete this.documentsModifiedAt[documentUrl];\n }\n\n return;\n }\n\n const children = getContainerRelations(model.static())\n .map((relation) => model.getRelationModels(relation) ?? [])\n .flat();\n\n for (const child of children) {\n await this.rememberModelDocuments(child);\n }\n }\n\n private async ignoringDocumentErrors(operation: Function): Promise<void> {\n try {\n await operation();\n } catch (error) {\n this.handleDocumentError(error);\n }\n }\n\n private handleDocumentError(error: unknown): void {\n if (isInstanceOf(error, MalformedSolidDocumentError)) {\n // eslint-disable-next-line no-console\n console.warn(error.message);\n\n error.documentUrl && this.documentsWithErrors.add(error.documentUrl);\n\n return;\n }\n\n if (isInstanceOf(error, InvalidModelAttributes)) {\n // eslint-disable-next-line no-console\n console.warn(error.message);\n\n const primaryKey = error.attributes[requireBootedModel(error.modelName).primaryKey];\n const documentUrl = primaryKey && urlRoute(toString(primaryKey));\n\n documentUrl && this.documentsWithErrors.add(documentUrl);\n\n return;\n }\n\n throw error;\n }\n\n}\n","import { defineServiceState, replaceExisting, translateWithDefault } from '@aerogel/core';\nimport { Solid } from '@aerogel/plugin-solid';\nimport type { ErrorSource } from '@aerogel/core';\nimport type { Nullable } from '@noeldemartin/utils';\nimport type { SolidModelConstructor, SolidSchemaDefinition } from 'soukai-solid';\n\nimport Migrate from '@aerogel/plugin-local-first/jobs/Migrate';\nimport type Sync from '@aerogel/plugin-local-first/jobs/Sync';\n\nexport const CloudStatus = {\n Disconnected: 'disconnected',\n Online: 'online',\n Syncing: 'syncing',\n Migrating: 'migrating',\n} as const;\n\nexport interface ModelRegistration {\n modelClass: SolidModelConstructor;\n path?: string;\n}\n\nexport type TCloudStatus = (typeof CloudStatus)[keyof typeof CloudStatus];\n\nexport default defineServiceState({\n name: 'cloud',\n persist: [\n 'localModelUpdates',\n 'migrationDismissed',\n 'migrationJob',\n 'modelCollections',\n 'pollingEnabled',\n 'pollingMinutes',\n 'ready',\n 'startupSync',\n ],\n initialState: () => ({\n autoPush: true,\n localModelUpdates: {} as Record<string, number>,\n migrationDismissed: false,\n migrationJob: null as Nullable<Migrate>,\n migrationPostponed: false,\n modelCollections: {} as Record<string, string[]>,\n pollingEnabled: true,\n pollingMinutes: 10,\n ready: false,\n registeredModels: [] as ModelRegistration[],\n schemaMigrations: new Map<SolidModelConstructor, SolidModelConstructor | SolidSchemaDefinition>(),\n setupDismissed: false,\n setupOngoing: false,\n startupSync: true,\n status: CloudStatus.Disconnected as TCloudStatus,\n syncError: null as Nullable<ErrorSource>,\n syncJob: null as Nullable<Sync>,\n }),\n serialize: (state) => replaceExisting(state, { migrationJob: state.migrationJob?.serialize() }),\n restore: (state) =>\n replaceExisting(state, {\n migrationJob: state.migrationJob && Migrate.restore(state.migrationJob),\n }),\n watch: {\n migrationJob(migrationJob) {\n migrationJob?.listeners.add({ onUpdated: () => this.updatePersistedState('migrationJob') });\n },\n },\n computed: {\n disconnected: ({ status }) => status === CloudStatus.Disconnected,\n online: ({ status }) => status === CloudStatus.Online,\n syncing: ({ status }) => status === CloudStatus.Syncing,\n migrating: ({ status }) => status === CloudStatus.Migrating,\n localChanges({ localModelUpdates }) {\n return Object.values(localModelUpdates).reduce((total, count) => total + count, 0);\n },\n dirty(): boolean {\n return this.localChanges > 0;\n },\n migrationStarted({ migrationJob }): boolean {\n return !!migrationJob;\n },\n migrationDisabledReason({ status, ready }): string | null {\n if (!Solid.isLoggedIn()) {\n return translateWithDefault(\n 'cloud.migrationNotLoggedIn',\n 'You need to reconnect before starting the migration',\n );\n }\n\n if (!ready) {\n return translateWithDefault(\n 'cloud.migrationNotReady',\n 'You need to backup your data before starting the migration',\n );\n }\n\n if (status === CloudStatus.Syncing || status === CloudStatus.Migrating) {\n return translateWithDefault(\n 'cloud.migrationNotSyncing',\n 'Wait for syncing to finish before starting the migration',\n );\n }\n\n if (!this.online) {\n return translateWithDefault(\n 'cloud.migrationNotOnline',\n 'You need to be online in order to start the migration',\n );\n }\n\n return null;\n },\n },\n});\n","import {\n Semaphore,\n after,\n facade,\n fail,\n getLocationQueryParameter,\n hasLocationQueryParameter,\n isArray,\n isTesting,\n parseBoolean,\n} from '@noeldemartin/utils';\nimport { Errors, Events, dispatch, translateWithDefault } from '@aerogel/core';\nimport { Solid } from '@aerogel/plugin-solid';\nimport { SolidContainer, SolidModel, Tombstone, isContainer, isContainerClass, isSolidModel } from 'soukai-solid';\nimport { getTrackedModels, trackModels, trackModelsCollection } from '@aerogel/plugin-soukai';\nimport { watchEffect } from 'vue';\nimport { getBootedModels } from 'soukai';\nimport type { Authenticator } from '@aerogel/plugin-solid';\nimport type { Engine } from 'soukai';\nimport type { JobListener } from '@aerogel/core';\nimport type { SolidContainsRelation, SolidModelConstructor, SolidSchemaDefinition } from 'soukai-solid';\n\nimport {\n clearLocalModelUpdates,\n createRemoteModel,\n getLocalModels,\n getRemoteClass,\n getRemoteContainersCollection,\n updateRemoteModel,\n} from '@aerogel/plugin-local-first/lib/mirroring';\nimport Backup from '@aerogel/plugin-local-first/jobs/Backup';\nimport DocumentsCache from '@aerogel/plugin-local-first/services/DocumentsCache';\nimport Migrate from '@aerogel/plugin-local-first/jobs/Migrate';\nimport Sync from '@aerogel/plugin-local-first/jobs/Sync';\nimport SyncQueue from '@aerogel/plugin-local-first/lib/SyncQueue';\nimport {\n getContainedModels,\n getContainerRelations,\n getRelatedClasses,\n} from '@aerogel/plugin-local-first/lib/inference';\n\nimport Service, { CloudStatus } from './Cloud.state';\n\nexport interface RegisterOptions {\n path?: string;\n}\n\nexport interface SyncOptions extends JobListener {\n refreshUserProfile?: boolean;\n model?: SolidModel;\n models?: SolidModel[];\n}\n\nexport class CloudService extends Service {\n\n protected asyncLock: Semaphore = new Semaphore();\n protected engine: Engine | null = null;\n protected pollingInterval: NodeJS.Timeout | null = null;\n\n public async whenReady<T>(callback: () => T): Promise<T> {\n if (this.ready) {\n return callback();\n }\n\n return new Promise((resolve) => {\n const onReady = () => resolve(callback());\n\n Events.once('cloud:ready', onReady);\n });\n }\n\n public async setup(modelUrlMappings?: WeakMap<SolidModelConstructor, Record<string, string>>): Promise<void> {\n this.setupOngoing = true;\n\n try {\n await this.backup(modelUrlMappings);\n await this.setReady(true);\n await this.sync();\n } finally {\n this.setupOngoing = false;\n }\n }\n\n public dismissSetup(): void {\n this.setupDismissed = true;\n }\n\n public dismissMigration(): void {\n this.migrationDismissed = true;\n }\n\n public postponeMigration(): void {\n this.migrationPostponed = true;\n }\n\n public async syncIfOnline(options?: SyncOptions): Promise<void>;\n public async syncIfOnline(model: SolidModel): Promise<void>;\n public async syncIfOnline(models: SolidModel[]): Promise<void>;\n public async syncIfOnline(config: SyncOptions | SolidModel | SolidModel[] = {}): Promise<void> {\n if (!this.online) {\n return;\n }\n\n await this.sync(config as SyncOptions);\n }\n\n public async sync(options?: SyncOptions): Promise<void>;\n public async sync(model: SolidModel): Promise<void>;\n public async sync(models: SolidModel[]): Promise<void>;\n public async sync(config: SyncOptions | SolidModel | SolidModel[] = {}): Promise<void> {\n const options = isArray(config)\n ? { models: config }\n : config instanceof SolidModel\n ? { model: config }\n : config;\n\n if (!Solid.isLoggedIn() || !this.ready || !this.online) {\n return;\n }\n\n await this.asyncLock.run(async () => {\n const start = Date.now();\n const models = options.model ? [options.model] : options.models;\n\n this.syncError = null;\n this.status = CloudStatus.Syncing;\n\n SyncQueue.clear(models);\n\n try {\n await Events.emit('cloud:sync-started', models);\n\n if (options.refreshUserProfile) {\n await Solid.refreshUserProfile();\n }\n\n this.syncJob = new Sync(models);\n\n this.syncJob.listeners.add(options);\n\n await dispatch(this.syncJob);\n\n if (this.syncJob.cancelled) {\n return;\n }\n\n if (!isTesting('unit')) {\n await after({ milliseconds: Math.max(500, 1000 - (Date.now() - start)) });\n }\n\n this.syncJob = null;\n } catch (error) {\n if (isTesting()) {\n throw error;\n }\n\n this.syncJob = null;\n this.syncError = error;\n\n await Errors.report(error, translateWithDefault('cloud.syncFailed', 'Sync failed'));\n } finally {\n this.status = CloudStatus.Online;\n\n await Events.emit('cloud:sync-completed', models);\n }\n });\n }\n\n public shouldMigrate(): boolean {\n return this.schemaMigrations.size > 0;\n }\n\n public async migrate(listener?: JobListener): Promise<void> {\n if (!this.online || !Solid.isLoggedIn() || !this.ready) {\n throw new Error('Data cannot be migrated at the moment');\n }\n\n if (!this.shouldMigrate()) {\n return;\n }\n\n await this.asyncLock.run(async () => {\n this.status = CloudStatus.Migrating;\n this.migrationJob ??= new Migrate();\n\n const start = Date.now();\n const removeListeners: Function[] = [];\n const models = (this.migrationJob.models ??= getLocalModels());\n\n SyncQueue.clear(models);\n\n try {\n listener && removeListeners.push(this.migrationJob.listeners.add(listener));\n\n await Events.emit('cloud:migration-started', models);\n await dispatch(this.migrationJob);\n\n if (this.migrationJob.cancelled) {\n await Events.emit('cloud:migration-cancelled', models);\n\n return;\n }\n\n this.migrationJob = null;\n this.migrationDismissed = false;\n this.migrationPostponed = false;\n\n await after({ milliseconds: Math.max(0, 1000 - (Date.now() - start)) });\n await Events.emit('cloud:migration-completed', models);\n } catch (error) {\n await Errors.report(error, translateWithDefault('cloud.migrationFailed', 'Migration failed'));\n } finally {\n this.status = CloudStatus.Online;\n\n removeListeners.forEach((removeListener) => removeListener?.());\n }\n });\n }\n\n public async register(modelClass: SolidModelConstructor, options: RegisterOptions = {}): Promise<void> {\n if (this.registeredModels.find((registered) => modelClass === registered.modelClass)) {\n return;\n }\n\n const engine = this.engine;\n\n if (engine) {\n getRelatedClasses(modelClass).forEach((relatedClass) => getRemoteClass(relatedClass).setEngine(engine));\n }\n\n this.whenReady(() => {\n const [existingCollection] = this.modelCollections[modelClass.modelName] ?? [];\n\n modelClass.useSoftDeletes(true);\n\n modelClass.collection = existingCollection ?? getRemoteContainersCollection(modelClass, options.path);\n });\n\n await trackModels(modelClass, {\n created: (model) => this.ready && createRemoteModel(model),\n updated: (model) => this.ready && updateRemoteModel(model),\n deleted: (model) =>\n this.ready && clearLocalModelUpdates(new Set([model.url ?? model.getDeletedPrimaryKey()])),\n });\n\n if (isContainerClass(modelClass)) {\n getContainerRelations(modelClass).forEach((relation) => {\n const relatedClass = modelClass\n .instance()\n .requireRelation<SolidContainsRelation>(relation).relatedClass;\n\n relatedClass.on('created', (model) => this.ready && createRemoteModel(model));\n relatedClass.on('updated', (model) => this.ready && updateRemoteModel(model));\n relatedClass.on(\n 'deleted',\n (model) =>\n this.ready && clearLocalModelUpdates(new Set([model.url ?? model.getDeletedPrimaryKey()])),\n );\n });\n }\n\n this.registeredModels.push({ modelClass, path: options.path });\n\n for (const collection of this.modelCollections[modelClass.modelName] ?? []) {\n await trackModelsCollection(modelClass, collection);\n }\n }\n\n public registerSchemaMigration(\n modelClass: SolidModelConstructor,\n schema: SolidModelConstructor | SolidSchemaDefinition,\n ): void {\n this.schemaMigrations.set(modelClass, schema);\n }\n\n public requireRemoteCollection(modelClass: SolidModelConstructor): string {\n for (const registration of this.registeredModels) {\n if (modelClass !== registration.modelClass) {\n continue;\n }\n\n return getRemoteContainersCollection(registration.modelClass, registration.path);\n }\n\n throw new Error(`Failed resolving remote collection for '${modelClass.modelName}' model`);\n }\n\n protected override async boot(): Promise<void> {\n await Solid.booted;\n\n Solid.isLoggedIn() && this.login(Solid.authenticator);\n\n Events.on('auth:login', ({ authenticator }) => this.login(authenticator));\n Events.on('auth:logout', () => this.logout());\n Events.once('application-ready', () => this.onApplicationReady());\n Events.once('application-mounted', () => this.onApplicationMounted());\n\n watchEffect(() => {\n this.pollingInterval && clearInterval(this.pollingInterval);\n\n if (!this.pollingEnabled || this.migrationJob) {\n this.pollingInterval = null;\n\n return;\n }\n\n this.pollingInterval = setInterval(() => this.sync(), this.pollingMinutes * 60 * 1000);\n });\n\n await this.bustDocumentsCache();\n await this.registerModels();\n }\n\n protected getDirtyLocalModels(): SolidModel[] {\n const urls = Object.keys(this.localModelUpdates);\n const dirtyLocalModels = [];\n\n for (const { modelClass } of this.registeredModels) {\n for (const model of getTrackedModels(modelClass, { includeSoftDeleted: true })) {\n dirtyLocalModels.push(...this.getModelsIn(urls, model));\n }\n }\n\n return dirtyLocalModels;\n }\n\n protected getModelsIn(urls: string[], model: SolidModel): SolidModel[] {\n const models = [];\n\n if (urls.includes(model.url)) {\n models.push(model);\n }\n\n if (isContainer(model)) {\n models.push(\n ...getContainedModels(model)\n .map((containedModel) => this.getModelsIn(urls, containedModel))\n .flat(),\n );\n }\n\n return models;\n }\n\n protected requireEngine(): Engine {\n return this.engine ?? fail('Could not get required Engine');\n }\n\n protected async setReady(ready: boolean): Promise<void> {\n if (this.ready || !ready) {\n return;\n }\n\n await Events.emit('cloud:ready');\n\n this.ready = true;\n }\n\n protected async backup(modelUrlMappings?: WeakMap<SolidModelConstructor, Record<string, string>>): Promise<void> {\n await Events.emit('cloud:backup-started');\n\n modelUrlMappings ??= new WeakMap();\n\n const job = new Backup();\n\n for (const { modelClass, path } of this.registeredModels) {\n if (!isContainerClass(modelClass)) {\n continue;\n }\n\n for (const [local, remote] of Object.entries(modelUrlMappings.get(modelClass) ?? {})) {\n job.migrateUrl(modelClass, local, remote);\n }\n\n const localCollection = modelClass.collection;\n const remoteCollection = getRemoteContainersCollection(modelClass, path);\n\n modelClass.collection = remoteCollection;\n\n job.migrateCollection(modelClass, localCollection, remoteCollection);\n }\n\n await dispatch(job);\n await Events.emit('cloud:backup-completed');\n }\n\n protected async onApplicationReady(): Promise<void> {\n if (this.ready || !Solid.isLoggedIn()) {\n return;\n }\n\n await this.setReady(!getLocalModels().some((model) => model.url.startsWith('solid://')));\n }\n\n protected async onApplicationMounted(): Promise<void> {\n if (!this.syncOnStartup()) {\n return;\n }\n\n await this.sync();\n }\n\n protected login(authenticator: Authenticator): void {\n const relatedClasses = [...this.registeredModels]\n .map(({ modelClass }) => getRelatedClasses(modelClass))\n .flat()\n .concat([Tombstone]);\n\n this.status = CloudStatus.Online;\n this.engine = authenticator.engine;\n\n getRemoteClass(SolidContainer).setEngine(this.engine);\n\n for (const relatedClass of relatedClasses) {\n getRemoteClass(relatedClass).setEngine(this.engine);\n }\n }\n\n protected logout(): void {\n this.setState({\n localModelUpdates: {},\n migrationDismissed: false,\n migrationJob: null,\n migrationPostponed: false,\n modelCollections: {},\n pollingEnabled: true,\n pollingMinutes: 10,\n ready: false,\n setupDismissed: false,\n setupOngoing: false,\n startupSync: true,\n status: CloudStatus.Disconnected,\n });\n }\n\n private syncOnStartup(): boolean {\n if (hasLocationQueryParameter('startupSync')) {\n return parseBoolean(getLocationQueryParameter('startupSync'));\n }\n\n if (this.migrationJob) {\n return false;\n }\n\n return this.startupSync;\n }\n\n private async bustDocumentsCache(): Promise<void> {\n if (\n !hasLocationQueryParameter('bustDocumentsCache') ||\n !parseBoolean(getLocationQueryParameter('bustDocumentsCache'))\n ) {\n return;\n }\n\n await DocumentsCache.booted;\n await DocumentsCache.clear();\n }\n\n private async registerModels(): Promise<void> {\n const models = getBootedModels();\n\n for (const model of models.values()) {\n if (!isSolidModel(model) || !model.cloud) {\n continue;\n }\n\n await this.register(model, typeof model.cloud === 'boolean' ? {} : model.cloud);\n }\n }\n\n}\n\nexport default facade(CloudService);\n\ndeclare module '@aerogel/core' {\n export interface EventsPayload {\n 'cloud:ready': void;\n 'cloud:backup-started': void;\n 'cloud:backup-completed': void;\n 'cloud:migration-started': SolidModel[];\n 'cloud:migration-cancelled': SolidModel[];\n 'cloud:migration-completed': SolidModel[];\n 'cloud:sync-started': SolidModel[] | undefined;\n 'cloud:sync-completed': SolidModel[] | undefined;\n }\n}\n\ndeclare module 'soukai-solid' {\n // eslint-disable-next-line @typescript-eslint/no-shadow\n namespace SolidModel {\n export const cloud: boolean | RegisterOptions | undefined;\n }\n}\n","<template>\n <details v-if=\"!$solid.hasLoggedIn()\" class=\"mt-4\">\n <summary>\n <span class=\"text-base font-semibold\">{{ $td('settings.dangerZone', 'Danger zone') }}</span>\n </summary>\n <Button variant=\"danger\" class=\"mt-4\" @click=\"purgeData()\">\n <IconTrash class=\"size-4\" />\n <span class=\"ml-1\">{{ $td('settings.purge', 'Purge data') }}</span>\n </Button>\n </details>\n</template>\n\n<script setup lang=\"ts\">\nimport IconTrash from '~icons/zondicons/trash';\n\nimport { Button, Storage, UI, translateWithDefault } from '@aerogel/core';\n\nimport AccountLoginModal from '@aerogel/plugin-local-first/components/AccountLoginModal.vue';\n\nasync function purgeData(): Promise<void> {\n const confirmed = await UI.confirm(\n translateWithDefault('settings.purgeConfirmTitle', 'Delete everything?'),\n translateWithDefault(\n 'settings.purgeConfirmMessage',\n 'If you proceed, all your data will be deleted forever. ' +\n 'If you want to save it before wiping this device, ' +\n 'you can [connect to your Solid account](#action:connect) first.',\n ),\n {\n acceptVariant: 'danger',\n acceptText: translateWithDefault('settings.purgeConfirmAccept', 'Purge data'),\n actions: { connect: () => UI.modal(AccountLoginModal) },\n },\n );\n\n if (!confirmed) {\n return;\n }\n\n await UI.closeAllModals();\n await Storage.purge();\n}\n</script>\n","import { defineSettings } from '@aerogel/core';\n\nimport PurgeData from './PurgeData.vue';\n\nexport default defineSettings([\n {\n priority: 0,\n component: PurgeData,\n },\n]);\n","<template>\n <Modal\n ref=\"$modalRef\"\n title-hidden\n close-hidden\n :title=\"$td('account.title', 'Account')\"\n >\n <div class=\"relative flex items-center rounded-md bg-gray-100 p-4 pr-12\">\n <SolidAvatar class=\"mr-2 size-16 shrink-0\" />\n <div class=\"flex flex-col overflow-hidden\">\n <span class=\"font-semibold\">{{ $solid.user?.name ?? $td('user.anonymous', 'Anonymous') }}</span>\n <Link :href=\"$solid.user?.webId\" class=\"mt-0.5 truncate text-sm font-light text-gray-500\">\n {{ $solid.user?.webId }}\n </Link>\n </div>\n <Button\n size=\"icon\"\n variant=\"ghost\"\n class=\"absolute top-1 right-1 hover:bg-gray-200\"\n :aria-label=\"$td('user.settings', 'Settings')\"\n :title=\"$td('user.settings', 'Settings')\"\n @click=\"$ui.modal(SettingsModal)\"\n >\n <IconCog class=\"size-5\" />\n </Button>\n </div>\n\n <div class=\"px-2\">\n <div v-if=\"$cloud.syncing\" class=\"mt-4 flex items-center gap-2\">\n <IconRefresh class=\"mt-0.5 size-6 shrink-0 animate-spin self-start text-green-500\" />\n <div class=\"flex w-full flex-col\">\n <Markdown lang-key=\"cloud.info.syncing\" lang-default=\"Synchronizing...\" />\n <ProgressBar v-if=\"$cloud.syncJob\" :job=\"$cloud.syncJob\" filled-class=\"bg-green-500\" />\n </div>\n </div>\n <div v-else-if=\"$solid.loginOngoing\" class=\"mt-4 flex items-center gap-2\">\n <IconRefresh class=\"mt-0.5 size-6 shrink-0 animate-spin self-start text-green-500\" />\n <Markdown lang-key=\"cloud.info.reconnecting\" lang-default=\"Reconnecting...\" />\n </div>\n <div v-else-if=\"error\" class=\"mt-4 flex items-center gap-2\">\n <IconWarning class=\"mt-0.5 size-6 shrink-0 self-start text-red-500\" />\n <div>\n <Markdown :text=\"errorDescription\" />\n <Link\n v-if=\"showErrorDetails\"\n class=\"text-sm text-red-700 opacity-50 hover:opacity-75 focus-visible:opacity-75\"\n @click=\"$errors.inspect(error)\"\n >\n {{ $td('errors.viewDetails', 'View details') }}\n </Link>\n </div>\n </div>\n <div v-else-if=\"!$cloud.ready\" class=\"mt-4 flex items-center gap-2\">\n <IconWarning class=\"mt-0.5 size-6 shrink-0 self-start text-yellow-500\" />\n <Markdown lang-key=\"cloud.info.setup\" lang-default=\"Your data is not backed up yet.\" />\n </div>\n <div v-else-if=\"$cloud.dirty\" class=\"mt-4 flex items-center gap-2\">\n <IconWarning class=\"mt-0.5 size-6 shrink-0 self-start text-yellow-500\" />\n <Markdown\n lang-key=\"cloud.info.changes\"\n lang-default=\"Everything is up to date. | There is one local change. | There are {n} local changes.\"\n :lang-params=\"$cloud.localChanges\"\n />\n </div>\n <div v-else-if=\"$cloud.online\" class=\"mt-4 flex items-center gap-2\">\n <IconCheckmarkOutline class=\"mt-0.5 size-6 shrink-0 self-start text-green-500\" />\n <Markdown lang-key=\"cloud.info.changes\" lang-default=\"Everything is up to date.\" :lang-params=\"0\" />\n </div>\n <div v-else class=\"mt-4 flex items-center gap-2\">\n <IconWarning class=\"mt-0.5 size-6 shrink-0 self-start text-yellow-500\" />\n <Markdown\n lang-key=\"cloud.info.disconnected\"\n lang-default=\"You are disconnected from your Solid account, all the changes you make will remain in your device.\"\n />\n </div>\n <AdvancedOptions class=\"mt-2\">\n <ul class=\"flex flex-col gap-2\">\n <li>\n <Checkbox\n v-model=\"$solid.autoReconnect\"\n label-class=\"text-base\"\n :label=\"$td('cloud.advanced.reconnect', 'Reconnect on startup')\"\n />\n </li>\n <li>\n <Checkbox\n v-model=\"$cloud.startupSync\"\n label-class=\"text-base\"\n :label=\"$td('cloud.advanced.startupSync', 'Synchronize on startup')\"\n />\n </li>\n <li>\n <Checkbox v-model=\"$cloud.pollingEnabled\" label-class=\"text-base\">\n <div class=\"flex items-center\">\n <span aria-hidden=\"true\">{{ pollingText[0] }}</span>\n <EditableContent\n type=\"number\"\n :text=\"`${$cloud.pollingMinutes}`\"\n :aria-label=\"\n $td('cloud.advanced.pollingMinutes', 'Synchronization interval (in minutes)')\n \"\n class=\"focus-within:border-primary-600 mx-1 -mb-px border-b\"\n @update=\"$cloud.pollingMinutes = $event as number\"\n >\n {{ $cloud.pollingMinutes }}\n </EditableContent>\n <span v-if=\"pollingText.length > 1\" aria-hidden=\"true\">{{ pollingText[1] }}</span>\n </div>\n </Checkbox>\n </li>\n </ul>\n </AdvancedOptions>\n </div>\n\n <div v-if=\"!$solid.loginOngoing\" class=\"mt-4 flex flex-row-reverse justify-start gap-2\">\n <Button\n v-if=\"$cloud.syncing\"\n variant=\"secondary\"\n :disabled=\"cancellingSync\"\n @click=\"cancelSync()\"\n >\n <IconStop class=\"size-5\" />\n <span>{{\n cancellingSync ? $td('cloud.stopping', 'Stopping...') : $td('cloud.stop', 'Stop synchronization')\n }}</span>\n </Button>\n <Button v-else-if=\"!$solid.isLoggedIn()\" @click=\"$solid.reconnect({ force: true })\">\n <IconRefresh class=\"size-5\" />\n <span>{{ $td('cloud.reconnect', 'Reconnect') }}</span>\n </Button>\n <Button v-else-if=\"$cloud.ready\" @click=\"$cloud.sync({ refreshUserProfile: true })\">\n <IconRefresh class=\"size-5\" />\n <span>{{ $td('cloud.sync', 'Synchronize') }}</span>\n </Button>\n <Button v-else @click=\"(($cloud.setupDismissed = false), $modal?.close())\">\n <IconCloudUpload class=\"size-5\" />\n <span>{{ $td('cloud.setup.submit', 'Back up now') }}</span>\n </Button>\n <Button v-if=\"!$cloud.syncing\" variant=\"secondary\" @click=\"$solid.logout()\">\n <IconLogout class=\"size-5\" />\n <span>{{ $cloud.ready ? $td('cloud.logOut', 'Log out') : $td('cloud.disconnect', 'Disconnect') }}</span>\n </Button>\n </div>\n </Modal>\n</template>\n\n<script setup lang=\"ts\">\nimport IconCheckmarkOutline from '~icons/zondicons/checkmark-outline';\nimport IconCloudUpload from '~icons/ic/sharp-cloud-upload';\nimport IconCog from '~icons/zondicons/cog';\nimport IconLogout from '~icons/material-symbols/logout-rounded';\nimport IconRefresh from '~icons/zondicons/refresh';\nimport IconStop from '~icons/ic/baseline-stop';\nimport IconWarning from '~icons/ion/warning';\n\nimport {\n AdvancedOptions,\n Button,\n Checkbox,\n EditableContent,\n Link,\n Markdown,\n Modal,\n ProgressBar,\n SettingsModal,\n translateWithDefault,\n useEvent,\n} from '@aerogel/core';\nimport { computed, ref, useTemplateRef } from 'vue';\nimport { Solid, SolidAvatar } from '@aerogel/plugin-solid';\n\nimport Cloud from '@aerogel/plugin-local-first/services/Cloud';\n\nconst $modal = useTemplateRef('$modalRef');\nconst cancellingSync = ref(false);\nconst pollingText = translateWithDefault('cloud.advanced.polling', 'Synchronize every {minutes} minutes', {\n minutes: '%%separator%%',\n}).split('%%separator%%');\nconst error = computed(() => Solid.error ?? Cloud.syncError);\nconst errorDescription = computed(() => {\n if (!error.value) {\n return;\n }\n\n if (typeof error.value === 'string') {\n return error.value;\n }\n\n return translateWithDefault('cloud.info.error', 'There has been an error connecting.');\n});\nconst showErrorDetails = computed(() => error.value && typeof error.value !== 'string');\n\nasync function cancelSync() {\n if (!Cloud.syncJob) {\n return;\n }\n\n cancellingSync.value = true;\n\n await Promise.race([Cloud.syncJob.cancel(), Cloud.syncJob.completed]);\n\n cancellingSync.value = false;\n}\n\nuseEvent('auth:logout', () => $modal.value?.close());\n</script>\n","<template>\n <div class=\"relative size-12\">\n <button\n class=\"clickable focus-visible:outline-primary-600 flex size-full rounded-full focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2\"\n type=\"button\"\n :aria-label=\"$td('account.open', 'Open account')\"\n :title=\"$td('account.open', 'Open account')\"\n @click=\"$ui.modal(AccountModal)\"\n >\n <SolidAvatar class=\"size-full\" />\n <div\n v-if=\"accountStatus.loading\"\n class=\"absolute -inset-1 animate-spin rounded-full border-2 border-[currentColor_transparent] text-green-500\"\n />\n </button>\n <div\n class=\"pointer-events-none absolute right-0 bottom-0 size-3 rounded-full border-2 border-white\"\n :class=\"accountStatus.classes\"\n >\n <span class=\"sr-only\">{{ accountStatus.message }}</span>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { Solid, SolidAvatar } from '@aerogel/plugin-solid';\nimport { translateWithDefault } from '@aerogel/core';\n\nimport Cloud from '@aerogel/plugin-local-first/services/Cloud';\nimport { CloudStatus } from '@aerogel/plugin-local-first/services/Cloud.state';\n\nimport AccountModal from './AccountModal.vue';\n\ninterface AccountStatus {\n classes: string;\n message: string;\n loading?: boolean;\n}\n\nconst accountStatus = computed((): AccountStatus => {\n if (Cloud.syncing || Solid.loginOngoing) {\n return {\n loading: true,\n classes: 'bg-green-500 sr-only',\n message: getAccountStatusMessage() ?? '',\n };\n }\n\n if (Solid.error || Cloud.syncError) {\n return {\n classes: 'bg-red-500',\n message: translateWithDefault('account.error', 'There has been an error connecting with your account.'),\n };\n }\n\n if (!Solid.isLoggedIn() || Cloud.dirty || !Cloud.ready) {\n return {\n classes: 'bg-yellow-500',\n message: translateWithDefault(\n 'account.dirty',\n 'There are local changes that haven\\'t been synchronized yet.',\n ),\n };\n }\n\n return {\n classes: 'bg-green-500',\n message: getAccountStatusMessage() ?? '',\n };\n});\n\nfunction getAccountStatusMessage(): string | undefined {\n switch (Cloud.status) {\n case CloudStatus.Syncing:\n return translateWithDefault('cloud.status.syncing', 'Synchronization in progress');\n case CloudStatus.Migrating:\n return translateWithDefault('cloud.status.migrating', 'Migration in progress');\n case CloudStatus.Online:\n return translateWithDefault('cloud.status.online', 'Online');\n case CloudStatus.Disconnected:\n return translateWithDefault('cloud.status.disconnected', 'Disconnected');\n }\n}\n</script>\n","import { App, bootServices } from '@aerogel/core';\nimport type { Plugin } from '@aerogel/core';\n\nimport Cloud from '@aerogel/plugin-local-first/services/Cloud';\nimport DocumentsCache from '@aerogel/plugin-local-first/services/DocumentsCache';\n\nimport settings from './components/settings';\n\nconst services = { $cloud: Cloud };\n\nexport { Cloud };\nexport * from './components';\nexport * from './services/Cloud';\n\nexport type LocalFirstServices = typeof services;\n\nexport default function localFirst(): Plugin {\n return {\n name: '@aerogel/local-first',\n async install(app) {\n settings.forEach((setting) => App.addSetting(setting));\n\n await bootServices(app, {\n ...services,\n $_documentsCache: DocumentsCache,\n });\n },\n };\n}\n\ndeclare module '@aerogel/core' {\n interface Services extends LocalFirstServices {}\n}\n"],"names":["DocumentsCacheService","Service","__publicField","IndexedDBMap","appNamespace","documentUrl","modifiedAt","meta","modifiedAtTime","Events","DocumentsCache","facade","containerRelations","getContainerRegisteredClasses","modelClass","arrayFilter","getContainerRelations","relation","relatedClass","isContainerClass","SolidModel","SolidContainsRelation","getContainedModels","model","models","getRelatedClasses","relatedClasses","instance","getRelatedAppModels","related","isInstanceOf","SolidACLAuthorization","SolidDocument","Metadata","Operation","SolidContainer","isDirtyOrHasDirtyChildren","relationHasDirtyModels","_a","relatedModel","Cloud","required","App","SyncQueue","after","operationOrPromise","promise","arrayRemove","children","isContainer","child","SyncQueue$1","remoteClasses","localClasses","cleanRemoteModelClone","remoteModel","relatedModels","fixRemoteModelClone","operations","operation","PropertyOperation","createRemoteModel","localModel","isRegisteredModelClass","trackModelsCollection","requireUrlParentDirectory","collection","trackSoukaiModelsCollection","updateRemoteModel","ignoreModelUpdates","modelUpdates","objectWithout","clearLocalModelUpdates","syncedModelUrls","documentsWithErrors","localModelUpdates","syncedModelUrlsArray","url","count","urlRoute","modelUrl","cloneLocalModel","options","localModelClasses","constructors","localClass","getRemoteClass","tap","cloneRemoteModel","remoteModelClasses","remoteClass","getLocalClass","completeRemoteModels","localModels","remoteModels","RemoteTombstone","Tombstone","remoteModelUrls","missingModelDocumentUrls","tombstones","documentModels","documentOperations","updatedAt","_b","getLocalModel","getLocalModels","getTrackedModels","getSchemaMigrations","clearSchemaMigrations","getSchemaMigration","makeRemoteClass","getRemoteContainersCollection","path","rootStorage","Solid","containedClass","urlResolveDirectory","getRemoteModel","isRegisteredModel","registeredModel","isRemoteModel","isLocalModel","registeredModelClass","LocalClass","withLocalHistoryConfig","RemoteClass","attributes","exists","schema","bootModels","fail","Backup","Job","local","remote","engine","requireEngine","collections","documents","id","document","ignoreModelsCollection","key","value","lazy","getter","result","LoadsChildren","relationModels","arrayFrom","map","documentUrlChunks","arrayChunk","statusChildren","statusChildrenMap","documentUrls","documentChildren","documentTombstones","childrenArray","onDocumentError","onDocumentRead","relationInstance","relatedLocalModels","relatedLocalModel","readDocument","documentModel","error","DocumentNotFound","typeIndexes","LoadsTypeIndex","user","TracksLocalModels","BaseJob","Migrate","mixed","status","job","childrenStatus","objectMap","modelStatuses","typeIndex","modelStatus","registeredClasses","registration","instanceContainer","migratedModel","migratedOperation","childStatus","isRootStatus","Sync","updateDocumentDate","headers","fallbackDate","date","clearListener","metadata","typedNavigator","Errors","lock","round","remoteModelsArray","index","pullStatus","registrations","container","processedContainerUrls","registeredModels","registeredChildren","childrenClass","rdfsClasses","rdfsClass","match","containerUrls","containerUrl","RemoteSolidContainer","wasDirty","childrenStatuses","synchronizedModelUrls","deletedModels","dirtyRemoteModels","processedModels","remoteRelatedModels","localRelatedModel","localRelation","remoteRelation","newLocalModelUrls","newRemoteModelUrls","MalformedSolidDocumentError","InvalidModelAttributes","primaryKey","requireBootedModel","toString","CloudStatus","defineServiceState","state","replaceExisting","migrationJob","total","ready","translateWithDefault","CloudService","Semaphore","callback","resolve","onReady","modelUrlMappings","config","isArray","start","dispatch","isTesting","listener","removeListeners","removeListener","registered","existingCollection","trackModels","authenticator","watchEffect","urls","dirtyLocalModels","containedModel","localCollection","remoteCollection","hasLocationQueryParameter","parseBoolean","getLocationQueryParameter","getBootedModels","isSolidModel","purgeData","UI","AccountLoginModal","Storage","settings","defineSettings","PurgeData","$modal","useTemplateRef","cancellingSync","ref","pollingText","computed","errorDescription","showErrorDetails","cancelSync","useEvent","accountStatus","getAccountStatusMessage","services","localFirst","app","setting","bootServices"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aerogel/plugin-local-first",
|
|
3
|
+
"version": "0.0.0-next.004d5deedf15bedf609a660bfd4543d3c0df9d9d",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"exports": {
|
|
7
|
+
"types": "./dist/aerogel-plugin-local-first.d.ts",
|
|
8
|
+
"style": "./src/index.css",
|
|
9
|
+
"default": "./dist/aerogel-plugin-local-first.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"src",
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"author": "Noel De Martin",
|
|
17
|
+
"repository": "github:NoelDeMartin/aerogel",
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "vite build",
|
|
20
|
+
"lint": "noeldemartin-lint src",
|
|
21
|
+
"test": "vitest --run",
|
|
22
|
+
"test:ci": "vitest --run --reporter verbose",
|
|
23
|
+
"verify": "noeldemartin-verify"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@aerogel/core": "*",
|
|
27
|
+
"@aerogel/plugin-solid": "*",
|
|
28
|
+
"@aerogel/plugin-soukai": "*",
|
|
29
|
+
"soukai": "*",
|
|
30
|
+
"soukai-solid": "*"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@noeldemartin/solid-utils": "0.6.0-next.c7addc0a638eedd08392f2f42039946a876fe146",
|
|
34
|
+
"@noeldemartin/utils": "0.7.0-next.31cf84b4b57092d146528f27579439783aca71bb",
|
|
35
|
+
"idb": "^8.0.2"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@aerogel/core": "*",
|
|
39
|
+
"@aerogel/plugin-solid": "*",
|
|
40
|
+
"@aerogel/plugin-soukai": "*",
|
|
41
|
+
"fake-indexeddb": "^6.0.0",
|
|
42
|
+
"soukai": "*",
|
|
43
|
+
"soukai-solid": "*"
|
|
44
|
+
},
|
|
45
|
+
"eslintConfig": {
|
|
46
|
+
"extends": [
|
|
47
|
+
"@noeldemartin/eslint-config-vue"
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="relative size-12">
|
|
3
|
+
<button
|
|
4
|
+
class="clickable focus-visible:outline-primary-600 flex size-full rounded-full focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2"
|
|
5
|
+
type="button"
|
|
6
|
+
:aria-label="$td('account.open', 'Open account')"
|
|
7
|
+
:title="$td('account.open', 'Open account')"
|
|
8
|
+
@click="$ui.modal(AccountModal)"
|
|
9
|
+
>
|
|
10
|
+
<SolidAvatar class="size-full" />
|
|
11
|
+
<div
|
|
12
|
+
v-if="accountStatus.loading"
|
|
13
|
+
class="absolute -inset-1 animate-spin rounded-full border-2 border-[currentColor_transparent] text-green-500"
|
|
14
|
+
/>
|
|
15
|
+
</button>
|
|
16
|
+
<div
|
|
17
|
+
class="pointer-events-none absolute right-0 bottom-0 size-3 rounded-full border-2 border-white"
|
|
18
|
+
:class="accountStatus.classes"
|
|
19
|
+
>
|
|
20
|
+
<span class="sr-only">{{ accountStatus.message }}</span>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script setup lang="ts">
|
|
26
|
+
import { computed } from 'vue';
|
|
27
|
+
import { Solid, SolidAvatar } from '@aerogel/plugin-solid';
|
|
28
|
+
import { translateWithDefault } from '@aerogel/core';
|
|
29
|
+
|
|
30
|
+
import Cloud from '@aerogel/plugin-local-first/services/Cloud';
|
|
31
|
+
import { CloudStatus } from '@aerogel/plugin-local-first/services/Cloud.state';
|
|
32
|
+
|
|
33
|
+
import AccountModal from './AccountModal.vue';
|
|
34
|
+
|
|
35
|
+
interface AccountStatus {
|
|
36
|
+
classes: string;
|
|
37
|
+
message: string;
|
|
38
|
+
loading?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const accountStatus = computed((): AccountStatus => {
|
|
42
|
+
if (Cloud.syncing || Solid.loginOngoing) {
|
|
43
|
+
return {
|
|
44
|
+
loading: true,
|
|
45
|
+
classes: 'bg-green-500 sr-only',
|
|
46
|
+
message: getAccountStatusMessage() ?? '',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (Solid.error || Cloud.syncError) {
|
|
51
|
+
return {
|
|
52
|
+
classes: 'bg-red-500',
|
|
53
|
+
message: translateWithDefault('account.error', 'There has been an error connecting with your account.'),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!Solid.isLoggedIn() || Cloud.dirty || !Cloud.ready) {
|
|
58
|
+
return {
|
|
59
|
+
classes: 'bg-yellow-500',
|
|
60
|
+
message: translateWithDefault(
|
|
61
|
+
'account.dirty',
|
|
62
|
+
'There are local changes that haven\'t been synchronized yet.',
|
|
63
|
+
),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
classes: 'bg-green-500',
|
|
69
|
+
message: getAccountStatusMessage() ?? '',
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
function getAccountStatusMessage(): string | undefined {
|
|
74
|
+
switch (Cloud.status) {
|
|
75
|
+
case CloudStatus.Syncing:
|
|
76
|
+
return translateWithDefault('cloud.status.syncing', 'Synchronization in progress');
|
|
77
|
+
case CloudStatus.Migrating:
|
|
78
|
+
return translateWithDefault('cloud.status.migrating', 'Migration in progress');
|
|
79
|
+
case CloudStatus.Online:
|
|
80
|
+
return translateWithDefault('cloud.status.online', 'Online');
|
|
81
|
+
case CloudStatus.Disconnected:
|
|
82
|
+
return translateWithDefault('cloud.status.disconnected', 'Disconnected');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
</script>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<DropdownMenu
|
|
3
|
+
align="start"
|
|
4
|
+
:options="[
|
|
5
|
+
{ label: $td('user.logIn', 'Connect account'), click: () => $ui.modal(AccountLoginModal) },
|
|
6
|
+
{ label: $td('user.settings', 'Settings'), click: () => $ui.modal(SettingsModal) },
|
|
7
|
+
]"
|
|
8
|
+
>
|
|
9
|
+
<Button
|
|
10
|
+
size="icon"
|
|
11
|
+
variant="ghost"
|
|
12
|
+
:aria-label="$td('user.menu', 'Configuration')"
|
|
13
|
+
:title="$td('user.menu', 'Configuration')"
|
|
14
|
+
>
|
|
15
|
+
<IconCog class="size-5" />
|
|
16
|
+
</Button>
|
|
17
|
+
</DropdownMenu>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script setup lang="ts">
|
|
21
|
+
import IconCog from '~icons/zondicons/cog';
|
|
22
|
+
|
|
23
|
+
import { Button, DropdownMenu, SettingsModal } from '@aerogel/core';
|
|
24
|
+
|
|
25
|
+
import AccountLoginModal from './AccountLoginModal.vue';
|
|
26
|
+
</script>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Modal :title="$td('cloud.logIn.title', 'Connect account')">
|
|
3
|
+
<Markdown
|
|
4
|
+
lang-key="cloud.logIn.info"
|
|
5
|
+
lang-default="Log in to your [Solid account](https://solidproject.org) to keep data safe across devices."
|
|
6
|
+
/>
|
|
7
|
+
<Link
|
|
8
|
+
class="text-sm"
|
|
9
|
+
@click="
|
|
10
|
+
$ui.alert(
|
|
11
|
+
$td('cloud.logIn.learnMore', 'What is Solid?'),
|
|
12
|
+
$td(
|
|
13
|
+
'cloud.logIn.learnMoreMessage',
|
|
14
|
+
'Solid is a decentralized storage protocol built on top of web standards. ' +
|
|
15
|
+
'If you want to use this app across devices, ' +
|
|
16
|
+
'you can use Solid to keep changes in sync. ' +
|
|
17
|
+
'Even if you use it in a single device, ' +
|
|
18
|
+
'this will also keep your data secure in case your device is lost.\n\n' +
|
|
19
|
+
'In any case, Focus works 100% offline and you can connect your Solid POD later on. ' +
|
|
20
|
+
'If you\'ve never heard of Solid and you\'re just trying things out, ' +
|
|
21
|
+
'you can keep using it without an account.\n\n' +
|
|
22
|
+
'[Learn more](https://solidproject.org)'
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
"
|
|
26
|
+
>
|
|
27
|
+
{{ $td('cloud.logIn.learnMore', 'What is Solid?') }}
|
|
28
|
+
</Link>
|
|
29
|
+
<SolidLogin no-loading class="mt-4" />
|
|
30
|
+
</Modal>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<script setup lang="ts">
|
|
34
|
+
import { Link, Markdown, Modal } from '@aerogel/core';
|
|
35
|
+
import { SolidLogin } from '@aerogel/plugin-solid';
|
|
36
|
+
</script>
|