Repository files navigation

Project logo

Unified JavaScript API for Fission + remoteStorage.

Comparisons

Long names…

Yes, it's long and verbose and how I do things generally, but ideally your final code looks like this:

// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.wash({id: 'batmobile',});

API Guide

Setup

constapi=awaitzerodatawrap.ZDRWrap({// include then pass directlyZDRParamLibrary: RemoteStorage,// or webnative// read/write permissionsZDRParamScopes: [{// code-level identifierZDRScopeKey: 'alfa',// top-level storage directoryZDRScopeDirectory: 'bravo',}],});// write `{"foo":"bar"}` to /bravo/charlie.jsonawaitapi.alfa.ZDRStorageWriteObject('charlie.json',{foo: 'bar',});

ZDRWrap

paramtypenotes
ZDRParamLibrary
Required
pass RemoteStorage or webnative or an object conforming to ZDRClient
ZDRParamScopes
Required
array of ZDRScope objects
ZDRParamDispatchErrorfunctioncalled on network or sync errors
ZDRParamDispatchConnectedfunctioncalled if linked to a cloud account
ZDRParamDispatchOnlinefunctioncalled when network is online
ZDRParamDispatchOfflinefunctioncalled when network is offline

ZDRScope

paramtypenotes
ZDRScopeKey
Required
string, non-empty, trimmedconvenience accessor for code only
ZDRScopeDirectory
Required
string, non-empty, trimmed, no slashestop-level directory for claiming read/write access
ZDRScopeCreatorDirectorystring, non-empty, trimmedif Fission, sets permissions.app instead of permissions.fs
ZDRScopeSchemasarray of ZDRSchema objectsdefines model helpers
ZDRScopeIsPublicbooleanuse 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)

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …// map schemas to pathsZDRScopeSchemas: [{// code-level identifierZDRSchemaKey: 'cars',// path for a given objectZDRSchemaPath(object){return`cars/${object.id}.json`;},// object information for a given pathZDRSchemaStub(path){return{id: path.split('/').pop().split('.json').shift(),};},}],// …}],// …});// write `{"id":"batmobile"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.ZDRModelWriteObject({id: 'batmobile',});

ZDRSchema

paramtypenotes
ZDRSchemaKey
Required
string, non-empty, trimmedconvenience accessor for code only
ZDRSchemaPath
Required
functionconstructs the path for a given object
ZDRSchemaStub
Required
functionconstructs object information for a given path, used for filtering paths in recursion and routing sync events
ZDRSchemaMethodsobjectdefines methods to be accessed from the api interface (bound to this)
ZDRSchemaDispatchValidatefunctioncalled before ZDRModelWriteObject
ZDRSchemaDispatchSyncCreatefunctioncalled on remote create remoteStorage only
ZDRSchemaDispatchSyncUpdatefunctioncalled on remote update remoteStorage only
ZDRSchemaDispatchSyncDeletefunctioncalled on remote delete remoteStorage only
ZDRSchemaDispatchSyncConflictfunctioncalled on remote conflict remoteStorage only
Note: this passes the remoteStorage change event directly

Specify a validation function

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// truthy values cause a promise rejectionZDRSchemaDispatchValidate(object){if(typeofobject.id!=='string'){return{not: 'so fast',};}},// …}],// …}],// …});// rejectstry{awaitapi.alfa.cars.ZDRModelWriteObject({id: 123,});}catch(truthy){console.log(truthy.not);// so fast}

Specify custom methods

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// logic to be done on saveZDRSchemaMethods: {clean(car){returnthis.alfa.cars.ZDRModelWriteObject(Object.assign(car,{clean: true,washed: newDate(),}));},},// …}],// …}],// …});// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.clean({id: 'batmobile',});

Receive object sync notifications

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// update the interface for remote changesZDRSchemaDispatchSyncCreate(object){console.log('create',object);},ZDRSchemaDispatchSyncUpdate(object){console.log('update',object);},ZDRSchemaDispatchSyncDelete(object){console.log('delete',object);},// handle conflictZDRSchemaDispatchSyncConflict(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.

constapi=awaitzerodatawrap.ZDRWrap({ZDRParamLibrary: (function(){// get the selected protocol, default to `ZDRProtocolCustom`constselected=zerodatawrap.ZDRPreferenceProtocol(zerodatawrap.ZDRProtocolCustom());if(selected===zerodatawrap.ZDRProtocolRemoteStorage()){returnRemoteStorage;}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:

if(zerodatawrap.ZDRPreferenceProtocolMigrate()){// generate apis from protocolconstwrap=function(protocol){returnzerodatawrap.ZDRWrap({// …});};constsource=awaitwrap(zerodatawrap.ZDRPreferenceProtocolMigrate());constdestination=awaitwrap(zerodatawrap.ZDRPreferenceProtocol());// get all objects (this is simplified, should be recursive)awaitPromise.all(Object.entries(awaitsource.App.ZDRStorageListingObjects('')).map(asyncfunction([key,value]){// write to destinationawaitdestination.App.ZDRStorageWriteObject(key,value);// delete from sourceawaitsource.App.ZDRStorageDeleteFile(key);}));// clear migrate preference to avoid repeatingzerodatawrap.ZDRPreferenceProtocolMigrateClear();// call disconnect to do any other cleanupsource.ZDRCloudDisconnect();};

ZDRClient (for custom protocol only)

functionnotes
ZDRClientWriteFile
Required
called by ZDRStorageWriteFile
ZDRClientReadFile
Required
called by ZDRStorageReadFile
ZDRClientListObjects
Required
called by ZDRStorageListingObjects
ZDRClientDelete
Required
called by ZDRStorageDeleteFile
ZDRClientPreparecalled before returning wrapper
ZDRClientConnectcalled by ZDRCloudConnect
ZDRClientReconnectcalled by ZDRCloudReconnect
ZDRClientDisconnectcalled 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.

Send a gift

License

The code is released under a Hippocratic License, 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 or Bluesky.

About

Unified JavaScript API for Fission + remoteStorage.

Topics

Resources

Stars

21 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Project logo

Unified JavaScript API for Fission + remoteStorage.

Comparisons

Long names…

Yes, it's long and verbose and how I do things generally, but ideally your final code looks like this:

// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.wash({id: 'batmobile',});

API Guide

Setup

constapi=awaitzerodatawrap.ZDRWrap({// include then pass directlyZDRParamLibrary: RemoteStorage,// or webnative// read/write permissionsZDRParamScopes: [{// code-level identifierZDRScopeKey: 'alfa',// top-level storage directoryZDRScopeDirectory: 'bravo',}],});// write `{"foo":"bar"}` to /bravo/charlie.jsonawaitapi.alfa.ZDRStorageWriteObject('charlie.json',{foo: 'bar',});

ZDRWrap

paramtypenotes
ZDRParamLibrary
Required
pass RemoteStorage or webnative or an object conforming to ZDRClient
ZDRParamScopes
Required
array of ZDRScope objects
ZDRParamDispatchErrorfunctioncalled on network or sync errors
ZDRParamDispatchConnectedfunctioncalled if linked to a cloud account
ZDRParamDispatchOnlinefunctioncalled when network is online
ZDRParamDispatchOfflinefunctioncalled when network is offline

ZDRScope

paramtypenotes
ZDRScopeKey
Required
string, non-empty, trimmedconvenience accessor for code only
ZDRScopeDirectory
Required
string, non-empty, trimmed, no slashestop-level directory for claiming read/write access
ZDRScopeCreatorDirectorystring, non-empty, trimmedif Fission, sets permissions.app instead of permissions.fs
ZDRScopeSchemasarray of ZDRSchema objectsdefines model helpers
ZDRScopeIsPublicbooleanuse 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)

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …// map schemas to pathsZDRScopeSchemas: [{// code-level identifierZDRSchemaKey: 'cars',// path for a given objectZDRSchemaPath(object){return`cars/${object.id}.json`;},// object information for a given pathZDRSchemaStub(path){return{id: path.split('/').pop().split('.json').shift(),};},}],// …}],// …});// write `{"id":"batmobile"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.ZDRModelWriteObject({id: 'batmobile',});

ZDRSchema

paramtypenotes
ZDRSchemaKey
Required
string, non-empty, trimmedconvenience accessor for code only
ZDRSchemaPath
Required
functionconstructs the path for a given object
ZDRSchemaStub
Required
functionconstructs object information for a given path, used for filtering paths in recursion and routing sync events
ZDRSchemaMethodsobjectdefines methods to be accessed from the api interface (bound to this)
ZDRSchemaDispatchValidatefunctioncalled before ZDRModelWriteObject
ZDRSchemaDispatchSyncCreatefunctioncalled on remote create remoteStorage only
ZDRSchemaDispatchSyncUpdatefunctioncalled on remote update remoteStorage only
ZDRSchemaDispatchSyncDeletefunctioncalled on remote delete remoteStorage only
ZDRSchemaDispatchSyncConflictfunctioncalled on remote conflict remoteStorage only
Note: this passes the remoteStorage change event directly

Specify a validation function

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// truthy values cause a promise rejectionZDRSchemaDispatchValidate(object){if(typeofobject.id!=='string'){return{not: 'so fast',};}},// …}],// …}],// …});// rejectstry{awaitapi.alfa.cars.ZDRModelWriteObject({id: 123,});}catch(truthy){console.log(truthy.not);// so fast}

Specify custom methods

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// logic to be done on saveZDRSchemaMethods: {clean(car){returnthis.alfa.cars.ZDRModelWriteObject(Object.assign(car,{clean: true,washed: newDate(),}));},},// …}],// …}],// …});// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.clean({id: 'batmobile',});

Receive object sync notifications

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// update the interface for remote changesZDRSchemaDispatchSyncCreate(object){console.log('create',object);},ZDRSchemaDispatchSyncUpdate(object){console.log('update',object);},ZDRSchemaDispatchSyncDelete(object){console.log('delete',object);},// handle conflictZDRSchemaDispatchSyncConflict(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.

constapi=awaitzerodatawrap.ZDRWrap({ZDRParamLibrary: (function(){// get the selected protocol, default to `ZDRProtocolCustom`constselected=zerodatawrap.ZDRPreferenceProtocol(zerodatawrap.ZDRProtocolCustom());if(selected===zerodatawrap.ZDRProtocolRemoteStorage()){returnRemoteStorage;}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:

if(zerodatawrap.ZDRPreferenceProtocolMigrate()){// generate apis from protocolconstwrap=function(protocol){returnzerodatawrap.ZDRWrap({// …});};constsource=awaitwrap(zerodatawrap.ZDRPreferenceProtocolMigrate());constdestination=awaitwrap(zerodatawrap.ZDRPreferenceProtocol());// get all objects (this is simplified, should be recursive)awaitPromise.all(Object.entries(awaitsource.App.ZDRStorageListingObjects('')).map(asyncfunction([key,value]){// write to destinationawaitdestination.App.ZDRStorageWriteObject(key,value);// delete from sourceawaitsource.App.ZDRStorageDeleteFile(key);}));// clear migrate preference to avoid repeatingzerodatawrap.ZDRPreferenceProtocolMigrateClear();// call disconnect to do any other cleanupsource.ZDRCloudDisconnect();};

ZDRClient (for custom protocol only)

functionnotes
ZDRClientWriteFile
Required
called by ZDRStorageWriteFile
ZDRClientReadFile
Required
called by ZDRStorageReadFile
ZDRClientListObjects
Required
called by ZDRStorageListingObjects
ZDRClientDelete
Required
called by ZDRStorageDeleteFile
ZDRClientPreparecalled before returning wrapper
ZDRClientConnectcalled by ZDRCloudConnect
ZDRClientReconnectcalled by ZDRCloudReconnect
ZDRClientDisconnectcalled 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.

Send a gift

License

The code is released under a Hippocratic License, 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 or Bluesky.

About

Unified JavaScript API for Fission + remoteStorage.

Topics

Resources

Stars

21 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Project logo

Unified JavaScript API for Fission + remoteStorage.

Comparisons

Long names…

Yes, it's long and verbose and how I do things generally, but ideally your final code looks like this:

// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.wash({id: 'batmobile',});

API Guide

Setup

constapi=awaitzerodatawrap.ZDRWrap({// include then pass directlyZDRParamLibrary: RemoteStorage,// or webnative// read/write permissionsZDRParamScopes: [{// code-level identifierZDRScopeKey: 'alfa',// top-level storage directoryZDRScopeDirectory: 'bravo',}],});// write `{"foo":"bar"}` to /bravo/charlie.jsonawaitapi.alfa.ZDRStorageWriteObject('charlie.json',{foo: 'bar',});

ZDRWrap

paramtypenotes
ZDRParamLibrary
Required
pass RemoteStorage or webnative or an object conforming to ZDRClient
ZDRParamScopes
Required
array of ZDRScope objects
ZDRParamDispatchErrorfunctioncalled on network or sync errors
ZDRParamDispatchConnectedfunctioncalled if linked to a cloud account
ZDRParamDispatchOnlinefunctioncalled when network is online
ZDRParamDispatchOfflinefunctioncalled when network is offline

ZDRScope

paramtypenotes
ZDRScopeKey
Required
string, non-empty, trimmedconvenience accessor for code only
ZDRScopeDirectory
Required
string, non-empty, trimmed, no slashestop-level directory for claiming read/write access
ZDRScopeCreatorDirectorystring, non-empty, trimmedif Fission, sets permissions.app instead of permissions.fs
ZDRScopeSchemasarray of ZDRSchema objectsdefines model helpers
ZDRScopeIsPublicbooleanuse 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)

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …// map schemas to pathsZDRScopeSchemas: [{// code-level identifierZDRSchemaKey: 'cars',// path for a given objectZDRSchemaPath(object){return`cars/${object.id}.json`;},// object information for a given pathZDRSchemaStub(path){return{id: path.split('/').pop().split('.json').shift(),};},}],// …}],// …});// write `{"id":"batmobile"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.ZDRModelWriteObject({id: 'batmobile',});

ZDRSchema

paramtypenotes
ZDRSchemaKey
Required
string, non-empty, trimmedconvenience accessor for code only
ZDRSchemaPath
Required
functionconstructs the path for a given object
ZDRSchemaStub
Required
functionconstructs object information for a given path, used for filtering paths in recursion and routing sync events
ZDRSchemaMethodsobjectdefines methods to be accessed from the api interface (bound to this)
ZDRSchemaDispatchValidatefunctioncalled before ZDRModelWriteObject
ZDRSchemaDispatchSyncCreatefunctioncalled on remote create remoteStorage only
ZDRSchemaDispatchSyncUpdatefunctioncalled on remote update remoteStorage only
ZDRSchemaDispatchSyncDeletefunctioncalled on remote delete remoteStorage only
ZDRSchemaDispatchSyncConflictfunctioncalled on remote conflict remoteStorage only
Note: this passes the remoteStorage change event directly

Specify a validation function

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// truthy values cause a promise rejectionZDRSchemaDispatchValidate(object){if(typeofobject.id!=='string'){return{not: 'so fast',};}},// …}],// …}],// …});// rejectstry{awaitapi.alfa.cars.ZDRModelWriteObject({id: 123,});}catch(truthy){console.log(truthy.not);// so fast}

Specify custom methods

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// logic to be done on saveZDRSchemaMethods: {clean(car){returnthis.alfa.cars.ZDRModelWriteObject(Object.assign(car,{clean: true,washed: newDate(),}));},},// …}],// …}],// …});// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.clean({id: 'batmobile',});

Receive object sync notifications

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// update the interface for remote changesZDRSchemaDispatchSyncCreate(object){console.log('create',object);},ZDRSchemaDispatchSyncUpdate(object){console.log('update',object);},ZDRSchemaDispatchSyncDelete(object){console.log('delete',object);},// handle conflictZDRSchemaDispatchSyncConflict(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.

constapi=awaitzerodatawrap.ZDRWrap({ZDRParamLibrary: (function(){// get the selected protocol, default to `ZDRProtocolCustom`constselected=zerodatawrap.ZDRPreferenceProtocol(zerodatawrap.ZDRProtocolCustom());if(selected===zerodatawrap.ZDRProtocolRemoteStorage()){returnRemoteStorage;}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:

if(zerodatawrap.ZDRPreferenceProtocolMigrate()){// generate apis from protocolconstwrap=function(protocol){returnzerodatawrap.ZDRWrap({// …});};constsource=awaitwrap(zerodatawrap.ZDRPreferenceProtocolMigrate());constdestination=awaitwrap(zerodatawrap.ZDRPreferenceProtocol());// get all objects (this is simplified, should be recursive)awaitPromise.all(Object.entries(awaitsource.App.ZDRStorageListingObjects('')).map(asyncfunction([key,value]){// write to destinationawaitdestination.App.ZDRStorageWriteObject(key,value);// delete from sourceawaitsource.App.ZDRStorageDeleteFile(key);}));// clear migrate preference to avoid repeatingzerodatawrap.ZDRPreferenceProtocolMigrateClear();// call disconnect to do any other cleanupsource.ZDRCloudDisconnect();};

ZDRClient (for custom protocol only)

functionnotes
ZDRClientWriteFile
Required
called by ZDRStorageWriteFile
ZDRClientReadFile
Required
called by ZDRStorageReadFile
ZDRClientListObjects
Required
called by ZDRStorageListingObjects
ZDRClientDelete
Required
called by ZDRStorageDeleteFile
ZDRClientPreparecalled before returning wrapper
ZDRClientConnectcalled by ZDRCloudConnect
ZDRClientReconnectcalled by ZDRCloudReconnect
ZDRClientDisconnectcalled 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.

Send a gift

License

The code is released under a Hippocratic License, 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 or Bluesky.

About

Unified JavaScript API for Fission + remoteStorage.

Topics

Resources

Stars

21 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Project logo

Unified JavaScript API for Fission + remoteStorage.

Comparisons

Long names…

Yes, it's long and verbose and how I do things generally, but ideally your final code looks like this:

// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.wash({id: 'batmobile',});

API Guide

Setup

constapi=awaitzerodatawrap.ZDRWrap({// include then pass directlyZDRParamLibrary: RemoteStorage,// or webnative// read/write permissionsZDRParamScopes: [{// code-level identifierZDRScopeKey: 'alfa',// top-level storage directoryZDRScopeDirectory: 'bravo',}],});// write `{"foo":"bar"}` to /bravo/charlie.jsonawaitapi.alfa.ZDRStorageWriteObject('charlie.json',{foo: 'bar',});

ZDRWrap

paramtypenotes
ZDRParamLibrary
Required
pass RemoteStorage or webnative or an object conforming to ZDRClient
ZDRParamScopes
Required
array of ZDRScope objects
ZDRParamDispatchErrorfunctioncalled on network or sync errors
ZDRParamDispatchConnectedfunctioncalled if linked to a cloud account
ZDRParamDispatchOnlinefunctioncalled when network is online
ZDRParamDispatchOfflinefunctioncalled when network is offline

ZDRScope

paramtypenotes
ZDRScopeKey
Required
string, non-empty, trimmedconvenience accessor for code only
ZDRScopeDirectory
Required
string, non-empty, trimmed, no slashestop-level directory for claiming read/write access
ZDRScopeCreatorDirectorystring, non-empty, trimmedif Fission, sets permissions.app instead of permissions.fs
ZDRScopeSchemasarray of ZDRSchema objectsdefines model helpers
ZDRScopeIsPublicbooleanuse 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)

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …// map schemas to pathsZDRScopeSchemas: [{// code-level identifierZDRSchemaKey: 'cars',// path for a given objectZDRSchemaPath(object){return`cars/${object.id}.json`;},// object information for a given pathZDRSchemaStub(path){return{id: path.split('/').pop().split('.json').shift(),};},}],// …}],// …});// write `{"id":"batmobile"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.ZDRModelWriteObject({id: 'batmobile',});

ZDRSchema

paramtypenotes
ZDRSchemaKey
Required
string, non-empty, trimmedconvenience accessor for code only
ZDRSchemaPath
Required
functionconstructs the path for a given object
ZDRSchemaStub
Required
functionconstructs object information for a given path, used for filtering paths in recursion and routing sync events
ZDRSchemaMethodsobjectdefines methods to be accessed from the api interface (bound to this)
ZDRSchemaDispatchValidatefunctioncalled before ZDRModelWriteObject
ZDRSchemaDispatchSyncCreatefunctioncalled on remote create remoteStorage only
ZDRSchemaDispatchSyncUpdatefunctioncalled on remote update remoteStorage only
ZDRSchemaDispatchSyncDeletefunctioncalled on remote delete remoteStorage only
ZDRSchemaDispatchSyncConflictfunctioncalled on remote conflict remoteStorage only
Note: this passes the remoteStorage change event directly

Specify a validation function

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// truthy values cause a promise rejectionZDRSchemaDispatchValidate(object){if(typeofobject.id!=='string'){return{not: 'so fast',};}},// …}],// …}],// …});// rejectstry{awaitapi.alfa.cars.ZDRModelWriteObject({id: 123,});}catch(truthy){console.log(truthy.not);// so fast}

Specify custom methods

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// logic to be done on saveZDRSchemaMethods: {clean(car){returnthis.alfa.cars.ZDRModelWriteObject(Object.assign(car,{clean: true,washed: newDate(),}));},},// …}],// …}],// …});// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.clean({id: 'batmobile',});

Receive object sync notifications

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// update the interface for remote changesZDRSchemaDispatchSyncCreate(object){console.log('create',object);},ZDRSchemaDispatchSyncUpdate(object){console.log('update',object);},ZDRSchemaDispatchSyncDelete(object){console.log('delete',object);},// handle conflictZDRSchemaDispatchSyncConflict(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.

constapi=awaitzerodatawrap.ZDRWrap({ZDRParamLibrary: (function(){// get the selected protocol, default to `ZDRProtocolCustom`constselected=zerodatawrap.ZDRPreferenceProtocol(zerodatawrap.ZDRProtocolCustom());if(selected===zerodatawrap.ZDRProtocolRemoteStorage()){returnRemoteStorage;}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:

if(zerodatawrap.ZDRPreferenceProtocolMigrate()){// generate apis from protocolconstwrap=function(protocol){returnzerodatawrap.ZDRWrap({// …});};constsource=awaitwrap(zerodatawrap.ZDRPreferenceProtocolMigrate());constdestination=awaitwrap(zerodatawrap.ZDRPreferenceProtocol());// get all objects (this is simplified, should be recursive)awaitPromise.all(Object.entries(awaitsource.App.ZDRStorageListingObjects('')).map(asyncfunction([key,value]){// write to destinationawaitdestination.App.ZDRStorageWriteObject(key,value);// delete from sourceawaitsource.App.ZDRStorageDeleteFile(key);}));// clear migrate preference to avoid repeatingzerodatawrap.ZDRPreferenceProtocolMigrateClear();// call disconnect to do any other cleanupsource.ZDRCloudDisconnect();};

ZDRClient (for custom protocol only)

functionnotes
ZDRClientWriteFile
Required
called by ZDRStorageWriteFile
ZDRClientReadFile
Required
called by ZDRStorageReadFile
ZDRClientListObjects
Required
called by ZDRStorageListingObjects
ZDRClientDelete
Required
called by ZDRStorageDeleteFile
ZDRClientPreparecalled before returning wrapper
ZDRClientConnectcalled by ZDRCloudConnect
ZDRClientReconnectcalled by ZDRCloudReconnect
ZDRClientDisconnectcalled 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.

Send a gift

License

The code is released under a Hippocratic License, 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 or Bluesky.

About

Unified JavaScript API for Fission + remoteStorage.

Topics

Resources

Stars

21 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Project logo

Unified JavaScript API for Fission + remoteStorage.

Comparisons

Long names…

Yes, it's long and verbose and how I do things generally, but ideally your final code looks like this:

// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.wash({id: 'batmobile',});

API Guide

Setup

constapi=awaitzerodatawrap.ZDRWrap({// include then pass directlyZDRParamLibrary: RemoteStorage,// or webnative// read/write permissionsZDRParamScopes: [{// code-level identifierZDRScopeKey: 'alfa',// top-level storage directoryZDRScopeDirectory: 'bravo',}],});// write `{"foo":"bar"}` to /bravo/charlie.jsonawaitapi.alfa.ZDRStorageWriteObject('charlie.json',{foo: 'bar',});

ZDRWrap

paramtypenotes
ZDRParamLibrary
Required
pass RemoteStorage or webnative or an object conforming to ZDRClient
ZDRParamScopes
Required
array of ZDRScope objects
ZDRParamDispatchErrorfunctioncalled on network or sync errors
ZDRParamDispatchConnectedfunctioncalled if linked to a cloud account
ZDRParamDispatchOnlinefunctioncalled when network is online
ZDRParamDispatchOfflinefunctioncalled when network is offline

ZDRScope

paramtypenotes
ZDRScopeKey
Required
string, non-empty, trimmedconvenience accessor for code only
ZDRScopeDirectory
Required
string, non-empty, trimmed, no slashestop-level directory for claiming read/write access
ZDRScopeCreatorDirectorystring, non-empty, trimmedif Fission, sets permissions.app instead of permissions.fs
ZDRScopeSchemasarray of ZDRSchema objectsdefines model helpers
ZDRScopeIsPublicbooleanuse 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)

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …// map schemas to pathsZDRScopeSchemas: [{// code-level identifierZDRSchemaKey: 'cars',// path for a given objectZDRSchemaPath(object){return`cars/${object.id}.json`;},// object information for a given pathZDRSchemaStub(path){return{id: path.split('/').pop().split('.json').shift(),};},}],// …}],// …});// write `{"id":"batmobile"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.ZDRModelWriteObject({id: 'batmobile',});

ZDRSchema

paramtypenotes
ZDRSchemaKey
Required
string, non-empty, trimmedconvenience accessor for code only
ZDRSchemaPath
Required
functionconstructs the path for a given object
ZDRSchemaStub
Required
functionconstructs object information for a given path, used for filtering paths in recursion and routing sync events
ZDRSchemaMethodsobjectdefines methods to be accessed from the api interface (bound to this)
ZDRSchemaDispatchValidatefunctioncalled before ZDRModelWriteObject
ZDRSchemaDispatchSyncCreatefunctioncalled on remote create remoteStorage only
ZDRSchemaDispatchSyncUpdatefunctioncalled on remote update remoteStorage only
ZDRSchemaDispatchSyncDeletefunctioncalled on remote delete remoteStorage only
ZDRSchemaDispatchSyncConflictfunctioncalled on remote conflict remoteStorage only
Note: this passes the remoteStorage change event directly

Specify a validation function

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// truthy values cause a promise rejectionZDRSchemaDispatchValidate(object){if(typeofobject.id!=='string'){return{not: 'so fast',};}},// …}],// …}],// …});// rejectstry{awaitapi.alfa.cars.ZDRModelWriteObject({id: 123,});}catch(truthy){console.log(truthy.not);// so fast}

Specify custom methods

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// logic to be done on saveZDRSchemaMethods: {clean(car){returnthis.alfa.cars.ZDRModelWriteObject(Object.assign(car,{clean: true,washed: newDate(),}));},},// …}],// …}],// …});// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.clean({id: 'batmobile',});

Receive object sync notifications

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// update the interface for remote changesZDRSchemaDispatchSyncCreate(object){console.log('create',object);},ZDRSchemaDispatchSyncUpdate(object){console.log('update',object);},ZDRSchemaDispatchSyncDelete(object){console.log('delete',object);},// handle conflictZDRSchemaDispatchSyncConflict(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.

constapi=awaitzerodatawrap.ZDRWrap({ZDRParamLibrary: (function(){// get the selected protocol, default to `ZDRProtocolCustom`constselected=zerodatawrap.ZDRPreferenceProtocol(zerodatawrap.ZDRProtocolCustom());if(selected===zerodatawrap.ZDRProtocolRemoteStorage()){returnRemoteStorage;}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:

if(zerodatawrap.ZDRPreferenceProtocolMigrate()){// generate apis from protocolconstwrap=function(protocol){returnzerodatawrap.ZDRWrap({// …});};constsource=awaitwrap(zerodatawrap.ZDRPreferenceProtocolMigrate());constdestination=awaitwrap(zerodatawrap.ZDRPreferenceProtocol());// get all objects (this is simplified, should be recursive)awaitPromise.all(Object.entries(awaitsource.App.ZDRStorageListingObjects('')).map(asyncfunction([key,value]){// write to destinationawaitdestination.App.ZDRStorageWriteObject(key,value);// delete from sourceawaitsource.App.ZDRStorageDeleteFile(key);}));// clear migrate preference to avoid repeatingzerodatawrap.ZDRPreferenceProtocolMigrateClear();// call disconnect to do any other cleanupsource.ZDRCloudDisconnect();};

ZDRClient (for custom protocol only)

functionnotes
ZDRClientWriteFile
Required
called by ZDRStorageWriteFile
ZDRClientReadFile
Required
called by ZDRStorageReadFile
ZDRClientListObjects
Required
called by ZDRStorageListingObjects
ZDRClientDelete
Required
called by ZDRStorageDeleteFile
ZDRClientPreparecalled before returning wrapper
ZDRClientConnectcalled by ZDRCloudConnect
ZDRClientReconnectcalled by ZDRCloudReconnect
ZDRClientDisconnectcalled 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.

Send a gift

License

The code is released under a Hippocratic License, 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 or Bluesky.

About

Unified JavaScript API for Fission + remoteStorage.

Topics

Resources

Stars

21 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Project logo

Unified JavaScript API for Fission + remoteStorage.

Comparisons

Long names…

Yes, it's long and verbose and how I do things generally, but ideally your final code looks like this:

// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.wash({id: 'batmobile',});

API Guide

Setup

constapi=awaitzerodatawrap.ZDRWrap({// include then pass directlyZDRParamLibrary: RemoteStorage,// or webnative// read/write permissionsZDRParamScopes: [{// code-level identifierZDRScopeKey: 'alfa',// top-level storage directoryZDRScopeDirectory: 'bravo',}],});// write `{"foo":"bar"}` to /bravo/charlie.jsonawaitapi.alfa.ZDRStorageWriteObject('charlie.json',{foo: 'bar',});

ZDRWrap

paramtypenotes
ZDRParamLibrary
Required
pass RemoteStorage or webnative or an object conforming to ZDRClient
ZDRParamScopes
Required
array of ZDRScope objects
ZDRParamDispatchErrorfunctioncalled on network or sync errors
ZDRParamDispatchConnectedfunctioncalled if linked to a cloud account
ZDRParamDispatchOnlinefunctioncalled when network is online
ZDRParamDispatchOfflinefunctioncalled when network is offline

ZDRScope

paramtypenotes
ZDRScopeKey
Required
string, non-empty, trimmedconvenience accessor for code only
ZDRScopeDirectory
Required
string, non-empty, trimmed, no slashestop-level directory for claiming read/write access
ZDRScopeCreatorDirectorystring, non-empty, trimmedif Fission, sets permissions.app instead of permissions.fs
ZDRScopeSchemasarray of ZDRSchema objectsdefines model helpers
ZDRScopeIsPublicbooleanuse 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)

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …// map schemas to pathsZDRScopeSchemas: [{// code-level identifierZDRSchemaKey: 'cars',// path for a given objectZDRSchemaPath(object){return`cars/${object.id}.json`;},// object information for a given pathZDRSchemaStub(path){return{id: path.split('/').pop().split('.json').shift(),};},}],// …}],// …});// write `{"id":"batmobile"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.ZDRModelWriteObject({id: 'batmobile',});

ZDRSchema

paramtypenotes
ZDRSchemaKey
Required
string, non-empty, trimmedconvenience accessor for code only
ZDRSchemaPath
Required
functionconstructs the path for a given object
ZDRSchemaStub
Required
functionconstructs object information for a given path, used for filtering paths in recursion and routing sync events
ZDRSchemaMethodsobjectdefines methods to be accessed from the api interface (bound to this)
ZDRSchemaDispatchValidatefunctioncalled before ZDRModelWriteObject
ZDRSchemaDispatchSyncCreatefunctioncalled on remote create remoteStorage only
ZDRSchemaDispatchSyncUpdatefunctioncalled on remote update remoteStorage only
ZDRSchemaDispatchSyncDeletefunctioncalled on remote delete remoteStorage only
ZDRSchemaDispatchSyncConflictfunctioncalled on remote conflict remoteStorage only
Note: this passes the remoteStorage change event directly

Specify a validation function

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// truthy values cause a promise rejectionZDRSchemaDispatchValidate(object){if(typeofobject.id!=='string'){return{not: 'so fast',};}},// …}],// …}],// …});// rejectstry{awaitapi.alfa.cars.ZDRModelWriteObject({id: 123,});}catch(truthy){console.log(truthy.not);// so fast}

Specify custom methods

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// logic to be done on saveZDRSchemaMethods: {clean(car){returnthis.alfa.cars.ZDRModelWriteObject(Object.assign(car,{clean: true,washed: newDate(),}));},},// …}],// …}],// …});// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.clean({id: 'batmobile',});

Receive object sync notifications

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// update the interface for remote changesZDRSchemaDispatchSyncCreate(object){console.log('create',object);},ZDRSchemaDispatchSyncUpdate(object){console.log('update',object);},ZDRSchemaDispatchSyncDelete(object){console.log('delete',object);},// handle conflictZDRSchemaDispatchSyncConflict(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.

constapi=awaitzerodatawrap.ZDRWrap({ZDRParamLibrary: (function(){// get the selected protocol, default to `ZDRProtocolCustom`constselected=zerodatawrap.ZDRPreferenceProtocol(zerodatawrap.ZDRProtocolCustom());if(selected===zerodatawrap.ZDRProtocolRemoteStorage()){returnRemoteStorage;}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:

if(zerodatawrap.ZDRPreferenceProtocolMigrate()){// generate apis from protocolconstwrap=function(protocol){returnzerodatawrap.ZDRWrap({// …});};constsource=awaitwrap(zerodatawrap.ZDRPreferenceProtocolMigrate());constdestination=awaitwrap(zerodatawrap.ZDRPreferenceProtocol());// get all objects (this is simplified, should be recursive)awaitPromise.all(Object.entries(awaitsource.App.ZDRStorageListingObjects('')).map(asyncfunction([key,value]){// write to destinationawaitdestination.App.ZDRStorageWriteObject(key,value);// delete from sourceawaitsource.App.ZDRStorageDeleteFile(key);}));// clear migrate preference to avoid repeatingzerodatawrap.ZDRPreferenceProtocolMigrateClear();// call disconnect to do any other cleanupsource.ZDRCloudDisconnect();};

ZDRClient (for custom protocol only)

functionnotes
ZDRClientWriteFile
Required
called by ZDRStorageWriteFile
ZDRClientReadFile
Required
called by ZDRStorageReadFile
ZDRClientListObjects
Required
called by ZDRStorageListingObjects
ZDRClientDelete
Required
called by ZDRStorageDeleteFile
ZDRClientPreparecalled before returning wrapper
ZDRClientConnectcalled by ZDRCloudConnect
ZDRClientReconnectcalled by ZDRCloudReconnect
ZDRClientDisconnectcalled 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.

Send a gift

License

The code is released under a Hippocratic License, 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 or Bluesky.

About

Unified JavaScript API for Fission + remoteStorage.

Topics

Resources

Stars

21 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Project logo

Unified JavaScript API for Fission + remoteStorage.

Comparisons

Long names…

Yes, it's long and verbose and how I do things generally, but ideally your final code looks like this:

// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.wash({id: 'batmobile',});

API Guide

Setup

constapi=awaitzerodatawrap.ZDRWrap({// include then pass directlyZDRParamLibrary: RemoteStorage,// or webnative// read/write permissionsZDRParamScopes: [{// code-level identifierZDRScopeKey: 'alfa',// top-level storage directoryZDRScopeDirectory: 'bravo',}],});// write `{"foo":"bar"}` to /bravo/charlie.jsonawaitapi.alfa.ZDRStorageWriteObject('charlie.json',{foo: 'bar',});

ZDRWrap

paramtypenotes
ZDRParamLibrary
Required
pass RemoteStorage or webnative or an object conforming to ZDRClient
ZDRParamScopes
Required
array of ZDRScope objects
ZDRParamDispatchErrorfunctioncalled on network or sync errors
ZDRParamDispatchConnectedfunctioncalled if linked to a cloud account
ZDRParamDispatchOnlinefunctioncalled when network is online
ZDRParamDispatchOfflinefunctioncalled when network is offline

ZDRScope

paramtypenotes
ZDRScopeKey
Required
string, non-empty, trimmedconvenience accessor for code only
ZDRScopeDirectory
Required
string, non-empty, trimmed, no slashestop-level directory for claiming read/write access
ZDRScopeCreatorDirectorystring, non-empty, trimmedif Fission, sets permissions.app instead of permissions.fs
ZDRScopeSchemasarray of ZDRSchema objectsdefines model helpers
ZDRScopeIsPublicbooleanuse 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)

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …// map schemas to pathsZDRScopeSchemas: [{// code-level identifierZDRSchemaKey: 'cars',// path for a given objectZDRSchemaPath(object){return`cars/${object.id}.json`;},// object information for a given pathZDRSchemaStub(path){return{id: path.split('/').pop().split('.json').shift(),};},}],// …}],// …});// write `{"id":"batmobile"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.ZDRModelWriteObject({id: 'batmobile',});

ZDRSchema

paramtypenotes
ZDRSchemaKey
Required
string, non-empty, trimmedconvenience accessor for code only
ZDRSchemaPath
Required
functionconstructs the path for a given object
ZDRSchemaStub
Required
functionconstructs object information for a given path, used for filtering paths in recursion and routing sync events
ZDRSchemaMethodsobjectdefines methods to be accessed from the api interface (bound to this)
ZDRSchemaDispatchValidatefunctioncalled before ZDRModelWriteObject
ZDRSchemaDispatchSyncCreatefunctioncalled on remote create remoteStorage only
ZDRSchemaDispatchSyncUpdatefunctioncalled on remote update remoteStorage only
ZDRSchemaDispatchSyncDeletefunctioncalled on remote delete remoteStorage only
ZDRSchemaDispatchSyncConflictfunctioncalled on remote conflict remoteStorage only
Note: this passes the remoteStorage change event directly

Specify a validation function

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// truthy values cause a promise rejectionZDRSchemaDispatchValidate(object){if(typeofobject.id!=='string'){return{not: 'so fast',};}},// …}],// …}],// …});// rejectstry{awaitapi.alfa.cars.ZDRModelWriteObject({id: 123,});}catch(truthy){console.log(truthy.not);// so fast}

Specify custom methods

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// logic to be done on saveZDRSchemaMethods: {clean(car){returnthis.alfa.cars.ZDRModelWriteObject(Object.assign(car,{clean: true,washed: newDate(),}));},},// …}],// …}],// …});// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.clean({id: 'batmobile',});

Receive object sync notifications

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// update the interface for remote changesZDRSchemaDispatchSyncCreate(object){console.log('create',object);},ZDRSchemaDispatchSyncUpdate(object){console.log('update',object);},ZDRSchemaDispatchSyncDelete(object){console.log('delete',object);},// handle conflictZDRSchemaDispatchSyncConflict(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.

constapi=awaitzerodatawrap.ZDRWrap({ZDRParamLibrary: (function(){// get the selected protocol, default to `ZDRProtocolCustom`constselected=zerodatawrap.ZDRPreferenceProtocol(zerodatawrap.ZDRProtocolCustom());if(selected===zerodatawrap.ZDRProtocolRemoteStorage()){returnRemoteStorage;}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:

if(zerodatawrap.ZDRPreferenceProtocolMigrate()){// generate apis from protocolconstwrap=function(protocol){returnzerodatawrap.ZDRWrap({// …});};constsource=awaitwrap(zerodatawrap.ZDRPreferenceProtocolMigrate());constdestination=awaitwrap(zerodatawrap.ZDRPreferenceProtocol());// get all objects (this is simplified, should be recursive)awaitPromise.all(Object.entries(awaitsource.App.ZDRStorageListingObjects('')).map(asyncfunction([key,value]){// write to destinationawaitdestination.App.ZDRStorageWriteObject(key,value);// delete from sourceawaitsource.App.ZDRStorageDeleteFile(key);}));// clear migrate preference to avoid repeatingzerodatawrap.ZDRPreferenceProtocolMigrateClear();// call disconnect to do any other cleanupsource.ZDRCloudDisconnect();};

ZDRClient (for custom protocol only)

functionnotes
ZDRClientWriteFile
Required
called by ZDRStorageWriteFile
ZDRClientReadFile
Required
called by ZDRStorageReadFile
ZDRClientListObjects
Required
called by ZDRStorageListingObjects
ZDRClientDelete
Required
called by ZDRStorageDeleteFile
ZDRClientPreparecalled before returning wrapper
ZDRClientConnectcalled by ZDRCloudConnect
ZDRClientReconnectcalled by ZDRCloudReconnect
ZDRClientDisconnectcalled 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.

Send a gift

License

The code is released under a Hippocratic License, 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 or Bluesky.

About

Unified JavaScript API for Fission + remoteStorage.

Topics

Resources

Stars

21 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Project logo

Unified JavaScript API for Fission + remoteStorage.

Comparisons

Long names…

Yes, it's long and verbose and how I do things generally, but ideally your final code looks like this:

// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.wash({id: 'batmobile',});

API Guide

Setup

constapi=awaitzerodatawrap.ZDRWrap({// include then pass directlyZDRParamLibrary: RemoteStorage,// or webnative// read/write permissionsZDRParamScopes: [{// code-level identifierZDRScopeKey: 'alfa',// top-level storage directoryZDRScopeDirectory: 'bravo',}],});// write `{"foo":"bar"}` to /bravo/charlie.jsonawaitapi.alfa.ZDRStorageWriteObject('charlie.json',{foo: 'bar',});

ZDRWrap

paramtypenotes
ZDRParamLibrary
Required
pass RemoteStorage or webnative or an object conforming to ZDRClient
ZDRParamScopes
Required
array of ZDRScope objects
ZDRParamDispatchErrorfunctioncalled on network or sync errors
ZDRParamDispatchConnectedfunctioncalled if linked to a cloud account
ZDRParamDispatchOnlinefunctioncalled when network is online
ZDRParamDispatchOfflinefunctioncalled when network is offline

ZDRScope

paramtypenotes
ZDRScopeKey
Required
string, non-empty, trimmedconvenience accessor for code only
ZDRScopeDirectory
Required
string, non-empty, trimmed, no slashestop-level directory for claiming read/write access
ZDRScopeCreatorDirectorystring, non-empty, trimmedif Fission, sets permissions.app instead of permissions.fs
ZDRScopeSchemasarray of ZDRSchema objectsdefines model helpers
ZDRScopeIsPublicbooleanuse 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)

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …// map schemas to pathsZDRScopeSchemas: [{// code-level identifierZDRSchemaKey: 'cars',// path for a given objectZDRSchemaPath(object){return`cars/${object.id}.json`;},// object information for a given pathZDRSchemaStub(path){return{id: path.split('/').pop().split('.json').shift(),};},}],// …}],// …});// write `{"id":"batmobile"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.ZDRModelWriteObject({id: 'batmobile',});

ZDRSchema

paramtypenotes
ZDRSchemaKey
Required
string, non-empty, trimmedconvenience accessor for code only
ZDRSchemaPath
Required
functionconstructs the path for a given object
ZDRSchemaStub
Required
functionconstructs object information for a given path, used for filtering paths in recursion and routing sync events
ZDRSchemaMethodsobjectdefines methods to be accessed from the api interface (bound to this)
ZDRSchemaDispatchValidatefunctioncalled before ZDRModelWriteObject
ZDRSchemaDispatchSyncCreatefunctioncalled on remote create remoteStorage only
ZDRSchemaDispatchSyncUpdatefunctioncalled on remote update remoteStorage only
ZDRSchemaDispatchSyncDeletefunctioncalled on remote delete remoteStorage only
ZDRSchemaDispatchSyncConflictfunctioncalled on remote conflict remoteStorage only
Note: this passes the remoteStorage change event directly

Specify a validation function

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// truthy values cause a promise rejectionZDRSchemaDispatchValidate(object){if(typeofobject.id!=='string'){return{not: 'so fast',};}},// …}],// …}],// …});// rejectstry{awaitapi.alfa.cars.ZDRModelWriteObject({id: 123,});}catch(truthy){console.log(truthy.not);// so fast}

Specify custom methods

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// logic to be done on saveZDRSchemaMethods: {clean(car){returnthis.alfa.cars.ZDRModelWriteObject(Object.assign(car,{clean: true,washed: newDate(),}));},},// …}],// …}],// …});// write `{"id":"batmobile","clean":true,"washed":"…"}` to /bravo/cars/batmobile.jsonawaitapi.alfa.cars.clean({id: 'batmobile',});

Receive object sync notifications

constapi=zerodatawrap.ZDRWrap({// …ZDRParamScopes: [{// …ZDRScopeSchemas: [{// …// update the interface for remote changesZDRSchemaDispatchSyncCreate(object){console.log('create',object);},ZDRSchemaDispatchSyncUpdate(object){console.log('update',object);},ZDRSchemaDispatchSyncDelete(object){console.log('delete',object);},// handle conflictZDRSchemaDispatchSyncConflict(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.

constapi=awaitzerodatawrap.ZDRWrap({ZDRParamLibrary: (function(){// get the selected protocol, default to `ZDRProtocolCustom`constselected=zerodatawrap.ZDRPreferenceProtocol(zerodatawrap.ZDRProtocolCustom());if(selected===zerodatawrap.ZDRProtocolRemoteStorage()){returnRemoteStorage;}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:

if(zerodatawrap.ZDRPreferenceProtocolMigrate()){// generate apis from protocolconstwrap=function(protocol){returnzerodatawrap.ZDRWrap({// …});};constsource=awaitwrap(zerodatawrap.ZDRPreferenceProtocolMigrate());constdestination=awaitwrap(zerodatawrap.ZDRPreferenceProtocol());// get all objects (this is simplified, should be recursive)awaitPromise.all(Object.entries(awaitsource.App.ZDRStorageListingObjects('')).map(asyncfunction([key,value]){// write to destinationawaitdestination.App.ZDRStorageWriteObject(key,value);// delete from sourceawaitsource.App.ZDRStorageDeleteFile(key);}));// clear migrate preference to avoid repeatingzerodatawrap.ZDRPreferenceProtocolMigrateClear();// call disconnect to do any other cleanupsource.ZDRCloudDisconnect();};

ZDRClient (for custom protocol only)

functionnotes
ZDRClientWriteFile
Required
called by ZDRStorageWriteFile
ZDRClientReadFile
Required
called by ZDRStorageReadFile
ZDRClientListObjects
Required
called by ZDRStorageListingObjects
ZDRClientDelete
Required
called by ZDRStorageDeleteFile
ZDRClientPreparecalled before returning wrapper
ZDRClientConnectcalled by ZDRCloudConnect
ZDRClientReconnectcalled by ZDRCloudReconnect
ZDRClientDisconnectcalled 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.

Send a gift

License

The code is released under a Hippocratic License, 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 or Bluesky.

About

Unified JavaScript API for Fission + remoteStorage.

Topics

Resources

Stars

21 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages