@culturehq/client
Advanced tools
Comparing version 4.1.0 to 5.0.0
@@ -9,2 +9,13 @@ # Changelog | ||
## [5.0.0] - 2018-08-13 | ||
### Added | ||
- The `skipPreflightChecks` named export that handles building an `iframe` to match domains and skip preflight CORS checks. | ||
### Changed | ||
- Build an iframe and change the domain in order to avoid preflight checks. | ||
- Moved the WebSocket exports into their own named exports and out of the main client: `onEventStarting`, `onLeaderboardUpdated`, `onNotificationReceived`, `onRecognitionCreated`, and `onUserActivityCreated`. | ||
- Moved the `autoPaginate` function into its own named export. | ||
- Moved `endUserSimulation`, `isSimulating`, and `startUserSimulation` functions into their own named exports. | ||
- Moved the signed in state functions into their own named exports: `isSignedIn`, `setToken`, `signIn`, and `signOut`. | ||
## [4.1.0] - 2018-08-11 | ||
@@ -11,0 +22,0 @@ ### Added |
@@ -86,6 +86,6 @@ "use strict"; | ||
var API_CALLS = Object.keys(_calls2.default).reduce(function (accum, callName) { | ||
var apiCalls = Object.keys(_calls2.default).reduce(function (accum, callName) { | ||
return _extends({}, accum, _defineProperty({}, callName, buildCall(_calls2.default[callName]))); | ||
}, {}); | ||
exports.default = API_CALLS; | ||
exports.default = apiCalls; |
@@ -6,21 +6,68 @@ "use strict"; | ||
}); | ||
exports.skipPreflightChecks = exports.onUserActivityCreated = exports.onRecognitionCreated = exports.onNotificationReceived = exports.onLeaderboardUpdated = exports.onEventStarting = exports.autoPaginate = exports.startUserSimulation = exports.endUserSimulation = exports.isSimulating = exports.signUpload = exports.signOut = exports.signIn = exports.setToken = exports.isSignedIn = exports.getToken = undefined; | ||
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); | ||
var _signUpload = require("./sign-upload"); | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
Object.defineProperty(exports, "signUpload", { | ||
enumerable: true, | ||
get: function get() { | ||
return _interopRequireDefault(_signUpload).default; | ||
} | ||
}); | ||
var _actioncable = require("actioncable"); | ||
var _autoPaginate = require("./auto-paginate"); | ||
var _actioncable2 = _interopRequireDefault(_actioncable); | ||
Object.defineProperty(exports, "autoPaginate", { | ||
enumerable: true, | ||
get: function get() { | ||
return _interopRequireDefault(_autoPaginate).default; | ||
} | ||
}); | ||
var _apiCalls = require("./api-calls"); | ||
var _cable = require("./cable"); | ||
var _apiCalls2 = _interopRequireDefault(_apiCalls); | ||
Object.defineProperty(exports, "onEventStarting", { | ||
enumerable: true, | ||
get: function get() { | ||
return _cable.onEventStarting; | ||
} | ||
}); | ||
Object.defineProperty(exports, "onLeaderboardUpdated", { | ||
enumerable: true, | ||
get: function get() { | ||
return _cable.onLeaderboardUpdated; | ||
} | ||
}); | ||
Object.defineProperty(exports, "onNotificationReceived", { | ||
enumerable: true, | ||
get: function get() { | ||
return _cable.onNotificationReceived; | ||
} | ||
}); | ||
Object.defineProperty(exports, "onRecognitionCreated", { | ||
enumerable: true, | ||
get: function get() { | ||
return _cable.onRecognitionCreated; | ||
} | ||
}); | ||
Object.defineProperty(exports, "onUserActivityCreated", { | ||
enumerable: true, | ||
get: function get() { | ||
return _cable.onUserActivityCreated; | ||
} | ||
}); | ||
var _autoPaginator = require("./auto-paginator"); | ||
var _fetcher = require("./fetcher"); | ||
var _autoPaginator2 = _interopRequireDefault(_autoPaginator); | ||
Object.defineProperty(exports, "skipPreflightChecks", { | ||
enumerable: true, | ||
get: function get() { | ||
return _fetcher.skipPreflightChecks; | ||
} | ||
}); | ||
var _constants = require("./constants"); | ||
var _apiCalls = require("./api-calls"); | ||
var _apiCalls2 = _interopRequireDefault(_apiCalls); | ||
var _state = require("./state"); | ||
@@ -30,15 +77,9 @@ | ||
var _signUpload = require("./sign-upload"); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var _signUpload2 = _interopRequireDefault(_signUpload); | ||
var createApiKey = _apiCalls2.default.createApiKey, | ||
createSimulation = _apiCalls2.default.createSimulation, | ||
deleteSession = _apiCalls2.default.deleteSession; | ||
var _stringCase = require("./string-case"); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
/** | ||
* An object for handling the connection to and querying of the CultureHQ API. | ||
* Mostly everything is represented in the `calls.json` file, as every call | ||
* listed in that file represents a member function on this class. | ||
* | ||
* == API call semantics == | ||
@@ -67,3 +108,88 @@ * | ||
* }; | ||
*/ | ||
exports.default = _apiCalls2.default; | ||
/** | ||
* == State == | ||
* | ||
* Signed in state is handled through the client using the `signIn` and | ||
* `signOut` functions. These effectively act as normal API calls but with the | ||
* additional functionality of setting or clearing `localStorage` with the | ||
* returned API token. | ||
* | ||
* You can also manually set the API token by using the `setToken` named export. | ||
* This is especially useful if the token is fixed in some context (as in most | ||
* integrations). | ||
*/ | ||
var getToken = _state2.default.getToken, | ||
isSignedIn = _state2.default.isSignedIn, | ||
setToken = _state2.default.setToken; | ||
exports.getToken = getToken; | ||
exports.isSignedIn = isSignedIn; | ||
exports.setToken = setToken; | ||
var signIn = exports.signIn = function signIn(params) { | ||
return createApiKey(params).then(function (response) { | ||
_state2.default.setToken(response.apiKey.token); | ||
return response; | ||
}); | ||
}; | ||
var signOut = exports.signOut = function signOut() { | ||
return deleteSession().then(function (response) { | ||
_state2.default.clear(); | ||
(0, _cable.disconnect)(); | ||
return response; | ||
}); | ||
}; | ||
/** | ||
* == Upload signing == | ||
* | ||
* To support faster uploading, we allow images to be uploaded directly to S3, | ||
* and then just send along the signed URL to the API for fetching. This allows | ||
* API servers to continue processing requests instead of waiting for the upload | ||
* to complete. | ||
* | ||
* To use this mechanism, call this function with a file object and it will | ||
* return a Promise that resolves to the URL of the file that was uploaded, as | ||
* in the following example: | ||
* | ||
* import { signUpload } from "@culturehq/client"; | ||
* | ||
* signUpload(document.querySelector("#file").files[0]).then(url => { | ||
* console.log(url); | ||
* }); | ||
*/ | ||
/** | ||
* == Simulation == | ||
* | ||
* If you're listed as a CultureHQ admin, you can simulate users for debugging | ||
* with read-only capabilities by using the `startUserSimulation` named export. | ||
* The corresponding end call is `endUserSimulation`, along with the check for | ||
* the current state which is `isSimulating`. | ||
*/ | ||
var isSimulating = _state2.default.isSimulating; | ||
exports.isSimulating = isSimulating; | ||
var endUserSimulation = exports.endUserSimulation = function endUserSimulation() { | ||
_state2.default.clearSimulationToken(); | ||
(0, _cable.disconnect)(); | ||
}; | ||
var startUserSimulation = exports.startUserSimulation = function startUserSimulation(params) { | ||
if (!_state2.default.isSignedIn()) { | ||
throw new Error("Cannot simulate unless you're already logged in."); | ||
} | ||
return createSimulation(params).then(function (response) { | ||
_state2.default.setSimulationToken(response.apiKey.token); | ||
(0, _cable.disconnect)(); | ||
return response; | ||
}); | ||
}; | ||
/** | ||
* == Pagination == | ||
@@ -78,145 +204,11 @@ * | ||
* You can handle this pagination manually, e.g., links on the bottom of the | ||
* page. Alternatively, you can use the client's built-in automatic pagination | ||
* capabilities. You prefix your API call with a call to `autoPaginate`, as in | ||
* the following example: | ||
* page. You can also use the client's built-in automatic pagination | ||
* capabilities by using the `autoPaginate` named export, as in the following | ||
* example: | ||
* | ||
* const { events } = await client.autoPaginate("events").listEvents(); | ||
* import { autoPaginate } from "@culturehq/client"; | ||
* const { events } = await autoPaginate("events").listEvents(); | ||
* | ||
* This will return the pagination information as normal, but the events will | ||
* be concatenated together. | ||
* | ||
* == WebSocket connection semantics == | ||
* | ||
* There are a few functions on the client that will establish a WebSocket | ||
* connection and call a callback function when data is received. For these | ||
* functions, in order to avoid leaking memory, it's important to ensure that | ||
* when you're done with the subscription (for instance when the component | ||
* containing it is unmounted) that you call `unsubscribe` on the subscription | ||
* object. An example with React of using these functions is below: | ||
* | ||
* class MyComponent { | ||
* state = { lastNotification: null }; | ||
* | ||
* componentDidMount() { | ||
* this.subscription = client.onNotificationReceived(notification => { | ||
* this.setState({ lastNotification: notification }); | ||
* }); | ||
* } | ||
* | ||
* componentWillUnmount() { | ||
* if (this.subscription) { | ||
* this.subscription.unsubscribe(); | ||
* } | ||
* } | ||
* | ||
* render() { | ||
* const { lastNotification } = this.state; | ||
* | ||
* return <span>{lastNotification}<span>; | ||
* } | ||
* } | ||
*/ | ||
var client = _extends({ | ||
consumer: null, | ||
endUserSimulation: function endUserSimulation() { | ||
_state2.default.endSimulation(); | ||
client.disconnectConsumer(); | ||
}, | ||
isSignedIn: function isSignedIn() { | ||
return _state2.default.isSignedIn(); | ||
}, | ||
isSimulating: function isSimulating() { | ||
return _state2.default.isSimulating(); | ||
}, | ||
onEventStarting: function onEventStarting(callback) { | ||
return client.subscribeToChannel("EventStartingChannel", callback); | ||
}, | ||
onLeaderboardUpdated: function onLeaderboardUpdated(callback) { | ||
return client.subscribeToChannel("LeaderboardChannel", callback); | ||
}, | ||
onNotificationReceived: function onNotificationReceived(callback) { | ||
return client.subscribeToChannel("NotificationChannel", callback); | ||
}, | ||
onRecognitionCreated: function onRecognitionCreated(callback) { | ||
return client.subscribeToChannel("RecognitionChannel", callback); | ||
}, | ||
onUserActivityCreated: function onUserActivityCreated(callback) { | ||
return client.subscribeToChannel("UserActivityChannel", callback); | ||
}, | ||
setToken: function setToken(token) { | ||
return _state2.default.signIn(token); | ||
}, | ||
signIn: function signIn(params) { | ||
return client.createApiKey(params).then(function (response) { | ||
_state2.default.signIn(response.apiKey.token); | ||
return response; | ||
}); | ||
}, | ||
signOut: function signOut() { | ||
return client.deleteSession().then(function (response) { | ||
_state2.default.signOut(); | ||
client.disconnectConsumer(); | ||
return response; | ||
}); | ||
}, | ||
signUpload: _signUpload2.default, | ||
startUserSimulation: function startUserSimulation(params) { | ||
return client.createSimulation(params).then(function (response) { | ||
_state2.default.startSimulation(response.apiKey.token); | ||
client.disconnectConsumer(); | ||
return response; | ||
}); | ||
}, | ||
autoPaginate: function autoPaginate(dataType) { | ||
return new _autoPaginator2.default(dataType); | ||
}, | ||
disconnectConsumer: function disconnectConsumer() { | ||
if (client.consumer) { | ||
client.consumer.disconnect(); | ||
client.consumer = null; | ||
} | ||
}, | ||
ensureConsumer: function ensureConsumer() { | ||
if (client.consumer) { | ||
return client.consumer; | ||
} | ||
var _API_HOST$split = _constants.API_HOST.split("://"), | ||
_API_HOST$split2 = _slicedToArray(_API_HOST$split, 2), | ||
protocol = _API_HOST$split2[0], | ||
host = _API_HOST$split2[1]; | ||
var wsProtocol = protocol === "https" ? "wss" : "ws"; | ||
var endpoint = wsProtocol + "://" + host + "/cable/" + _state2.default.getToken(); | ||
client.consumer = _actioncable2.default.createConsumer(endpoint); | ||
return client.consumer; | ||
}, | ||
subscribeToChannel: function subscribeToChannel(channel, callback) { | ||
return client.ensureConsumer().subscriptions.create(channel, { | ||
received: function received(data) { | ||
return callback((0, _stringCase.camelize)(data)); | ||
} | ||
}); | ||
} | ||
}, _apiCalls2.default); | ||
exports.default = client; | ||
*/ |
@@ -7,4 +7,6 @@ "use strict"; | ||
var _stringCase = require("./string-case"); | ||
var _fetcher = require("./fetcher"); | ||
var _fetcher2 = _interopRequireDefault(_fetcher); | ||
var _formData = require("./form-data"); | ||
@@ -18,2 +20,4 @@ | ||
var _stringCase = require("./string-case"); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -26,3 +30,3 @@ | ||
var headers = { "X-Client-Version": "4.1.0" }; | ||
var headers = { "X-Client-Version": "5.0.0" }; | ||
@@ -75,5 +79,5 @@ if (!multipart) { | ||
var request = buildRequest(method, url, options); | ||
return fetch(request.url, request.options).then(_response2.default); | ||
return _fetcher2.default.fetch(request.url, request.options).then(_response2.default); | ||
}; | ||
exports.default = performRequest; |
@@ -10,4 +10,8 @@ "use strict"; | ||
var state = { | ||
endSimulation: function endSimulation() { | ||
state.signIn(localStorage.getItem(SIMULATION_KEY)); | ||
clear: function clear() { | ||
return localStorage.clear(); | ||
}, | ||
clearSimulationToken: function clearSimulationToken() { | ||
state.setToken(localStorage.getItem(SIMULATION_KEY)); | ||
localStorage.removeItem(SIMULATION_KEY); | ||
@@ -32,17 +36,9 @@ }, | ||
signIn: function signIn(token) { | ||
return localStorage.setItem(TOKEN_KEY, token); | ||
setSimulationToken: function setSimulationToken(token) { | ||
localStorage.setItem(SIMULATION_KEY, state.getToken()); | ||
state.setToken(token); | ||
}, | ||
signOut: function signOut() { | ||
return localStorage.clear(); | ||
}, | ||
startSimulation: function startSimulation(token) { | ||
if (!state.isSignedIn()) { | ||
throw new Error("Cannot simulate unless you're already logged in."); | ||
} | ||
localStorage.setItem(SIMULATION_KEY, state.getToken()); | ||
state.signIn(token); | ||
setToken: function setToken(token) { | ||
return localStorage.setItem(TOKEN_KEY, token); | ||
} | ||
@@ -49,0 +45,0 @@ }; |
{ | ||
"name": "@culturehq/client", | ||
"version": "4.1.0", | ||
"version": "5.0.0", | ||
"description": "A JavaScript client that wraps the CultureHQ API", | ||
@@ -34,3 +34,3 @@ "main": "dist/client.js", | ||
"eslint-config-airbnb": "^17.0.0", | ||
"eslint-plugin-import": "^2.12.0", | ||
"eslint-plugin-import": "^2.14.0", | ||
"eslint-plugin-jsx-a11y": "^6.1.1", | ||
@@ -40,3 +40,3 @@ "eslint-plugin-react": "^7.10.0", | ||
"isomorphic-form-data": "^2.0.0", | ||
"jest": "^23.4.2", | ||
"jest": "^23.5.0", | ||
"packfiles": "^0.0.2", | ||
@@ -43,0 +43,0 @@ "prettier": "^1.14.0", |
103582
19
1623
1