Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/0dataapp/0datawrap
Unified JavaScript API for Fission + remoteStorage.
https://github.com/0dataapp/0datawrap
0data fission ownyourdata remotestorage solid unhosted
Last synced: 2 days ago
JSON representation
Unified JavaScript API for Fission + remoteStorage.
- Host: GitHub
- URL: https://github.com/0dataapp/0datawrap
- Owner: 0dataapp
- License: other
- Created: 2021-02-16T13:44:22.000Z (over 3 years ago)
- Default Branch: master
- Last Pushed: 2024-06-16T21:57:36.000Z (5 months ago)
- Last Synced: 2024-08-03T13:14:42.824Z (3 months ago)
- Topics: 0data, fission, ownyourdata, remotestorage, solid, unhosted
- Language: JavaScript
- Homepage: https://0data.app
- Size: 143 KB
- Stars: 20
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
- awesome-0data - Zero Data Wrap
README
# [Zero Data](https://0data.app) Wrap
_Unified JavaScript API for [Fission](https://guide.fission.codes/developers/webnative) + [remoteStorage](https://github.com/remotestorage/remotestorage.js)._
# Comparisons
- [remotestorage.js](https://community.remotestorage.io/t/659)
- [Webnative SDK](https://talk.fission.codes/t/1587)# Long names…
Yes, it's long and verbose and how I do things generally, but ideally your final code looks like this:
```javascript
// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.json
await api.alfa.cars.wash({
id: 'batmobile',
});
```# API Guide
## Setup
```javascript
const api = await zerodatawrap.ZDRWrap({// include then pass directly
ZDRParamLibrary: RemoteStorage, // or webnative// read/write permissions
ZDRParamScopes: [{// code-level identifier
ZDRScopeKey: 'alfa',// top-level storage directory
ZDRScopeDirectory: 'bravo',}],
});// write `{"foo":"bar"}` to /bravo/charlie.json
await api.alfa.ZDRStorageWriteObject('charlie.json', {
foo: 'bar',
});
```### ZDRWrap
| param | type | notes |
|-------|---------|-------|
| ZDRParamLibrary
**Required** | pass `RemoteStorage` or `webnative` or an object conforming to `ZDRClient` | |
| ZDRParamScopes
**Required** | array of `ZDRScope` objects | |
| ZDRParamDispatchError | function | called on network or sync errors |
| ZDRParamDispatchConnected | function | called if linked to a cloud account |
| ZDRParamDispatchOnline | function | called when network is online |
| ZDRParamDispatchOffline | function | called when network is offline |### ZDRScope
| param | type | notes |
|-------|---------|-------|
| ZDRScopeKey
**Required** | string, non-empty, trimmed | convenience accessor for code only |
| ZDRScopeDirectory
**Required** | string, non-empty, trimmed, no slashes | top-level directory for claiming read/write access |
| ZDRScopeCreatorDirectory | string, non-empty, trimmed | if Fission, sets `permissions.app` instead of `permissions.fs` |
| ZDRScopeSchemas | array of `ZDRSchema` objects | defines model helpers |
| ZDRScopeIsPublic | boolean | use public directory on read/write |## Storage
### ZDRStorageWriteObject(path, object)
Call `JSON.stringify`; write to storage.
Returns input object.
### ZDRStorageWriteFile(path, data, mimetype)
*`mimetype` used by remoteStorage.*
Write to storage.
Returns input.
### ZDRStorageReadObject(path)
Read from storage; call `JSON.parse`.
Returns object.
### ZDRStorageReadFile(path)
Read from storage.
Returns data.
### ZDRStorageListingObjects(path)
Read from storage in path directory (non-recursive); group by path.
Returns key/value object.
### ZDRStoragePaths(path)
Fetch paths (non-recursive).
Returns array of paths.
### ZDRStoragePathsRecursive(path)
Fetch paths recursively.
Returns flat array of paths.
### ZDRStorageDeleteFile(path)
Delete from storage.
Returns null.
### ZDRStorageDeleteFolderRecursive(path)
Delete folder and subcontents recursively from storage.
Returns input.
## Cloud
### ZDRCloudConnect(address)
Start authorization process corresponding to `ZDRParamLibrary`.
Returns undefined.
### ZDRCloudReconnect()
Retry authorization process in case of expiry or denied access.
Returns undefined.
### ZDRCloudDisconnect()
Log out.
Returns undefined.
## Model (optional)
```javascript
const api = zerodatawrap.ZDRWrap({// …
ZDRParamScopes: [{
// …
// map schemas to paths
ZDRScopeSchemas: [{// code-level identifier
ZDRSchemaKey: 'cars',// path for a given object
ZDRSchemaPath (object) {
return `cars/${ object.id }.json`;
},// object information for a given path
ZDRSchemaStub (path) {
return {
id: path.split('/').pop().split('.json').shift(),
};
},}],
// …
}],
// …});
// write `{"id":"batmobile"}` to /bravo/cars/batmobile.json
await api.alfa.cars.ZDRModelWriteObject({
id: 'batmobile',
});
```### ZDRSchema
| param | type | notes |
|-------|---------|-------|
| ZDRSchemaKey
**Required** | string, non-empty, trimmed | convenience accessor for code only |
| ZDRSchemaPath
**Required** | function | constructs the path for a given object |
| ZDRSchemaStub
**Required** | function | constructs object information for a given path, used for filtering paths in recursion and routing sync events |
| ZDRSchemaMethods | object | defines methods to be accessed from the api interface (bound to `this`) |
| ZDRSchemaDispatchValidate | function | called before `ZDRModelWriteObject` |
| ZDRSchemaDispatchSyncCreate | function | called on remote create *remoteStorage only* |
| ZDRSchemaDispatchSyncUpdate | function | called on remote update *remoteStorage only* |
| ZDRSchemaDispatchSyncDelete | function | called on remote delete *remoteStorage only* |
| ZDRSchemaDispatchSyncConflict | function | called on remote conflict *remoteStorage only*
**Note: this passes the remoteStorage change event directly** |### Specify a validation function
```javascript
const api = zerodatawrap.ZDRWrap({// …
ZDRParamScopes: [{
// …
ZDRScopeSchemas: [{
// …
// truthy values cause a promise rejection
ZDRSchemaDispatchValidate (object) {
if (typeof object.id !== 'string') {
return {
not: 'so fast',
};
}
},// …
}],
// …
}],
// …
});
// rejects
try {
await api.alfa.cars.ZDRModelWriteObject({
id: 123,
});
} catch (truthy) {
console.log(truthy.not); // so fast
}
```### Specify custom methods
```javascript
const api = zerodatawrap.ZDRWrap({// …
ZDRParamScopes: [{
// …
ZDRScopeSchemas: [{
// …
// logic to be done on save
ZDRSchemaMethods: {clean (car) {
return this.alfa.cars.ZDRModelWriteObject(Object.assign(car, {
clean: true,
washed: new Date(),
}));
},},
// …
}],
// …
}],
// …
});
// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.json
await api.alfa.cars.clean({
id: 'batmobile',
});
```### Receive object sync notifications
```javascript
const api = zerodatawrap.ZDRWrap({// …
ZDRParamScopes: [{
// …
ZDRScopeSchemas: [{
// …
// update the interface for remote changes
ZDRSchemaDispatchSyncCreate (object) {
console.log('create', object);
},
ZDRSchemaDispatchSyncUpdate (object) {
console.log('update', object);
},
ZDRSchemaDispatchSyncDelete (object) {
console.log('delete', object);
},// handle conflict
ZDRSchemaDispatchSyncConflict (event) {
console.log('conflict', event);
},// …
}],
// …
}],
// …
});
```### ZDRModelPath(object)
Returns object path via `ZDRSchemaPath`.
### ZDRModelWriteObject(object)
Validate with `ZDRSchemaDispatchValidate`, reject if truthy; write object to path from `ZDRModelPath`.
Returns input.
### ZDRModelListObjects()
Read all objects recursively (where paths conform to logic in `ZDRSchema`).
Returns array of objects.
### ZDRModelDeleteObject(object)
Delete object from storage.
Returns input.
## Multiple protocols
When supporting multiple protocols, the library can help track which one was selected.
```javascript
const api = await zerodatawrap.ZDRWrap({ZDRParamLibrary: (function() {
// get the selected protocol, default to `ZDRProtocolCustom`
const selected = zerodatawrap.ZDRPreferenceProtocol(zerodatawrap.ZDRProtocolCustom());if (selected === zerodatawrap.ZDRProtocolRemoteStorage()) {
return RemoteStorage;
}if (selected === zerodatawrap.ZDRProtocolFission()) {
return webnative;
}return {
ZDRClientWriteFile (path, data) {
console.log('custom protocol write', [...arguments]);
},
ZDRClientReadFile (path) {
console.log('custom protocol read', [...arguments]);
},
ZDRClientListObjects (path) {
console.log('custom protocol list objects', [...arguments]);
},
ZDRClientDelete (path) {
console.log('custom protocol delete', [...arguments]);
},
};
})(),// …
});
```Move from one protocol to another by generating APIs from preferences:
```javascript
if (zerodatawrap.ZDRPreferenceProtocolMigrate()) {// generate apis from protocol
const wrap = function (protocol) {
return zerodatawrap.ZDRWrap({// …
});
};
const source = await wrap(zerodatawrap.ZDRPreferenceProtocolMigrate());
const destination = await wrap(zerodatawrap.ZDRPreferenceProtocol());
// get all objects (this is simplified, should be recursive)
await Promise.all(Object.entries(await source.App.ZDRStorageListingObjects('')).map(async function ([key, value]) {
// write to destination
await destination.App.ZDRStorageWriteObject(key, value);
// delete from source
await source.App.ZDRStorageDeleteFile(key);
}));// clear migrate preference to avoid repeating
zerodatawrap.ZDRPreferenceProtocolMigrateClear();// call disconnect to do any other cleanup
source.ZDRCloudDisconnect();
};
```### ZDRClient (for custom protocol only)
| function | notes |
|-------|---------|
| ZDRClientWriteFile
**Required** | called by `ZDRStorageWriteFile` |
| ZDRClientReadFile
**Required** | called by `ZDRStorageReadFile` |
| ZDRClientListObjects
**Required** | called by `ZDRStorageListingObjects` |
| ZDRClientDelete
**Required** | called by `ZDRStorageDeleteFile` |
| ZDRClientPrepare | called before returning wrapper |
| ZDRClientConnect | called by `ZDRCloudConnect` |
| ZDRClientReconnect | called by `ZDRCloudReconnect` |
| ZDRClientDisconnect | called by `ZDRCloudDisconnect` |### ZDRProtocolRemoteStorage()
Returns string.
### ZDRProtocolFission()
Returns string.
### ZDRProtocolCustom()
Returns string.
### ZDRPreferenceProtocol(protocol)
Stores input as the protocol preference if none is set.
Returns the protocol preference.
### ZDRPreferenceProtocolClear()
Clears the protocol preference.
Returns null.
### ZDRPreferenceProtocolConnect(protocol)
Sets the protocol preference as 'to be migrated' if connecting to a different protocol.
Returns input.
### ZDRPreferenceProtocolMigrate()
Returns the 'to be migrated' protocol if set.
### ZDRPreferenceProtocolMigrateClear()
Clears the 'to be migrated' protocol.
Returns input object.
## ❤️
Help me keep creating projects that are public, accessible for free, and open-source.
## License
The code is released under a [Hippocratic License](https://firstdonoharm.dev), modified to exclude its use for surveillance capitalism and also to require large for-profit entities to purchase a paid license.
## Questions
Feel free to reach out on [Mastodon](https://rosano.ca/mastodon) or [Twitter](https://rosano.ca/twitter).