
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
A pure javascript implementation of the SyncML adapter framework and protocol.
A pure javascript implementation of the SyncML adapter framework and protocol.
The syncml-js package is in "beta". That means that everything is
fully functional, however it has not had much real-world experience,
and therefore there are definitely bugs hidden here and there. Use
with caution, and always backup your data before doing anything (see
sbt for a convenient backup tool that
uses this SyncML implementation).
This is the easy part, provided you have npm installed:
npm install syncml-js
Note that syncml-js does not provide any command-line tools, so
you typically would list it in your package.json's "dependencies"
attribute and use it in your application.
For in-depth discussion on how to use a SyncML protocol library, please take a look at pysyncml: despite being in python, it uses the same concepts and almost an identical API. Basically, creating a SyncML client comprises the following steps:
Create the actual data layer of where your data lives, how it is stored and formatted, and the mechanisms that users use to interact and manipulate it.
Create an "Agent" class, which implements an API that forms the bridge between your data layer and the SyncML adapter.
Instantiate a "Context" and an "Adapter", classes provided by this package, which are responsible for actually communicating with a SyncML peer.
Ensure that changes made to the data layer are registered to the SyncML library.
Synchronize the adapter, using the adapter.sync() method for
client-side initialization or adapter.handleRequest() for
server-side request handling.
Here is a quick example of such a client, which assumes that the first
step, the local data layer, is implemented elsewhere. It uses the
amdefine package to handle dependencies, underscore for general
utilities, and cascade for taking some of the pain out of
callback-hell:
if ( typeof(define) !== 'function' )
var define = require('amdefine')(module);
define(['syncml-js', 'underscore', 'cascade'], function(syncml, _, cascade) {
//---------------------------------------------------------------------------
// define an agent class that is the bridge between your actual
// data and the SyncML adapter protocol framework.
var MyAgent = syncmljs.Agent.extend({
constructor: function(options) {
// TODO: constructor items
},
getContentTypes: function() {
// TODO: returns the content-types that your agent supports
return [
new syncmljs.ContentTypeInfo('text/calendar', '2.0', {preferred: true}),
new syncmljs.ContentTypeInfo('text/x-vcalendar', ['1.0', '1.1'])
];
},
dumpsItem: function(item, contentType, version, cb) {
// TODO: serialize the item
return cb(null, CONVERT-ITEM-TO-DATA [, CONTENT-TYPE [, VERSION ] ]);
},
loadsItem: function(data, contentType, version, cb) {
// TODO: de-serialize an item
var item = CONVERT-DATA-TO-ITEM;
return cb(null, item);
},
getAllItems: function(cb) {
// TODO: supplies a list of all existing items
return cb(null, LIST);
},
addItem: function(item, cb) {
// TODO: adds the new item to local storage -- it MUST also set
// the `id` attribute of the new item
return cb(null, ITEM-WITH-NEW-ID);
},
getItem: function(itemID, cb) {
// TODO: fetches the item with the specified `itemID`
return cb(null, ITEM);
},
replaceItem: function(item, reportChanges, cb) {
// TODO: updates the local storage with the new item, replacing the
// existing item with ID ``item.id``. if `reportChanges` is
// true (usually when this agent is acting as the server), the
// agent should provide a changeSpec string.
return cb(null, CHANGESPEC);
},
deleteItem: function(itemID, cb) {
// TODO: removes the item with the specified ID `itemID` from the
// local storage.
return cb(null);
}
});
//---------------------------------------------------------------------------
// create a SyncML adapter, which will be the object that actually
// communicates and synchronizes your data with other SyncML peers.
// this example shows how to create a client-side peer -- see the
// full documentation for how to create a server-side peer.
var context = new syncml.Context({
// `storage` must point to an "IndexedDB" implementation. if
// operating within a modern browser context, you can use
// the IndexedDB implementation provided by the browser:
storage: window.indexedDB,
// you can namespace this context's data with the `prefix`
// parameter:
prefix: 'my-syncml-client',
});
var exit = function(err, exitcode) {
util.error('[**] ERROR: ' + err);
process.exit(exitcode);
return;
}
context.getEasyClientAdapter({
displayName: 'My Remote Calendar Database',
devInfo: {
devID : 'a-globally-unique-identifier',
devType : syncml.DEVTYPE_WORKSTATION,
manufacturerName : 'syncml-js',
modelName : 'syncml-js.example.client',
hierarchicalSync : false
},
stores: [
{
uri : 'cal',
displayName : 'Remote Calendar',
maxGuidSize : 32,
maxObjSize : 2147483647,
agent : new MyAgent()
}
],
peer: {
url : 'https://example.com/sync',
auth : syncml.NAMESPACE_AUTH_BASIC,
username : 'guest',
password : 'guest'
}
// you can either specify how to bind local stores to the stores
// on the server, or you can let syncml-js apply its best guess.
// here, an example of how to bind the local "cal" datastore to
// the server's "calendar" datastore:
//
// routes: [
// [ 'cal', 'calendar' ]
// ]
}, function(err, adapter, stores, peer) {
if ( err )
return exit(err, 20);
// now the adapter is fully setup
report_changes(adapter, stores[0], peer);
});
//---------------------------------------------------------------------------
// with an adapter and peer setup, we can scan for local changes, report
// them, and then start the synchronization. the "find_all_*" functions are
// expected to be provided by your local data storage layer.
var report_changes = function(adapter, store, peer) {
find_all_add(function(items) {
cascade(items, cascade.queue, function(item, cb) {
store.registerChange(item.id, syncml.ITEM_ADDED, null, cb);
}, function(err) {
if ( err )
return exit(err, 30);
find_all_mod(function(items) {
cascade(items, cascade.queue, function(item, cb) {
store.registerChange(item.id, syncml.ITEM_MODIFIED, null, cb);
}, function(err) {
if ( err )
return exit(err, 31);
find_all_del(function(items) {
cascade(items, cascade.queue, function(item, cb) {
store.registerChange(item.id, syncml.ITEM_DELETED, null, cb);
}, function(err) {
if ( err )
return exit(err, 32);
sync_peer(adapter, store, peer);
});
});
});
});
});
});
};
//---------------------------------------------------------------------------
// now that all of the changes have been reported, we can actually do the
// synchronization with a remote peer.
var sync_peer = function(adapter, store, peer) {
adapter.sync(peer, syncml.SYNCTYPE_AUTO, function(err, stats) {
if ( err )
return exit(err, 40);
var stream = new syncml.Stream.extend({
write: function(data) {
util.print(data);
}
});
syncml.describeStats(stats, stream, {
title: 'Remote Calendar Sync Results'
});
process.exit(0);
});
};
});
FAQs
A pure javascript implementation of the SyncML adapter framework and protocol.
We found that syncml-js demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.