freezr is an open source personal server, built on node.js.
It acts as a thin layer providing identity and permissions management, to connect apps to the data owner's files, data and even compute resources.
Apps define their parameters and permissions via an App Manifest
Apps communicate with the server via a Core API which is CEPS-compatible.
Apps can be independent third party apps outside of the freezr server (eg a smart phone app that communicates with your freezr, or even a third party server that stores your data on your freezr.) But freezr also allows html apps to be served from your freezr server. Such a "freezr app" is just a collection of html, css and js files which you can "install" on your server. ie you just download the html/css/js files on your freezr, define how a page should be served in the manifest and then.
Of course, this would mean that, for security reasons, freezr apps can't directly run any code on the back end. However, back end code can either be run on serverless instances or on the server if it is trusted. See here for more details.
Within freezr, all data is stored within a user's preferred storage medium - their personal data store, which can be on AWS, Azure or even Dropbox, or any other storage medium that is connected to freezr via its Resource APIs. Here, data refers to actual data sitting in the freezr database, any files which you store there (eg pictures), as well as the freezr-app's actual program files (ie html/css/js files served.)
Details on all of this can be found in the sections below.
App Manifest
Core API for Apps (CEPS+)
Microservices - for running code on the server
Resource API
App Info API
A manifest defines a JSON object with the attributes listed below. A freezr manifest is compatible with the manifest described by CEPS, with some additional features.
Metadata about the app (based on CEPS):
identifier: The formal name of the app, in reverse domain name notation
display_name: The name as it would appear in a listing of apps
description: A description of the app for its users.
version: For internal purposes.
manifest_url: The url of site where the official manifest of the file can be found.
app_url: For server based apps, which have an external srver service.
pages: Attributes of the web pages served by freezr. This is used for freezr-apps only.
Each web page's main html file serves as a key to an object with the attributes below. (eg index.html would have the key "index".)
page_title: The name of the page as you would want your users to see it in the their browser.
html_file: The name of the file holding the basic html for the page.
script_files: The name of the javascript file or a list of files that the page should to. freezr automatically adds this js file to the app page "head". Each name can be a js file in the root directory (eg 'index.js') or in a subdirectory ('scripts/index.js') or a reference to a js file on the internet (anything starting with 'http').
css_files: The name of the css file or a list of files that the page should to. freezr automatically adds this css file to the app page "head". (Different paths can be defined as with js files above.)
initial_query (WIP): Query parameters to be used to populate the app before it is seved up. (If used, the app html file needs to follow mustache.js conventions.)
app_tables: Defines the attributes of specific data tables (ie collections.)
should contain json objects with the name of the collection, and each collection name object can have the following attributes:
Collection names cannot have the following characters: "_", "/", " ", or ".", nor start with "system","-" or "\". The following collection names are reserved and can't be used: "files", "field_permissions", "accessible_objects".
strictly_Adhere_To_schema: true forces freezr to only accept the field_names defined below.
make_data_id: If left undefined, mongodb automatically generates a unique id for each data-base record. Other options...
manual: Setting true means that the app needs to provide the unique id ("data_object_id") when writing a new object to the database.
from_field_names: If true, a unique data_object_id is created by combining a set of reference field_names. (It is up to the app to make sure that the combination of those reference field_names is unique.)
reference_field_names: An array of field_names in the collections, the combination of which is unique. This is needed if "from_field_names" is set to true.
Note that files necessarily have their own object id's based on their folder and file name. So obejct_id's cannot be generated manually or from field_names.
field_names: Defines the attributes of specific field_names in a collection.
"field_names" should contain json objects with the name of the key, and each key object can have the following attributes:
description: This is shown to users, when asking them to accept or deny the permission. It can provide context for the user.
required: true forces object to have this key.
type: This is not used for the moment. In the future it can be used to enforce data type.
field_names cannot begin with "_".
The following field_names are generated automatically for each record: "_owner" (the person who created the record), and "_date_Created".
files: freezr can store files and it creates a database record for each file. File attrbutes are as follows:
do_not_allow: 'true' stops freezr from accepting any file uploads. Best practice is to mark this as true if the app doesnt use file uploads.
strictly_Adhere_To_schema: 'true' forces freezr to only accept the field_names defined below.
donot_auto_enumerate_duplicates: In case a file's name already exists, by default, freezr autom-enumerates the files, by adding a number at the end of the file. Setting this to true returns an error if the file is duplicated.
allowed_file_types: A list of file extensions which uploaded files must adhere to.
field_names: Names of field_names that can accompany a record of the file in the database. field_names contain json objects with names each of which can contain the following attributes: description, type, required (like all collections - see above).
permissions: Defines the permissions the app is asking for.
"permissions" are a list of json objects with the name of the permission. Each permission object has the following attributes:
name: Permission to access all records in a table (based on CEPS).
An object_delegate can have the following attributes:
Permission names cannot have "_" or "/".
share_records: Permission to access all records in a table (based on CEPS).
An object_delegate can have the following attributes:
Example: Share messages held in a "messages" collection. Note that the app gets permission to access all records and then solicits user input to see who is allowed to see which message.
description: This is shown to users, when asking them to accept or deny the permission. It can provide context for the user.
requestee_app: Apps can ask to gain read permission in other apps' collections. This defaults to null.
app_tables: A list of tables that app can have access to.
sharable_groups: A list of who the files can be shared with. Currently, the options are "logged_in" (for all users of your freezr), "public" and "self" (which can be used when your app wants to access data from another app in teh same freezr.) The default is "self" to the same app, meaning only the user can access.
return_fields: An array of the field names, whose values are allowed to be returned with each record queried. (null returns all.)
card (Used for public queries): The name of an html file in the app fodlers. This is a mustache-based file that will be integrated with the data from the object.
search_fields (Used for public queries): The fields whose values can be searched on.
db_query: A specfic database query that can return a limited set of results.
A db_query can have the following attributes:
Example: Allow access only to the most recent score in a game.
description: This is shown to users, when asking them to accept or deny the permission. It can provide context for the user.
requestee_app: Apps can ask to gain read permission in other apps' collections. default is to request permissions within the app.
collection: The name of the collection the permission relates to.
sharable_groups: A list of who the files can be shared with. Currently, the options are "logged_in" (for all users of your freezr), "public" and "self" (which can be used when your app wants to access data from another app in teh same freezr.) The default is "self" to the same app, meaning only the user can access.
permitted_fields: A list of fields that can be queried. null defaults to all fields.
sort_fields: A json object of how results must be sorted - formatted as for mongodb, with -1 and 1 to descentding versus ascending. (eg {"score":-1} )
return_fields: An array of the field names, whose values are allowed to be returned with each record queried. (null returns all.)
max_count: The maximum bumber of data records which can be returned.
query_params: Other parameters to query - formatted for mongodb. (Permission mist be granted for fields queried.)
OLDER ITEMS NOT USED:
folder_delegate (WIP): Permission to access files (and their records). Permissions would be granted by folder.
A folder_delegate can have the following attributes:
Example: Share photos within a folder. Note that the app gets permission to access all photos and then solicits user input to see who is allowed to see which photo in the folder.
description: This is shown to users, when asking them to accept or deny the permission. It can provide context for the user.
requestee_app: Apps can ask to gain read permission in other apps' collections. This defaults to null.
sharable_folders: A list of the names of the folders to be shared. ('/' for root.) Cannot be left blank.
sharable_groups: A list of who the files can be shared with. Currently, the options are "logged_in" (for all users of your freezr), "public" and "self" (which can be used when your app wants to access data from another app in teh same freezr.) The default is "self" to the same app, meaning only the user can access.
return_fields: An array of the field names, whose values are allowed to be returned with each record queried. (null returns all.)
field_delegate (WIP): Permission to access a set of records, defined by a colelction and a field_name /field_value pair.
A field_delegate can have the following attributes:
Example: In an "albums" collection, which contains records of photos, share all photos whose field_value is "album" and field_value is "mySummerVacation".
description: This is shown to users, when asking them to accept or deny the permission. It can provide context for the user.
requestee_app: Apps can ask to gain read permission in other apps' collections. This defaults to null.
collections: A list of only 1 collection only - the collection the fields are in.
sharable_fields: A list of the name of the fields to be shared.
sharable_groups: A list of who the files can be shared with. Currently, the options are "logged_in" (for all users of your freezr), "public" and "self" (which can be used when your app wants to access data from another app in teh same freezr.) The default is "self" to the same app, meaning only the user can access.
return_fields: An array of the field names, whose values are allowed to be returned with each record queried. (null returns all.)
outside_scripts: Permission to use scripts on the internet.
An outside_scripts can have the following attributes:
Example: Link to maps.google.com api for the app.
description: This is shown to users, when asking them to accept or deny the permission. It can provide context for the user.
script_url: The url of the script to be included in the app page. The same url needs to appear in the "pages object."
This is an example of a manifest file. (Key words in green):
{
"app_name":"info.freezr.demo.clickOnCheese.EveryOnesCheese",
app name is
"app_display_name":"Click On EVERY ONE's Cheese - File Sharing Demo"
"app_version": "01"
"only_use_collections_listed":true, // true means only accept field_names that are in the key list below
"pages": { app pages
"index": {
"page_title":"Click on Cheese Game",
"html_file":"index.html",
"css_files": ["index.css"],
"script_files": ["index.js"]
},
"cheese_list": {
"page_title":"list of Cheeses to choose from",
"html_file":"cheese_list.html",
"css_files": "cheese_list.css",
"initial_query": {"type":"queryData", "permission_name":"cheese_share" }
"script_files": ["cheese_list.js"]
}
},
"app_tables": { collections
"scores": {
"strictly_Adhere_To_schema":true,
"make_data_id":{"manual":true},
"field_names": {
"score": {
"description":"Player Score",
"type":"integer",
"required":true,
}
}
},
},
"files": {
"do_not_allow":false,
"strictly_Adhere_To_schema":false,
"donot_auto_enumerate_duplicates":false,
"allowed_file_types":["jpg","png","jpeg","JPG","PNG","JPEG"],
"field_names":{
"description":"Cheese Name",
"type":"string",
"required":false,
}
},
"permissions": {
"top_scores": {
"type":"db_query",
"description":"Player Top Scores",
"requestee_app":null,
"collection":"scores",
"permitted_fields":null,
"sort_fields":{"score":-1},
"max_count":1,
"return_fields":"score","_owner","_date_Created"],
"sharable_groups":["logged_in"],
},
"cheese_share": {
"type":"object_delegate",
"description":"Share All Cheese Pictures",
"collection":"files",
"sharable_groups":["logged_in"],
"requestee_app":null,
}
}
}
The freezr_core API is a set of javascript functions for accessing the database, accessing uploaded files, managing permissioning, and rendering pages.
freezr automatically includes this library (freezr_core.js) when a freezr-app is served. But this file can also be used in stand-alone apps, including any ceps-compatible app. The freezr core API with the functions below.
The main functions may be used either with a callback or as a promise. For example, you can write either
freezr.ceps.create({foo: 'bar'}, function(results) { console.log(results)})
or
results = await freepr.ceps.create({foo: 'bar'})
("freepr" is shorthand for "freezr.promise".)
The functions in the library are:
CEPS: CEPS compatible functions
create (data [, options] [, callback]): Create an entry in a table.
Example: freezr.ceps.create({"score":score});
Example: freezr.promise.ceps.create({"score":score}). then(callFwdForScoreWrite);
Example: freezr.ceps.create({"score":score}, {collection: "scores"}, callbackForScoreWrite);
Example: freepr.ceps.create({"score":score}, {collection: "scores"}). then(callFwdForScoreWrite);
This POSTs to: /ceps/write/{table-identifier}
Parameters:
data: data to write, in json format. (obligatory)
options: Json object currently accepting:
app_table: table to write to.
collection: Can be provided instead of app_table. The collection name is appended to the app name to create the app_table. (Collection defaults to "main" if both are left blank)
callback: callback function to be executed after the CEPS server responds
The following parameters are added to each record automatically
_date_created: Date record was first written
_date_modified: Current time
_owner: user name
_id: automatically generated.
Collection names cannot have the following characters: "_", "/", " ", or ".", nor start with "system","-" or "\". The 'files' collection is used to keep track of uploaded files and should not be used.
getById (dataObjectId [, options [, callback]]): Get object by id
Example: freezr.ceps.getById('unique_id_of_db_record', null, callbackForGetById);
Example: freezr.ceps.getById('unique_id_of_db_record', null, callbackForGetById);
This GETs from: /ceps/read/{table-identifier}/{record-id}
Parameters:
dataObjectId: id of record. (obligatory)
callback: callback function to be executed after the CEPS server responds
getquery ([options [, callback] ]): Query database
Example: freezr.ceps.getquery( { 'collection':'scores', 'query_params': {'_owner':'slowJoeCrow' } }, callbackForTopScoreQuery );
Example: freezr.promise.ceps.getquery(). then(callFwdForAllScoresQuery);
This GETs from: /ceps/query/{table-identifier}[?{attribute}={ value}[&{attribute2}={value2} ...] ]
Parameters:
options: if null, queries all records. Possible Parameters:
app_table: table to query.
collection: Can be provided instead of app_table. The collection name is appended to the app name to create the app_table. (Collection defaults to "main" if both are left blank)
query_params: A Json obejct of key value pairs to search for equality. As per ceps, getquery can also take ''$gt' (>) and ''$lt' (<) only for the key _date_modified, using mongo notation. (More complex queries can be made with feps).
callback: callback function to be executed after the freezr server responds
update (data [, options [, callback] ]): Update a record in the database.
Example: freezr.ceps.update({ _id, score :newScore});
Example: freezr.promise.ceps.update({ _id, score :newScore}. then(callFwdForScoreWrite);
This PUTs to: /ceps/update/{table-identifier}/{record-id}
Parameters:
data: Json object only holding '_id' key
options: options:
app_table: table to write to.
collection: Can be provided instead of app_table. The collection name is appended to the app name to create the app_table. (Collection defaults to "main" if both are left blank)
callback: callback function to be executed after the freezr server responds
delete (dataObjectId [, options [, callback]]): Get object by id
Example: freezr.ceps.delete('unique_id_of_db_record', callbackForGetById);
Example: freezr.ceps.delete('unique_id_of_db_record', null, callbackForGetById);
This DELETEs at: /ceps/delete/{table-identifier}/{record-id}
Parameters:
dataObjectId: id of record. (obligatory)
callback: callback function to be executed after the CEPS server responds
sendMessage (toShare [, callback]): Sends a message to another user / server.
This POSTs to: /ceps/message/initiate
Parameters:
toShare: a Json object with the following:
recipient_host: url of host being sent a message. (obligatory)
recipient_id: id of user being sent a message. (obligatory)
sharing_permission: Permission name for sharing. (obligatory)
contact_permission: Permission name for accessign contacts. (obligatory)
record_id: id of record being shared. (obligatory)
table_id: Table from which record is being shared. (obligatory)
callback: callback function to be executed after the CEPS server responds
FEPS: freezr End-Points - like CEPS, but with advanced functionality...
create (data [, options] [, callback]): Create an entry in a table.
Example: freezr.feps.create({"score":score});
Example: freezr.promise.feps.create({"score":score}). then(callFwdForScoreWrite);
Example: freezr.feps.create({"score":score}, {collection: "scores"}, callbackForScoreWrite);
Example: freepr.feps.create({"score":score}, {collection: "scores"}). then(callFwdForScoreWrite);
This POSTs to: /feps/write/{table-identifier}
Parameters:
data: data to write, in json format. (obligatory)
options: Json object currently accepting:
app_table: table to write to.
collection: Can be provided instead of app_table. The collection name is appended to the app name to create the app_table. (Collection defaults to "main" if both are left blank)
updateRecord: Boolean. If write operation is to update existing record.
data_object_id: If data_object_id is to be set manually, or if a record is being update.
restoreRecord: Boolean. A special option for restoring a record If restoreRecord is set, then freezr uses the _date_Modified sent as data, rather than setting the _date_modified to the current time.
upsert: Boolean. Upsert option.
callback: callback function to be executed after the CEPS server responds
The following parameters are added to each record automatically
_date_created: Date record was first written
_date_modified: Current time
_owner: user name
_id: automatically generated.
Collection names cannot have the following characters: "_", "/", " ", or ".", nor start with "system","-" or "\". The 'files' collection is used to keep track of uploaded files and should not be used.
getById (dataObjectId [, options [, callback]]): Get object by id
Example: freezr.feps.getById('unique_id_of_db_record', null, callbackForGetById);
Example: freezr.feps.getById('unique_id_of_db_record', null, callbackForGetById);
This GETs from: /feps/read/{table-identifier}/{record-id}[/{user-id}]
Parameters:
dataObjectId: id of record. (obligatory)
callback: callback function to be executed after the CEPS server responds
permission_name: Permission name required to access other users' or apps' data.
userId: For reading another person's data.
postquery ([options [, callback] ]): Query database
Example: freezr.feps.postquery( { 'collection':'scores', 'query_params': {'_owner':'slowJoeCrow' } }, callbackForTopScoreQuery );
Example: freezr.promise.feps.postquery(). then(callFwdForAllScoresQuery);
This POSTs to: /feps/query/{table-identifier}[?{attribute}={ value}[&{attribute2}={value2} ...] ]
Parameters:
options: if null, queries all records. Possible Parameters:
app_table: table to query.
collection: Can be provided instead of app_table. The collection name is appended to the app name to create the app_table. (Collection defaults to "main" if both are left blank)
query_params: A Json obejct with search queries compatible with Mongodb.
permission_name: permission under which query is made. If a "permission" is used, query must conform with it.
sort_field: Defaults to _date_Modified
sort_desc: 1 or -1
count: Number of records to return
skip: Number of records to skip before sending results.
callback: callback function to be executed after the freezr server responds
update (data [, options [, callback] ]): Update a record in the database.
Example: freezr.feps.update({ _id, score: newScore});
Example: freezr.promise.feps.update({ _id, score: newScore}). then(callFwdForScoreWrite);
Example: freezr.feps.update({ score: artificiallyuInflatedScore }, {q: { name }}, callbackForScoreWrite, "scores");
This PUTs to: /ceps/update/{table-identifier}/{record-id}
Parameters:
data: The record as Json object. Must include '_id' if options.q doesnt exist
options: options:
app_table: table to write to.
collection: Can be provided instead of app_table. The collection name is appended to the app name to create the app_table. (Collection defaults to "main" if both are left blank)
q: Query used to find records to update. Mongodb compatible format.
setkeys: Only updates the keys provided in the data object. (Does not work with options.q - ie only works win updating 1 record)
callback: callback function to be executed after the freezr server responds
upload (file [, options [, callback] ]): Upload a file and record it in the database.
Example: freezr.feps.upload(document.getElementById('picture_file').files[0]);
Example: freezr.feps.upload(document.getElementById('picture_file').files[0], {'caption':'savoie cheese','fileOverWrite':true}, callbackForPictureUpload);
Example: freezr.promise.feps.upload(document.getElementById('picture_file').files[0], {'caption':'savoie cheese','fileOverWrite':true}) .then( callFwdForPictureUpload);
Parameters:
file: File to upload via html tag. (obligatory)
options: Json object currently accepting:
data: Json format data to store in db related to the file.
updateRecord: If write operation is to update the data in the existing record.
doNotOverWrite: Boolean - indicates not to overwrite if file already exists
targetFolder: Subfolder under root app folder where file should be saved.
fileName: name under which file should be saved. (Defaults to uploaded file's name).
callback: callback function to be executed after the freezr server responds
The following parameters are added to each record automatically
_date_created: Date record was first written
_date_modified: Current time
_owner: user name
_id: Automatically generated based on file name and relative path
_folder: Folder in which file is being saved.
Each file uploaded gets an associated record in the db in a collection named "files", and ad-hoc other data fields can be added to that record. The _id of the record is the relative file path plus file name, and this cannot be changed. Files can be accessed via url - see freezr.filePath below.
getByPublicId (dataObjectId [, options [, callback]]): Get a publicly accessible object by id
Example: freezr.feps.getByPublicId('unique_public_id_of_db_record', null, callbackForGetById);
This GETs from: /v1/pdb/{record-id}
Parameters:
dataObjectId: Public id of record. (obligatory)
callback: callback function to be executed after the CEPS server responds
userId: For reading another person's data.
publicquery ([options [, callback] ]): Queries all published (ie publicly accessible) records on server
Example: freezr.feps.publicquery( { 'collection':'scores', 'query_params': {'_owner':'slowJoeCrow' } }, callbackForTopScoreQuery );
Example: freezr.promise.feps.publicquery(). then(callFwdForAllScoresQuery);
This POSTs to: /v1/pdbq
Parameters:
options: if null, queries all records. Possible Parameters:
pid: public id of record.
userid: limits search to posts from one user
q: A Json obejct with search queries compatible with Mongodb.
sort_field: Defaults to _date_Modified
sort_desc: 1 or -1
count: Number of records to return
skip: Number of records to skip before sending results.
callback: callback function to be executed after the freezr server responds
Perms: Granting and reading permissions...
getAppPermissions (callback): Gets a list of permissions granted by the user to the app.
This is mainly called on my freezr_core, but can also be accessed by apps.
Example: freezr.perms.getAppPermissions(callbackForAppPerms);
Example: freezr.promise.perms.getAppPermissions() .then(callFwdForAppPerms);
Parameters:
callback: callback function to be executed after the freezr server responds
freepr substitutes freezr.promise.
shareRecords (idOrQuery, options, callback): Gives specific users rights to a specific record. (Can be CEPS or FEPS)
This gives specific people access to a specific single objects. If the object is a file, then the user can access the file. (CEPS compatible)
Example: freezr.perms.shareRecords("aug2015photos/2015-08-21-0234.jpg", callbackForObjectAccess);
Example: freezr.promise.perms.shareRecords("aug2015photos/2015-08-21-0234.jpg") .then(callFwdForObjectAccess);
This POSTs to: /feps/perms/share_records or /ceps/perms/share_records
Parameters:
idOrQuery: The _id of the db record being shared, as a string. FEPS also allows his to be a mongodb compatible Json query.
options: Possible Parameters:
permissionName: Permission under which query is being made. (Obligatory)
table_id: Table in which shared record lies.
grantees: A 'contact' as defined by CEPS, with which this is being shared. This can also be '_public'
action: Can be 'grant' (default) or 'deny'
publicid (FEPS only): A proposed public id for the shares item - where it is being shared with public. For non-admin users of the server, this has to start with @userId
_date_published (FEPS only): A publish date
unlisted (FEPS only): Does not appear in the public table and thus cannot be queried using publicquery.
doNotList (FEPS only): Does appear in the public table but doesnt show up on the ppage query list.
callback:callback function to be executed after the freezr server responds
shareServableFile (id, options, callback) (FEPS): Used to publish user uplaoded web pages.
This is like shareRecords but has an additional fileStrcuture field showing the js and css files that need to be appended to the page.
This POSTs to: /feps/perms/share_records
Parameters (Same as share_records plus the option):
fileStructure: A JSON object holding a a list of js files and css files. {js: [], css: []}
Utils: Functions for rendering html or referring to files from html
getConfig (callback): Developer function to get the app_config and the list of colelction_names used.
Example: freezr.utils.getConfig(callbackForGetConfig) ;
This is for the app development process mainly. It returns "{'app_config':app_config, 'collection_names':collection_names}", where collection_names are the collection_names actually used, whether they appear in the app_config or not.
Parameters:
callback: callback function to be executed after the freezr server responds
updateFileList: Developer function
Example: freezr.db.updateFileList(callbackForUpdatingFilelst) ;
This is for the app development process mainly. If files have been added to a folder manually, this function reads all the files and records them in the db.
Parameters:
callback: callback function to be executed after the freezr server responds
folder_name: Defaults to home folder
Note: Each subfolder needs to be updated separately. Function doesn't iterate automatically at the server level.
ping (callback): Pings server to see if it is available. (CEPS compatible)
Gets user_id, freezr_server_version and log in status on return.
Parameters:
callback: callback function to be executed after the freezr server responds
logout (): Logs out of freezr
getHtml (part_path, app_name, callback): Gets an html file on the freezr server.
This can be used to serve snippets of html via javascript (using mustache for example)
Parameters:
part_path: file name or sub-folder name plus file name in the app root directory
app_name: Defaults to current app
callback: callback function to be executed after the freezr server responds
getAllAppList (callback): Gets a JSON of all the user's apps.
filePathFromName (fileName, options): Creates full url or path to a file from a file name so that the file can be referred to in html.
Creates the full freezr path to user file based on the file's name. Each file's id (and path) includes the app name, user name, folder name and file name - the combination of which is always unique.
Example: freezr.utils.filePathFromName('aug2015photos/2015-08-21-0234.jpg', 'donald', 'photoAccess');
Parameters:
fileName: Name of file (including any folders.
user_id: user_id of owner (defaults to the user.)
permission_name: defaults to 'me'. Any user can access any data stored by the app being used - no permission required.
requestee_app:... if asking for another app.
Other: Other miscellaneous utilies for freezr apps.
app: Functions and variables for creating stand-alone apps with the likes of phonegap or electron, which are not accessed online via a web browser.
isWebBased: false by default. This should be set to true in the index.html of stand alone apps to indicate it is a standalone app
loginCallback: This can be set to a function which will be called when the user logs in, so that the app can do any necessary initialization.
logoutCallback: This can be set to a function which will be called when the user logs out, so that the app can do any necessary re-adjustments like deleting variables and local storage items.
initPageScripts: A special function, null by default that can be defined for each app, and whch is run after the app page has been created.
onFreezrMenuClose (hasChanged) : A special function, null by default that can be defined for each app, and is called when the freezr menu is closed. An app can define this to perform specific actions when a user grants or denies a new permission. ("hasChanged" indicates if the user has granted or denied a permission.)
Obviously it would be inherently unsafe to run untrusted third party code on any server. Unfortunately this also means that apps cannot run any back end code on freezr directly, not can they install any additional npm modules on the freezr backend end. So, to run server code and associated npm modules on the backend of freezr you can create microservices which can either bee run on a serverless instance, or if the service is trusted, on the freezr server itself.
To do this, apps can include a zip file of the microservice code in their app bundle (along with the app html/js/css files), and request the microservice permission. If users grant this permission, then the app can run the microservice zip file in one of two ways.
For users to take advantage of this serverless functionality, they need to have added a servlerless token for “compute” on their profile under “/account/settings”. Then, when they grant the use_microservice permission to an app, the app can run it as a backend process, using the token provided by that specific user. Currently the only choice is an AWS serverless instance but other cloud services will be added in the future.
If the server admin trusts the microservice’s code, then the admin can upload the same zip file here: /admin/addsystemextension and freezr will run the microservice locally. This is particularly useful for developers who would want to iterate on the microservice code without calling a serverless instance every time.
This simple microservices architecture makes freezr backend functionality infinitely extensible.
Note that when a user updates an app and they have given the use_microservice permission, the new microservices version is uploaded to their host (eg aws). However, only admins can install local extensions, as such the admin on the server needs to update the microservice for usage directly. Also note that local microservices are available to all users, and they are not restricted to any particular user, so they should be used cautiously, and preferrably mainly for development.
The permission for microservices is as follows:
type: use_microservice
description: optional - free text
name: the name of the permission. This name typically in reverse domain notation will need to be unique if used locally. When the microservice is run on a serverless instance, to avoid conflicts, the function is stored under a name which includes the app name, the microservice name and the user’s name. So an app called com.salmanff.llmtester which declares a microservice called com.anthropic.apitester run by the user Alice, would appear as such in Alice’s AWS dashboard: 'freezr_alice_com_salmanff_llmtester_com_anthropic_apitester All dots are replaced by underscores. Also note that due to the aws limit this is slices to 64 characters, leading to potential conflicts, if the user’s user name is very long for example)
functions: Currently not implemented. As a default, the permission name is also the function name. In the future, a single permission may encompass multiple functions.
Example:
{
"name": "com_anthropic_apitester",
"type": "use_micorservice",
"description": "testing serverless... "
}
The app can call the microservices function by using freezr.feps.microservice. As an example:
const serviceReturns = await freepr.feps.microservice(parameters)
Here are the parameters that can be passed to the function.
task: The following tasks may be called:
invokeserverless or invokelocalservice - currently the app needs to determine which of the two (serverless or local) is called. In the future, ‘invoke’ will default to the local service if not use the serverless one.
createserverless, createinvokeserverless, upsertserverless, updateserverless upsertlocalservice and deleteserverless - these allow the app to manage the serverless instance
permission_name: name of permission. Note that in the future, permissions may invoke multiple functions, and so a list of function_names may be added to the parameter. Currently, the permission)name acts as the function name.
The following keys are used to populate invokeserverless & invokeextension with parameters to run the function on.
inputParams: A set of parameters the app can send to the microservice directly.
read_collection_name, read_query and read_name: These three must be used together. When these are populated, freezr reads the read_query from the read_collection_name and passes it to the function parameters under the read_name key under ‘dbResults’ object. For the moment, the permissioning only allows the function to call data tables that belong to the app (ie that start with the app name.)
Additionally, in the future, the microservice will add additional parameters:
read_fileswill allow the function tom read a user file and pass it as a parameter to the function.
write_result and write_file will also allow the app to write the results of its function into the database or file system without having to be sent back to the client.
Example:
{
task: invokeextenstion,
inputParams: { args: ‘what is freezr?’, action: 'chat' },
permission_name: 'ai_open_tester_writeOpenai',
read_collection_name: 'openAIKeys',
read_query: { _id: 'openAIKey' },
read_name: 'openAiKeyQuery',
}
When this is sent to the freezr server, the server reads the database to get the openAIKey and then sends it to the microservice in an 'event' parameter set which look like this:
{
inputParams: { args: ‘what is freezr?’, action: 'chat' },
dbResults: { llmKeyQuery: [{ openAIKey: ‘secretKeyHere’, _id: ‘sdsdsd’, _date_modified: 34343433433}] }
}
The function can be thought of s compatible with any aws function, packed up in a zip. In fact it could probably be written in any language, but here we are assuming it is a node js function. So it would have a package.json (and package-lock.json) with only the dependencies, and it needs to have a file called index.mjs that has a function called handler. All the parameters noted above will be passed to the handler….
For example:
export const handler = async (event, context) => {
DO WHATEVER YOU WANT HERE, knowing that the event variable may have a dbResults and a inputParams key…
const apiResponse = { success: ‘send whatever you like’}
the value of the apiResponse object will be returned to the app.
const error = null
return { apiResponse, error }
})
freezr is purposefully targetting a lowest common denominator of files, databases and compute so that any file system, database and serverless compute resource can be plugged into it.
For the moment, mongo db compatible databases are supported, but it would be possible to design an interface for a sql database to be connected to it.
More details to be added