@soundworks/core
Advanced tools
Comparing version 3.0.4 to 3.1.0-beta.0
@@ -38,4 +38,3 @@ "use strict"; | ||
exports.DETACH_RESPONSE = DETACH_RESPONSE; | ||
const DETACH_ERROR = 's:dt:err'; // usefull | ||
const DETACH_ERROR = 's:dt:err'; | ||
exports.DETACH_ERROR = DETACH_ERROR; | ||
@@ -42,0 +41,0 @@ const OBSERVE_REQUEST = 's:o:req'; |
@@ -8,6 +8,4 @@ "use strict"; | ||
var _parameters = _interopRequireDefault(require("@ircam/parameters")); | ||
var _ParameterBag = _interopRequireDefault(require("./ParameterBag.js")); | ||
var _lodash = _interopRequireDefault(require("lodash.clonedeep")); | ||
var _sharedStateUtils = require("./shared-state-utils.js"); | ||
@@ -31,8 +29,7 @@ | ||
class SharedState { | ||
constructor(id, remoteId, schemaName, schema, client, isCreator, manager, initValues = {}) { | ||
constructor(id, remoteId, schemaName, schema, client, isOwner, manager, initValues = {}) { | ||
this.id = id; | ||
this.remoteId = remoteId; | ||
this.schemaName = schemaName; | ||
this._schema = (0, _lodash.default)(schema); | ||
this._isCreator = isCreator; // may be the server or any client | ||
this._isOwner = isOwner; // may be the server or any client | ||
@@ -43,3 +40,3 @@ this._client = client; | ||
try { | ||
this._parameters = (0, _parameters.default)(schema, initValues); | ||
this._parameters = new _ParameterBag.default(schema, initValues); | ||
} catch (err) { | ||
@@ -55,4 +52,4 @@ console.error(err.stack); | ||
client.transport.addListener(`${_sharedStateUtils.UPDATE_RESPONSE}-${id}-${this.remoteId}`, (reqId, updates) => { | ||
const updated = this._commit(updates); | ||
client.transport.addListener(`${_sharedStateUtils.UPDATE_RESPONSE}-${id}-${this.remoteId}`, (reqId, updates, context) => { | ||
const updated = this._commit(updates, context, true, true); | ||
@@ -62,10 +59,10 @@ (0, _sharedStateUtils.resolveRequest)(reqId, updated); | ||
client.transport.addListener(`${_sharedStateUtils.UPDATE_ABORT}-${id}-${this.remoteId}`, (reqId, updates) => { | ||
const updated = this._commit(updates, false); | ||
client.transport.addListener(`${_sharedStateUtils.UPDATE_ABORT}-${id}-${this.remoteId}`, (reqId, updates, context) => { | ||
const updated = this._commit(updates, context, false, true); | ||
(0, _sharedStateUtils.resolveRequest)(reqId, updated); | ||
}); | ||
client.transport.addListener(`${_sharedStateUtils.UPDATE_NOTIFICATION}-${id}-${this.remoteId}`, updates => { | ||
client.transport.addListener(`${_sharedStateUtils.UPDATE_NOTIFICATION}-${id}-${this.remoteId}`, (updates, context) => { | ||
// cf. https://github.com/collective-soundworks/soundworks/issues/18 | ||
this._commit(updates); | ||
this._commit(updates, context, true, false); | ||
}); // --------------------------------------------- | ||
@@ -87,3 +84,3 @@ // DELETE initiated by creator, or schema deleted | ||
if (this._isCreator) { | ||
if (this._isOwner) { | ||
// --------------------------------------------- | ||
@@ -133,8 +130,8 @@ // DELETE (can only delete if creator) | ||
this._onDeleteCallbacks.clear(); // Monkey patch detach so it throws we called twice. Doing nothing blocks | ||
// the process on a second `detach` call as the Promise was never resolved | ||
this._onDeleteCallbacks.clear(); // Monkey patch detach so it throws if called twice. Doing nothing blocks | ||
// the process on a second `detach` call as the Promise never resolves | ||
this.detach = () => { | ||
throw new Error(`State "${this.schemaName} (${this.id})" already detached, cannot detach twice`); | ||
throw new Error(`[stateManager] State "${this.schemaName} (${this.id})" already detached, cannot detach twice`); | ||
}; | ||
@@ -158,40 +155,104 @@ } | ||
_commit(obj, propagate = true) { | ||
const updated = {}; | ||
_commit(updates, context, propagate = true, initiator = false) { | ||
const newValues = {}; | ||
const oldValues = {}; | ||
for (let name in obj) { | ||
updated[name] = this._parameters.set(name, obj[name]); | ||
for (let name in updates) { | ||
const { | ||
immediate, | ||
filterChange, | ||
event | ||
} = this._parameters.getSchema(name); | ||
const oldValue = this._parameters.get(name); | ||
const [newValue, changed] = this._parameters.set(name, updates[name]); // handle immediate stuff | ||
if (initiator && immediate) { | ||
// @note - we don't need to check filterChange here because the value | ||
// has been updated in parameters on the `set` side so can rely on `changed` | ||
// to avoid retrigger listeners. | ||
// If the value has overriden by the server, `changed` will true | ||
// anyway so it should behave correctly. | ||
if (!changed || event) { | ||
continue; | ||
} | ||
} | ||
newValues[name] = newValue; | ||
oldValues[name] = oldValue; | ||
} // if the `UPDATE_REQUEST` as been aborted by the server, do not propagate | ||
if (propagate) { | ||
this._subscriptions.forEach(listener => listener(updated)); | ||
if (propagate && Object.keys(newValues).length > 0) { | ||
this._subscriptions.forEach(listener => listener(newValues, oldValues, context)); | ||
} | ||
return updated; | ||
return newValues; | ||
} | ||
/** | ||
* Get the schema that describes the state. | ||
* | ||
* @return {Object} | ||
*/ | ||
getSchema() { | ||
return this._schema; | ||
} | ||
/** | ||
* Updates values of the state. | ||
* | ||
* @async | ||
* @param {Object} updates - key / value pairs of updates to apply to the state | ||
* @return {Object} | ||
* @param {Object} updates - key / value pairs of updates to apply to the state. | ||
* @param {Mixed} [context=null] - optionnal context that will be propagated | ||
* alongside the updates of the state. The context is valid only for the | ||
* current call and will be passed as third argument to any subscribe listeners. | ||
* @return {Promise<Object>} A promise to the (coerced) updates. | ||
* | ||
* @see {common.SharedState~subscribeCallback} | ||
*/ | ||
async set(updates) { | ||
async set(updates, context = null) { | ||
// handle immediate option | ||
const immediateNewValues = {}; | ||
const immediateOldValues = {}; | ||
let propagateNow = false; | ||
for (let name in updates) { | ||
// throw early (client-side and not only server-side) if parameter is undefined | ||
if (!this._parameters.has(name)) { | ||
throw new ReferenceError(`[stateManager] Cannot set value of undefined parameter "${name}"`); | ||
} // @note: general idea... | ||
// if immediate=true | ||
// - call listeners if value changed | ||
// - go through normal server path | ||
// - retrigger only if response from server is different from current value | ||
// if immediate=true && (filterChange=false || event=true) | ||
// - call listeners with value regarless it changed | ||
// - go through normal server path | ||
// - if the node is initiator of the update (UPDATE_RESPONSE), (re-)check | ||
// to prevent execute the listeners twice | ||
const { | ||
immediate, | ||
filterChange, | ||
event | ||
} = this._parameters.getSchema(name); | ||
if (immediate) { | ||
const oldValue = this._parameters.get(name); | ||
const [newValue, changed] = this._parameters.set(name, updates[name]); | ||
if (changed || filterChange === false) { | ||
immediateOldValues[name] = oldValue; | ||
immediateNewValues[name] = newValue; | ||
propagateNow = true; | ||
} | ||
} | ||
} | ||
if (propagateNow) { | ||
this._subscriptions.forEach(listener => listener(immediateNewValues, immediateOldValues, context)); | ||
} // go through server-side normal behavior | ||
return new Promise((resolve, reject) => { | ||
const reqId = (0, _sharedStateUtils.storeRequestPromise)(resolve, reject); | ||
this._client.transport.emit(`${_sharedStateUtils.UPDATE_REQUEST}-${this.id}-${this.remoteId}`, reqId, updates); | ||
this._client.transport.emit(`${_sharedStateUtils.UPDATE_REQUEST}-${this.id}-${this.remoteId}`, reqId, updates, context); | ||
}); | ||
@@ -202,3 +263,3 @@ } | ||
* | ||
* @param {String} name - Name of the param | ||
* @param {String} name - Name of the param. Throws an error if the name is invalid. | ||
* @return {Mixed} | ||
@@ -222,5 +283,53 @@ */ | ||
/** | ||
* Get the schema that describes the state. | ||
* | ||
* @param {String} [name=null] - if given, returns only the definition | ||
* of the given param name. Throws an error if the name is invalid. | ||
* @return {Object} | ||
*/ | ||
getSchema(name = null) { | ||
return this._parameters.getSchema(name); | ||
} | ||
/** | ||
* Get the values with which the state has been initialized. | ||
* | ||
* @return {Object} | ||
*/ | ||
getInitValues() { | ||
return this._parameters.getInitValues(); | ||
} | ||
/** | ||
* Get the default values that has been declared in the schema. | ||
* | ||
* @return {Object} | ||
*/ | ||
getDefaults() { | ||
return this._parameters.getDefaults(); | ||
} | ||
/** | ||
* @callback common.SharedState~subscribeCallback | ||
* @param {Object} updates - key / value pairs of the updates that have been | ||
* applied to the state | ||
* @param {Object} newValues - key / value pairs of the updates that have been | ||
* applied to the state. | ||
* @param {Object} oldValues - key / value pairs of the related params before | ||
* the updates has been applied to the state. | ||
* @param {Mixed} [context=null] - Optionnal context data that has been passed | ||
* with the updates in the `set` call. | ||
* | ||
* @example | ||
* state.subscribe(async (newValues, oldValues[, context=null]) => { | ||
* for (let [key, value] of Object.entries(newValues)) { | ||
* switch (key) { | ||
* // do something | ||
* } | ||
* } | ||
* } | ||
* | ||
* @see {common.SharedState#set} | ||
* @see {common.SharedState#subscribe} | ||
*/ | ||
@@ -232,7 +341,10 @@ | ||
* @param {common.SharedState~subscribeCallback} callback - callback to execute | ||
* when an update is commited on the state. | ||
* when an update is applied on the state. | ||
* | ||
* @example | ||
* state.subscribe(async (updates) => { | ||
* for (let [key, value] of Object.entries(updates)) { | ||
* // dispatch | ||
* state.subscribe(async (newValues, oldValues) => { | ||
* for (let [key, value] of Object.entries(newValues)) { | ||
* switch (key) { | ||
* // do something | ||
* } | ||
* } | ||
@@ -267,3 +379,3 @@ * } | ||
if (this._isCreator) { | ||
if (this._isOwner) { | ||
return new Promise((resolve, reject) => { | ||
@@ -283,2 +395,24 @@ const reqId = (0, _sharedStateUtils.storeRequestPromise)(resolve, reject); | ||
/** | ||
* Delete the state. Only the creator/owner of the state (i.e. a state created using | ||
* `create`) can use this method. If a non-owner call this method (i.e. a | ||
* state created using `attach`), an error will be thrown. | ||
* | ||
* @async | ||
* @see {common.SharedState#onDetach} | ||
* @see {common.SharedState#onDelete} | ||
* @see {client.SharedStateManagerClient#create} | ||
* @see {server.SharedStateManagerClient#create} | ||
* @see {client.SharedStateManagerClient#attach} | ||
* @see {server.SharedStateManagerClient#attach} | ||
*/ | ||
async delete() { | ||
if (this._isOwner) { | ||
return this.detach(); | ||
} else { | ||
throw new Error(`[stateManager] can delete state "${this.schemaName}", only owner of the state (i.e. the node that "create[d]" it) can delete it`); | ||
} | ||
} | ||
/** | ||
* Register a function to execute when detaching from the state | ||
@@ -285,0 +419,0 @@ * |
@@ -18,3 +18,3 @@ "use strict"; | ||
* An instance of `SharedStateManagerClient` is automatically created by the | ||
* `soundworks.Client` (cf. {@link client.Client#stateManager}). | ||
* `soundworks.Client` at initialization (cf. {@link client.Client#stateManager}). | ||
* | ||
@@ -21,0 +21,0 @@ * Tutorial: [https://collective-soundworks.github.io/tutorials/state-manager.html](https://collective-soundworks.github.io/tutorials/state-manager.html) |
@@ -10,3 +10,3 @@ "use strict"; | ||
var _parameters = _interopRequireDefault(require("@ircam/parameters")); | ||
var _ParameterBag = _interopRequireDefault(require("./ParameterBag.js")); | ||
@@ -30,4 +30,4 @@ var _lodash = _interopRequireDefault(require("lodash.clonedeep")); | ||
* | ||
* An instance of `SharedStateManagerClient` is automatically created by the | ||
* `soundworks.Server` (cf. {@link server.Server#stateManager}). | ||
* An instance of `SharedStateManagerServer` is automatically created by the | ||
* `soundworks.Server` at initialization (cf. {@link server.Server#stateManager}). | ||
* | ||
@@ -54,2 +54,4 @@ * Tutorial: [https://collective-soundworks.github.io/tutorials/state-manager.html](https://collective-soundworks.github.io/tutorials/state-manager.html) | ||
this._observers = new Set(); | ||
this._hooksBySchemaName = new Map(); // protected | ||
this.addClient(localClientId, localTransport); | ||
@@ -228,7 +230,25 @@ } | ||
/** | ||
* Register a schema. The schema definition follows the convention described | ||
* here [https://github.com/ircam-jstools/parameters#booleandefinition--object](https://github.com/ircam-jstools/parameters#booleandefinition--object) (@todo - document somewhere else). | ||
* Register a schema from which shared states (cf. {@link common.SharedState}) | ||
* can be instanciated. | ||
* | ||
* @param {String} schemaName - Name of the schema. | ||
* @param {Object} schema - Description of the state data structure. | ||
* @param {server.SharedStateManagerServer~schema} schema - Data structure | ||
* describing the states that will be created from this schema. | ||
* | ||
* @see {@link server.SharedStateManagerServer#create} | ||
* @see {@link client.SharedStateManagerClient#create} | ||
* | ||
* @example | ||
* server.stateManager.registerSchema('my-schema', { | ||
* myBoolean: { | ||
* type: 'boolean' | ||
* default: false, | ||
* }, | ||
* myFloat: { | ||
* type: 'float' | ||
* default: 0.1, | ||
* min: -1, | ||
* max: 1 | ||
* } | ||
* }) | ||
*/ | ||
@@ -239,18 +259,17 @@ | ||
if (this._schemas.has(schemaName)) { | ||
throw new Error(`schema "${schemaName}" already registered`); | ||
} // throw is schema is invalid | ||
throw new Error(`[stateManager.registerSchema] cannot register schema with name: "${schemaName}", schema name already exists`); | ||
} | ||
_ParameterBag.default.validateSchema(schema); | ||
try { | ||
(0, _parameters.default)(schema, {}); | ||
} catch (err) { | ||
throw new Error(`Invalid schema "${schemaName}": ${err.message}`); | ||
} | ||
this._schemas.set(schemaName, (0, _lodash.default)(schema)); // create hooks list | ||
this._schemas.set(schemaName, (0, _lodash.default)(schema)); | ||
this._hooksBySchemaName.set(schemaName, new Set()); | ||
} | ||
/** | ||
* Delete a schema and all associated states. | ||
* When a schema is deleted, all attached clients are detached | ||
* and the `onDetach` and `onDelete` callbacks are called. | ||
* When a schema is deleted, all states created from this schema are deleted | ||
* as well, therefore all attached clients are detached and the `onDetach` | ||
* and `onDelete` callbacks are called on the related states. | ||
* | ||
@@ -274,5 +293,63 @@ * @param {String} schemaName - Name of the schema. | ||
this._schemas.delete(schemaName); | ||
this._schemas.delete(schemaName); // delete registered hooks | ||
this._hooksBySchemaName.delete(schemaName); | ||
} | ||
/** | ||
* @callback server.SharedStateManagerServer~updateHook | ||
* | ||
* @param {Object} updates - Update object as given on a set callback, or | ||
* result of the previous hook | ||
* @param {Object} currentValues - Current values of the state. | ||
* @param {Object} [context=null] - Optionnal context passed by the creator | ||
* of the update. | ||
* @return {Object} The "real" updates to be applied on the state. | ||
*/ | ||
/** | ||
* Register a function for a given schema (e.g. will be applied on all states | ||
* created from this schema) that will be executed before the update values | ||
* are propagated. For example, this could be used to implement a preset system | ||
* where all the values of the state are updated from e.g. some data stored in | ||
* filesystem while the consumer of the state only want to update the preset name. | ||
* | ||
* The hook is associated to every state of its kind (i.e. schemaName) and | ||
* executed on every update (call of `set`). Note that the hooks are executed | ||
* server-side regarless the node on which `set` has been called and before | ||
* the "actual" update of the state (e.g. before the call of `subscribe`). | ||
* | ||
* @example | ||
* server.stateManager.registerSchema('hooked', schema); | ||
* server.stateManager.registerUpdateHook('hooked', (updates, currentValues) => { | ||
* return { | ||
* ...updates | ||
* numUpdates: currentValues.numUpdates + 1, | ||
* }; | ||
* }); | ||
* | ||
* const state = await server.stateManager.create('hooked'); | ||
* | ||
* await state.set({ name: 'test' }); | ||
* state.getValues(); | ||
* // > { name: 'test', numUpdates: 1 }; | ||
* | ||
* @param {String} schemaName - Kind of states on which applying the hook. | ||
* @param {server.SharedStateManagerServer~updateHook} updateHook - Function | ||
* called between the `set` call and the actual update. | ||
*/ | ||
registerUpdateHook(schemaName, updateHook) { | ||
// throw error if schemaName has not been registered | ||
if (!this._schemas.has(schemaName)) { | ||
throw new Error(`[stateManager.registerUpdateHook] cannot register update hook for schema name "${schemaName}", schema name does not exists`); | ||
} | ||
const hooks = this._hooksBySchemaName.get(schemaName); | ||
hooks.add(updateHook); | ||
return () => hooks.delete(updateHook); | ||
} | ||
} | ||
@@ -279,0 +356,0 @@ |
@@ -8,6 +8,4 @@ "use strict"; | ||
var _parameters = _interopRequireDefault(require("@ircam/parameters")); | ||
var _ParameterBag = _interopRequireDefault(require("./ParameterBag.js")); | ||
var _lodash = _interopRequireDefault(require("lodash.clonedeep")); | ||
var _sharedStateUtils = require("./shared-state-utils"); | ||
@@ -26,5 +24,4 @@ | ||
this.schemaName = schemaName; | ||
this._schema = (0, _lodash.default)(schema); | ||
this._manager = manager; | ||
this._parameters = (0, _parameters.default)(schema, initValues); | ||
this._parameters = new _ParameterBag.default(schema, initValues); | ||
this._attachedClients = new Map(); // other peers interested in watching / controlling the state | ||
@@ -36,6 +33,6 @@ | ||
_attachClient(remoteId, client, isCreator = false) { | ||
_attachClient(remoteId, client, isOwner = false) { | ||
this._attachedClients.set(remoteId, client); | ||
if (isCreator) { | ||
if (isOwner) { | ||
this._creatorRemoteId = remoteId; | ||
@@ -46,25 +43,42 @@ this._creatorId = client.id; | ||
client.transport.addListener(`${_sharedStateUtils.UPDATE_REQUEST}-${this.id}-${remoteId}`, (reqId, updates) => { | ||
const updated = {}; | ||
let dirty = false; | ||
client.transport.addListener(`${_sharedStateUtils.UPDATE_REQUEST}-${this.id}-${remoteId}`, async (reqId, updates, context) => { | ||
// apply registered hooks | ||
const hooks = this._manager._hooksBySchemaName.get(this.schemaName); | ||
const values = this._parameters.getValues(); // @note: we may need a proper update queue to avoid race conditions | ||
for (let hook of hooks.values()) { | ||
updates = await hook(updates, values, context); | ||
} | ||
const filteredUpdates = {}; | ||
let hasUpdates = false; | ||
for (let name in updates) { | ||
const currentValue = this._parameters.get(name); // get new value this way to store events return values | ||
// from v3.1.0 - the `filteredUpdates` check is made using 'fast-deep-equal' | ||
// cf. https://github.com/epoberezkin/fast-deep-equal | ||
// therefore unchanged objects are not considered changed | ||
// nor propagated anymore. | ||
// until v3.0.4 - we checked the `schema[name].type === 'any'`, to always consider | ||
// objects as dirty, because if the state is attached locally, we | ||
// compare the Object instances instead of their values. | ||
// @note - this should be made more robust but how? | ||
const [newValue, changed] = this._parameters.set(name, updates[name]); // if `filterChange` is set to `false` we don't check if the value | ||
// has been changed or not, it is always propagated to client states | ||
const newValue = this._parameters.set(name, updates[name]); // we check the `schema[name].type === 'any'`, to always consider | ||
// objects as dirty, because if the state is attached locally, we | ||
// compare the Object instances instead of their values. | ||
// @todo - this should be made more robust but how? | ||
const { | ||
filterChange | ||
} = this._parameters.getSchema(name); | ||
if (newValue !== currentValue || this._schema[name].type === 'any') { | ||
updated[name] = newValue; | ||
dirty = true; | ||
if (filterChange && changed || !filterChange) { | ||
filteredUpdates[name] = newValue; | ||
hasUpdates = true; | ||
} | ||
} | ||
if (dirty) { | ||
if (hasUpdates) { | ||
// send response to requester | ||
// client.transport.emit(`${UPDATE_RESPONSE}-${this.id}-${remoteId}`, reqId, updated); | ||
// client.transport.emit(`${UPDATE_RESPONSE}-${this.id}-${remoteId}`, reqId, filteredUpdates); | ||
// @note: we propagate server-side last, because as the server transport | ||
@@ -89,3 +103,3 @@ // is synchronous it can break ordering if a subscription function makes | ||
if (remoteId !== peerRemoteId && peer.id !== -1) { | ||
peer.transport.emit(`${_sharedStateUtils.UPDATE_NOTIFICATION}-${this.id}-${peerRemoteId}`, updated); | ||
peer.transport.emit(`${_sharedStateUtils.UPDATE_NOTIFICATION}-${this.id}-${peerRemoteId}`, filteredUpdates, context); | ||
} | ||
@@ -95,3 +109,3 @@ } | ||
if (client.id !== -1) { | ||
client.transport.emit(`${_sharedStateUtils.UPDATE_RESPONSE}-${this.id}-${remoteId}`, reqId, updated); | ||
client.transport.emit(`${_sharedStateUtils.UPDATE_RESPONSE}-${this.id}-${remoteId}`, reqId, filteredUpdates, context); | ||
} | ||
@@ -102,3 +116,3 @@ | ||
if (remoteId !== peerRemoteId && peer.id === -1) { | ||
peer.transport.emit(`${_sharedStateUtils.UPDATE_NOTIFICATION}-${this.id}-${peerRemoteId}`, updated); | ||
peer.transport.emit(`${_sharedStateUtils.UPDATE_NOTIFICATION}-${this.id}-${peerRemoteId}`, filteredUpdates, context); | ||
} | ||
@@ -108,3 +122,3 @@ } | ||
if (client.id === -1) { | ||
client.transport.emit(`${_sharedStateUtils.UPDATE_RESPONSE}-${this.id}-${remoteId}`, reqId, updated); | ||
client.transport.emit(`${_sharedStateUtils.UPDATE_RESPONSE}-${this.id}-${remoteId}`, reqId, filteredUpdates, context); | ||
} | ||
@@ -114,7 +128,7 @@ } else { | ||
// ignore all other attached clients. | ||
client.transport.emit(`${_sharedStateUtils.UPDATE_ABORT}-${this.id}-${remoteId}`, reqId, updates); | ||
client.transport.emit(`${_sharedStateUtils.UPDATE_ABORT}-${this.id}-${remoteId}`, reqId, updates, context); | ||
} | ||
}); | ||
if (isCreator) { | ||
if (isOwner) { | ||
// delete only if creator | ||
@@ -121,0 +135,0 @@ client.transport.addListener(`${_sharedStateUtils.DELETE_REQUEST}-${this.id}-${remoteId}`, reqId => { |
{ | ||
"name": "@soundworks/core", | ||
"version": "3.0.4", | ||
"version": "3.1.0-beta.0", | ||
"description": "full-stack javascript framework for distributed audio visual experiences on the web", | ||
@@ -21,6 +21,6 @@ "authors": [ | ||
"clean": "rm -Rf client && rm -Rf server && rm -Rf common", | ||
"docs": "rm -Rf docs && jsdoc -c .jsdoc.json --verbose && cp -R assets docs/", | ||
"doc": "rm -Rf docs && jsdoc -c .jsdoc.json --verbose && cp -R assets docs/", | ||
"prepublishOnly": "npm run build", | ||
"toc": "markdown-toc -i README.md", | ||
"version": "npm run toc && npm run docs && git add docs", | ||
"version": "npm run toc && npm run doc && git add docs", | ||
"build:client": "babel src/client --out-dir client", | ||
@@ -36,4 +36,2 @@ "build:server": "babel src/server --out-dir server", | ||
"dependencies": { | ||
"@ircam/parameters": "^1.2.2", | ||
"braintree-jsdoc-template": "^3.3.0", | ||
"chalk": "^2.4.2", | ||
@@ -43,2 +41,3 @@ "columnify": "^1.5.4", | ||
"debug": "^4.1.1", | ||
"fast-deep-equal": "^3.1.3", | ||
"fast-text-encoding": "^1.0.0", | ||
@@ -61,4 +60,4 @@ "isomorphic-ws": "^4.0.1", | ||
"@babel/core": "^7.4.5", | ||
"@babel/plugin-proposal-export-default-from": "^7.5.2", | ||
"@babel/preset-env": "^7.4.5", | ||
"braintree-jsdoc-template": "^3.3.0", | ||
"chai": "^4.2.0", | ||
@@ -65,0 +64,0 @@ "chokidar": "^3.0.1", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
159566
18
28
3960
2
+ Addedfast-deep-equal@^3.1.3
- Removed@ircam/parameters@^1.2.2
- Removedbraintree-jsdoc-template@^3.3.0
- Removed@ircam/parameters@1.2.2(transitive)
- Removedbraintree-jsdoc-template@3.3.0(transitive)