diff --git a/.gitignore b/.gitignore
index 871a42f3e..11aaa5cd1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,7 +25,7 @@ node_modules
.DS_Store
-.env
+.env*
.vscode
# Ignore all build output
diff --git a/.travis.yml b/.travis.yml
index 86cdb85b2..227f96e2d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,8 +14,6 @@ matrix:
- '6'
env:
- 'CAN_DEPLOY=true'
- - node_js:
- - '4'
before_install:
- npm -g install npm@4
script:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 85839dead..7685e8be2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
This project adheres to [Semantic Versioning](http://semver.org/).
+## v7.0.0 - 2017-10-12
+
+* *BREAKING*: Remove device.ensureSupervisorCompatibility - use semver directly instead #420 [Tim Perry]
+* Fix breaking bugs in device.enable/disableTcpPing #420 [Tim Perry]
+* Make device.update options optional #420 [Tim Perry]
+* *BREAKING*: Upgrade to API v3. Main change is that all relationships & result properties now include verbs (e.g. device.application is now device.belongs_to__application). #420 [Tim Perry]
+* *BREAKING*: Tie the SDK to a specific API version (removing `apiVersion` option) #420 [Tim Perry]
+* *BREAKING*: Stop actively supporting node 4. #420 [Tim Perry]
+* Change device registration to use a provisioning key #420 [Tim Perry]
+* *BREAKING*: Remove (already deprecated) models.application.getApiKey() #420 [Tim Perry]
+* *BREAKING*: Rename getAppWithOwner to getAppByOwner #420 [Tim Perry]
+* *BREAKING*: Don't allow creating applications with discontinued device types #420 [Tim Perry]
+* Make device.move throw ResinInvalidDeviceType for incompatible device types (not just Error) #420 [Tim Perry]
+* *BREAKING*: Don't expand relationships by default. Pass { expand: '...' } options to opt in instead. #420 [Tim Perry]
+* *BREAKING*: Remove device.application_name and device.dashboard_url #420 [Tim Perry]
+* *BREAKING*: Remove application.online_devices and application.device_length #420 [Tim Perry]
+
## v6.15.0 - 2017-10-12
* Add application.generateProvisioningKey() #419 [Tim Perry]
diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md
index f0a85c853..60eb8a5e9 100644
--- a/DOCUMENTATION.md
+++ b/DOCUMENTATION.md
@@ -20,7 +20,7 @@ If you feel something is missing, not clear or could be improved, please don't h
* [.application](#resin.models.application) : object
* [.getAll([options])](#resin.models.application.getAll) ⇒ Promise
* [.get(nameOrId, [options])](#resin.models.application.get) ⇒ Promise
- * [.getAppWithOwner(appName, owner, [options])](#resin.models.application.getAppWithOwner) ⇒ Promise
+ * [.getAppByOwner(appName, owner, [options])](#resin.models.application.getAppByOwner) ⇒ Promise
* [.has(nameOrId)](#resin.models.application.has) ⇒ Promise
* [.hasAny()](#resin.models.application.hasAny) ⇒ Promise
* ~~[.getById(id)](#resin.models.application.getById) ⇒ Promise
~~
@@ -32,7 +32,6 @@ If you feel something is missing, not clear or could be improved, please don't h
* [.purge(appId)](#resin.models.application.purge) ⇒ Promise
* [.shutdown(appId, [options])](#resin.models.application.shutdown) ⇒ Promise
* [.reboot(appId, [options])](#resin.models.application.reboot) ⇒ Promise
- * ~~[.getApiKey(nameOrId)](#resin.models.application.getApiKey) ⇒ Promise
~~
* [.enableDeviceUrls(nameOrId)](#resin.models.application.enableDeviceUrls) ⇒ Promise
* [.disableDeviceUrls(nameOrId)](#resin.models.application.disableDeviceUrls) ⇒ Promise
* [.grantSupportAccess(nameOrId, expiryTimestamp)](#resin.models.application.grantSupportAccess) ⇒ Promise
@@ -235,7 +234,7 @@ in the SDK.
resin.pine.get({
resource: 'build/$count',
options: {
- filter: { application: applicationId }
+ filter: { belongs_to__application: applicationId }
}
});
```
@@ -269,7 +268,7 @@ resin.models.device.get(123).catch(function (error) {
* [.application](#resin.models.application) : object
* [.getAll([options])](#resin.models.application.getAll) ⇒ Promise
* [.get(nameOrId, [options])](#resin.models.application.get) ⇒ Promise
- * [.getAppWithOwner(appName, owner, [options])](#resin.models.application.getAppWithOwner) ⇒ Promise
+ * [.getAppByOwner(appName, owner, [options])](#resin.models.application.getAppByOwner) ⇒ Promise
* [.has(nameOrId)](#resin.models.application.has) ⇒ Promise
* [.hasAny()](#resin.models.application.hasAny) ⇒ Promise
* ~~[.getById(id)](#resin.models.application.getById) ⇒ Promise
~~
@@ -281,7 +280,6 @@ resin.models.device.get(123).catch(function (error) {
* [.purge(appId)](#resin.models.application.purge) ⇒ Promise
* [.shutdown(appId, [options])](#resin.models.application.shutdown) ⇒ Promise
* [.reboot(appId, [options])](#resin.models.application.reboot) ⇒ Promise
- * ~~[.getApiKey(nameOrId)](#resin.models.application.getApiKey) ⇒ Promise
~~
* [.enableDeviceUrls(nameOrId)](#resin.models.application.enableDeviceUrls) ⇒ Promise
* [.disableDeviceUrls(nameOrId)](#resin.models.application.disableDeviceUrls) ⇒ Promise
* [.grantSupportAccess(nameOrId, expiryTimestamp)](#resin.models.application.grantSupportAccess) ⇒ Promise
@@ -379,7 +377,7 @@ resin.models.device.get(123).catch(function (error) {
* [.application](#resin.models.application) : object
* [.getAll([options])](#resin.models.application.getAll) ⇒ Promise
* [.get(nameOrId, [options])](#resin.models.application.get) ⇒ Promise
- * [.getAppWithOwner(appName, owner, [options])](#resin.models.application.getAppWithOwner) ⇒ Promise
+ * [.getAppByOwner(appName, owner, [options])](#resin.models.application.getAppByOwner) ⇒ Promise
* [.has(nameOrId)](#resin.models.application.has) ⇒ Promise
* [.hasAny()](#resin.models.application.hasAny) ⇒ Promise
* ~~[.getById(id)](#resin.models.application.getById) ⇒ Promise
~~
@@ -391,7 +389,6 @@ resin.models.device.get(123).catch(function (error) {
* [.purge(appId)](#resin.models.application.purge) ⇒ Promise
* [.shutdown(appId, [options])](#resin.models.application.shutdown) ⇒ Promise
* [.reboot(appId, [options])](#resin.models.application.reboot) ⇒ Promise
- * ~~[.getApiKey(nameOrId)](#resin.models.application.getApiKey) ⇒ Promise
~~
* [.enableDeviceUrls(nameOrId)](#resin.models.application.enableDeviceUrls) ⇒ Promise
* [.disableDeviceUrls(nameOrId)](#resin.models.application.disableDeviceUrls) ⇒ Promise
* [.grantSupportAccess(nameOrId, expiryTimestamp)](#resin.models.application.grantSupportAccess) ⇒ Promise
@@ -454,9 +451,9 @@ resin.models.application.get('MyApp', function(error, application) {
console.log(application);
});
```
-
+
-##### application.getAppWithOwner(appName, owner, [options]) ⇒ Promise
+##### application.getAppByOwner(appName, owner, [options]) ⇒ Promise
**Kind**: static method of [application](#resin.models.application)
**Summary**: Get a single application using the appname and owner's username
**Access**: public
@@ -470,7 +467,7 @@ resin.models.application.get('MyApp', function(error, application) {
**Example**
```js
-resin.models.application.getAppWithOwner('MyApp', 'MyUser').then(function(application) {
+resin.models.application.getAppByOwner('MyApp', 'MyUser').then(function(application) {
console.log(application);
});
```
@@ -768,21 +765,6 @@ resin.models.application.reboot(123, function(error) {
if (error) throw error;
});
```
-
-
-##### ~~application.getApiKey(nameOrId) ⇒ Promise
~~
-***Deprecated***
-
-**Kind**: static method of [application](#resin.models.application)
-**Summary**: Get an API key for a specific application
-**Access**: public
-**Fulfil**: String
- api key
-**See**: [generateApiKey](#resin.models.application.generateApiKey)
-
-| Param | Type | Description |
-| --- | --- | --- |
-| nameOrId | String
\| Number
| application name (string) or id (number) |
-
##### application.enableDeviceUrls(nameOrId) ⇒ Promise
@@ -3726,7 +3708,6 @@ startup and before any calls to `fromSharedOptions()` are made.
resin.setSharedOptions({
apiUrl: 'https://api.resin.io/',
imageMakerUrl: 'https://img.resin.io/',
- apiVersion: 'v2',
isBrowser: true,
});
```
diff --git a/README.md b/README.md
index 11f2d715e..26a33c6e0 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,8 @@ $ npm install --save resin-sdk
Platforms
---------
-We currently support NodeJS and the browser.
+We currently support NodeJS (6+) and the browser.
+
The following features are node-only:
- OS image streaming download (`resin.models.os.download`),
- resin settings client (`resin.settings`).
@@ -63,7 +64,6 @@ var resin = require('resin-sdk')({
Where the factory method accepts the following options:
* `apiUrl`, string, *optional*, is the resin.io API url. Defaults to `https://api.resin.io/`,
-* `apiVersion`, string, *optional*, is the version of the API to talk to, like `v2`. Defaults to the current stable version: `v2`,
* `apiKey`, string, *optional*, is the API key to make the requests with,
* `imageMakerUrl`, string, *optional*, is the resin.io image maker url. Defaults to `https://img.resin.io/`,
* `dataDirectory`, string, *optional*, *ignored in the browser*, is the directory where the user settings are stored, normally retrieved like `require('resin-settings-client').get('dataDirectory')`. Defaults to `$HOME/.resin`,
diff --git a/appveyor.yml b/appveyor.yml
index 49a7af57f..3ca352f53 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -14,13 +14,13 @@ matrix:
# what combinations to test
environment:
matrix:
- - nodejs_version: 6
+ - nodejs_version: 8
RESINTEST_EMAIL: 'test2+juan@resin.io'
RESINTEST_USERNAME: 'test2_juan'
RESINTEST_USERID: 5616
RESINTEST_REGISTER_EMAIL: 'test2+register+juan@resin.io'
RESINTEST_REGISTER_USERNAME: 'test2_register_juan'
- - nodejs_version: 4
+ - nodejs_version: 6
RESINTEST_EMAIL: 'test3+juan@resin.io'
RESINTEST_USERNAME: 'test3_juan'
RESINTEST_USERID: 8717
diff --git a/lib/models/application.coffee b/lib/models/application.coffee
index 0caec36d0..619ba42c1 100644
--- a/lib/models/application.coffee
+++ b/lib/models/application.coffee
@@ -55,8 +55,8 @@ getApplicationModel = (deps, opts) ->
exports._getId = getId
normalizeApplication = (application) ->
- if isArray(application.device)
- forEach application.device, (device) ->
+ if isArray(application.owns__device)
+ forEach application.owns__device, (device) ->
normalizeDeviceOsVersion(device)
return application
@@ -91,16 +91,11 @@ getApplicationModel = (deps, opts) ->
options:
mergePineOptions
orderby: 'app_name asc'
- expand: 'device'
filter:
user: userId
, options
- # TODO: It might be worth to do all these handy
- # manipulations server side directly.
.map (application) ->
- application.online_devices = filter(application.device, is_online: true).length
- application.devices_length = application.device?.length or 0
normalizeApplication(application)
return application
@@ -169,7 +164,7 @@ getApplicationModel = (deps, opts) ->
###*
# @summary Get a single application using the appname and owner's username
- # @name getAppWithOwner
+ # @name getAppByOwner
# @public
# @function
# @memberof resin.models.application
@@ -181,11 +176,11 @@ getApplicationModel = (deps, opts) ->
# @returns {Promise}
#
# @example
- # resin.models.application.getAppWithOwner('MyApp', 'MyUser').then(function(application) {
+ # resin.models.application.getAppByOwner('MyApp', 'MyUser').then(function(application) {
# console.log(application);
# });
###
- exports.getAppWithOwner = (appName, owner, options = {}, callback) ->
+ exports.getAppByOwner = (appName, owner, options = {}, callback) ->
callback = findCallback(arguments)
appName = appName.toLowerCase()
@@ -199,15 +194,14 @@ getApplicationModel = (deps, opts) ->
$eq: [
$tolower: $: 'app_name'
appName
- ]
- expand:
+ ],
user:
- $filter:
- $eq: [
+ $any:
+ $alias: 'u',
+ $expr: $eq: [
$tolower: $: 'username'
owner
]
- $select: 'id'
, options
.tap (applications) ->
if isEmpty(applications)
@@ -349,15 +343,18 @@ getApplicationModel = (deps, opts) ->
else
Promise.resolve()
- deviceSlugPromise = deviceModel().getDeviceSlug(deviceType)
- .tap (deviceSlug) ->
- if not deviceSlug?
+ deviceManifestPromise = deviceModel().getManifestBySlug(deviceType)
+ .tap (deviceManifest) ->
+ if not deviceManifest?
throw new errors.ResinInvalidDeviceType(deviceType)
- return Promise.all([ deviceSlugPromise, parentAppPromise ])
- .then ([ deviceSlug, parentApplication ]) ->
+ return Promise.all([ deviceManifestPromise, parentAppPromise ])
+ .then ([ deviceManifest, parentApplication ]) ->
+ if deviceManifest.state == 'DISCONTINUED'
+ throw new errors.ResinDiscontinuedDeviceType(deviceType)
+
extraOptions = if parentApplication
- application: parentApplication.id
+ depends_on__application: parentApplication.id
else {}
return pine.post
@@ -365,7 +362,7 @@ getApplicationModel = (deps, opts) ->
body:
assign
app_name: name
- device_type: deviceSlug
+ device_type: deviceManifest.slug
, extraOptions
.asCallback(callback)
@@ -614,22 +611,6 @@ getApplicationModel = (deps, opts) ->
throw err
.asCallback(callback)
- ###*
- # @summary Get an API key for a specific application
- # @name getApiKey
- # @public
- # @function
- # @memberof resin.models.application
- #
- # @param {String|Number} nameOrId - application name (string) or id (number)
- # @fulfil {String} - api key
- # @returns {Promise}
- #
- # @deprecated Use generateApiKey instead
- # @see {@link resin.models.application.generateApiKey}
- ###
- exports.getApiKey = exports.generateApiKey
-
###*
# @summary Enable device urls for all devices that belong to an application
# @name enableDeviceUrls
@@ -659,7 +640,7 @@ getApplicationModel = (deps, opts) ->
is_web_accessible: true
options:
filter:
- application: id
+ belongs_to__application: id
.asCallback(callback)
###*
@@ -691,7 +672,7 @@ getApplicationModel = (deps, opts) ->
is_web_accessible: false
options:
filter:
- application: id
+ belongs_to__application: id
.asCallback(callback)
###*
@@ -724,7 +705,7 @@ getApplicationModel = (deps, opts) ->
return pine.patch
resource: 'application'
id: applicationId
- body: support_expiry_date: expiryTimestamp
+ body: is_accessible_by_support_until__date: expiryTimestamp
.catch(notFoundResponse, treatAsMissingApplication(nameOrId))
.asCallback(callback)
@@ -754,7 +735,7 @@ getApplicationModel = (deps, opts) ->
return pine.patch
resource: 'application'
id: applicationId
- body: support_expiry_date: null
+ body: is_accessible_by_support_until__date: null
.catch(notFoundResponse, treatAsMissingApplication(nameOrId))
.asCallback(callback)
diff --git a/lib/models/build.coffee b/lib/models/build.coffee
index 79c568397..ace9ae8cf 100644
--- a/lib/models/build.coffee
+++ b/lib/models/build.coffee
@@ -98,7 +98,7 @@ getBuildModel = (deps, opts) ->
options:
mergePineOptions
filter:
- application: id
+ belongs_to__application: id
select: [
'id'
'created_at'
@@ -113,12 +113,6 @@ getBuildModel = (deps, opts) ->
'message'
# 'log' # We *don't* include logs by default, since it's usually huge.
]
- expand:
- user:
- $select: [
- 'id'
- 'username'
- ]
orderby: 'created_at desc'
, options
.asCallback(callback)
diff --git a/lib/models/device.coffee b/lib/models/device.coffee
index d23a71241..b0bc7f275 100644
--- a/lib/models/device.coffee
+++ b/lib/models/device.coffee
@@ -28,7 +28,17 @@ semver = require('semver')
errors = require('resin-errors')
deviceStatus = require('resin-device-status')
-{ onlyIf, isId, findCallback, mergePineOptions, notFoundResponse, treatAsMissingDevice, LOCKED_STATUS_CODE, timeSince } = require('../util')
+{
+ onlyIf,
+ isId,
+ findCallback,
+ mergePineOptions,
+ notFoundResponse,
+ noDeviceForKeyResponse,
+ treatAsMissingDevice,
+ LOCKED_STATUS_CODE,
+ timeSince
+} = require('../util')
{ normalizeDeviceOsVersion } = require('../util/device-os-version')
# The min version where /apps API endpoints are implemented is 1.8.0 but we'll
@@ -91,7 +101,7 @@ getDeviceModel = (deps, opts) ->
# console.log('Is compatible');
# });
###
- exports.ensureSupervisorCompatibility = ensureSupervisorCompatibility = Promise.method (version, minVersion) ->
+ ensureSupervisorCompatibility = Promise.method (version, minVersion) ->
if semver.lt(version, minVersion)
throw new Error("Incompatible supervisor version: #{version} - must be >= #{minVersion}")
@@ -117,9 +127,6 @@ getDeviceModel = (deps, opts) ->
return url.resolve(dashboardUrl, "/apps/#{options.appId}/devices/#{options.deviceId}/summary")
addExtraInfo = (device) ->
- # TODO: Move this to the server
- device.application_name = device.application[0].app_name
- device.dashboard_url = getDashboardUrl({ appId: device.application[0].id, deviceId: device.id })
normalizeDeviceOsVersion(device)
return device
@@ -152,7 +159,6 @@ getDeviceModel = (deps, opts) ->
resource: 'device'
options:
mergePineOptions
- expand: 'application'
orderby: 'name asc'
, options
@@ -192,7 +198,7 @@ getDeviceModel = (deps, opts) ->
applicationModel().get(nameOrId, select: 'id').then ({ id }) ->
exports.getAll(mergePineOptions(
- filter: application: id
+ filter: belongs_to__application: id
options
), callback)
@@ -229,7 +235,7 @@ getDeviceModel = (deps, opts) ->
exports.get(parentUuidOrId, select: 'id').then ({ id }) ->
exports.getAll(mergePineOptions(
- filter: device: id
+ filter: is_managed_by__device: id
options
), callback)
@@ -272,10 +278,7 @@ getDeviceModel = (deps, opts) ->
pine.get
resource: 'device'
id: uuidOrId
- options:
- mergePineOptions
- expand: 'application'
- , options
+ options: options
.tap (device) ->
if not device?
throw new errors.ResinDeviceNotFound(uuidOrId)
@@ -284,7 +287,6 @@ getDeviceModel = (deps, opts) ->
resource: 'device'
options:
mergePineOptions
- expand: 'application'
filter:
uuid: $startswith: uuidOrId
, options
@@ -389,7 +391,12 @@ getDeviceModel = (deps, opts) ->
# });
###
exports.getApplicationName = (uuidOrId, callback) ->
- exports.get(uuidOrId, select: 'application_name').get('application_name').asCallback(callback)
+ exports.get uuidOrId,
+ select: 'id'
+ expand: belongs_to__application: $select: 'app_name'
+ .then (device) ->
+ device.belongs_to__application[0].app_name
+ .asCallback(callback)
###*
# @summary Get application container information
@@ -419,9 +426,12 @@ getDeviceModel = (deps, opts) ->
# });
###
exports.getApplicationInfo = (uuidOrId, callback) ->
- exports.get(uuidOrId).then (device) ->
+ exports.get uuidOrId,
+ select: ['id', 'supervisor_version']
+ expand: belongs_to__application: $select: 'id'
+ .then (device) ->
ensureSupervisorCompatibility(device.supervisor_version, MIN_SUPERVISOR_APPS_API).then ->
- appId = device.application[0].id
+ appId = device.belongs_to__application[0].id
return request.send
method: 'POST'
url: "/supervisor/v1/apps/#{appId}"
@@ -770,12 +780,12 @@ getDeviceModel = (deps, opts) ->
.then ({ application, device }) ->
if device.device_type isnt application.device_type
- throw new Error("Incompatible application: #{applicationNameOrId}")
+ throw new errors.ResinInvalidDeviceType("Incompatible application: #{applicationNameOrId}")
return pine.patch
resource: 'device'
body:
- application: application.id
+ belongs_to__application: application.id
options:
filter:
uuid: device.uuid
@@ -810,9 +820,12 @@ getDeviceModel = (deps, opts) ->
# });
###
exports.startApplication = (uuidOrId, callback) ->
- exports.get(uuidOrId).then (device) ->
+ exports.get uuidOrId,
+ select: ['id', 'supervisor_version']
+ expand: belongs_to__application: $select: 'id'
+ .then (device) ->
ensureSupervisorCompatibility(device.supervisor_version, MIN_SUPERVISOR_APPS_API).then ->
- appId = device.application[0].id
+ appId = device.belongs_to__application[0].id
return request.send
method: 'POST'
url: "/supervisor/v1/apps/#{appId}/start"
@@ -853,9 +866,12 @@ getDeviceModel = (deps, opts) ->
# });
###
exports.stopApplication = (uuidOrId, callback) ->
- exports.get(uuidOrId).then (device) ->
+ exports.get uuidOrId,
+ select: ['id', 'supervisor_version']
+ expand: belongs_to__application: $select: 'id'
+ .then (device) ->
ensureSupervisorCompatibility(device.supervisor_version, MIN_SUPERVISOR_APPS_API).then ->
- appId = device.application[0].id
+ appId = device.belongs_to__application[0].id
return request.send
method: 'POST'
url: "/supervisor/v1/apps/#{appId}/stop"
@@ -975,14 +991,17 @@ getDeviceModel = (deps, opts) ->
exports.shutdown = (uuidOrId, options = {}, callback) ->
callback = findCallback(arguments)
- exports.get(uuidOrId).then (device) ->
+ exports.get uuidOrId,
+ select: 'id'
+ expand: belongs_to__application: $select: 'id'
+ .then (device) ->
return request.send
method: 'POST'
url: '/supervisor/v1/shutdown'
baseUrl: apiUrl
body:
deviceId: device.id
- appId: device.application[0].id
+ appId: device.belongs_to__application[0].id
data:
force: Boolean(options.force)
.catch (err) ->
@@ -1017,16 +1036,19 @@ getDeviceModel = (deps, opts) ->
# });
###
exports.purge = (uuidOrId, callback) ->
- exports.get(uuidOrId).then (device) ->
+ exports.get uuidOrId,
+ select: 'id'
+ expand: belongs_to__application: $select: 'id'
+ .then (device) ->
return request.send
method: 'POST'
url: '/supervisor/v1/purge'
baseUrl: apiUrl
body:
deviceId: device.id
- appId: device.application[0].id
+ appId: device.belongs_to__application[0].id
data:
- appId: device.application[0].id
+ appId: device.belongs_to__application[0].id
.catch (err) ->
if err.statusCode == LOCKED_STATUS_CODE
throw new errors.ResinSupervisorLockedError()
@@ -1063,15 +1085,20 @@ getDeviceModel = (deps, opts) ->
# if (error) throw error;
# });
###
- exports.update = (uuidOrId, options, callback) ->
- exports.get(uuidOrId).then (device) ->
+ exports.update = (uuidOrId, options = {}, callback) ->
+ callback = findCallback(arguments)
+
+ exports.get uuidOrId,
+ select: 'id'
+ expand: belongs_to__application: $select: 'id'
+ .then (device) ->
return request.send
method: 'POST'
url: '/supervisor/v1/update'
baseUrl: apiUrl
body:
deviceId: device.id
- appId: device.application[0].id
+ appId: device.belongs_to__application[0].id
data:
force: Boolean(options.force)
.asCallback(callback)
@@ -1300,7 +1327,7 @@ getDeviceModel = (deps, opts) ->
exports.register = (applicationNameOrId, uuid, callback) ->
Promise.props
userId: auth.getUserId()
- apiKey: applicationModel().getApiKey(applicationNameOrId)
+ apiKey: applicationModel().generateProvisioningKey(applicationNameOrId)
application: applicationModel().get(applicationNameOrId, select: ['id', 'device_type'])
.then ({ userId, apiKey, application }) ->
@@ -1347,14 +1374,7 @@ getDeviceModel = (deps, opts) ->
url: "/api-key/device/#{deviceId}/device-key"
baseUrl: apiUrl
.get('body')
- .catch(
- {
- code: 'ResinRequestError'
- statusCode: 500
- body: 'No device found to associate with the api key'
- }
- treatAsMissingDevice(uuidOrId)
- )
+ .catch(noDeviceForKeyResponse, treatAsMissingDevice(uuidOrId))
.asCallback(callback)
###*
@@ -1523,14 +1543,17 @@ getDeviceModel = (deps, opts) ->
# });
###
exports.enableTcpPing = (uuidOrId, callback) ->
- exports.get(uuidOrId).then (device) ->
+ exports.get uuidOrId,
+ select: 'id'
+ expand: belongs_to__application: $select: 'id'
+ .then (device) ->
return request.send
method: 'POST'
url: '/supervisor/v1/tcp-ping'
baseUrl: apiUrl
- data:
+ body:
deviceId: device.id
- appId: device.application[0].id
+ appId: device.belongs_to__application[0].id
.get('body')
.asCallback(callback)
@@ -1560,14 +1583,18 @@ getDeviceModel = (deps, opts) ->
# });
###
exports.disableTcpPing = (uuidOrId, callback) ->
- exports.get(uuidOrId).then (device) ->
+ exports.get uuidOrId,
+ select: 'id'
+ expand: belongs_to__application: $select: 'id'
+ .then (device) ->
return request.send
- method: 'DELETE'
+ method: 'POST'
url: '/supervisor/v1/tcp-ping'
baseUrl: apiUrl
- data:
+ body:
+ method: 'DELETE'
deviceId: device.id
- appId: device.application[0].id
+ appId: device.belongs_to__application[0].id
.get('body')
.asCallback(callback)
@@ -1596,7 +1623,10 @@ getDeviceModel = (deps, opts) ->
# });
###
exports.ping = (uuidOrId, callback) ->
- exports.get(uuidOrId).then (device) ->
+ exports.get uuidOrId,
+ select: 'id'
+ expand: belongs_to__application: $select: 'id'
+ .then (device) ->
return request.send
method: 'POST'
url: '/supervisor/ping'
@@ -1604,7 +1634,7 @@ getDeviceModel = (deps, opts) ->
body:
method: 'GET'
deviceId: device.id
- appId: device.application[0].id
+ appId: device.belongs_to__application[0].id
.asCallback(callback)
###*
@@ -1664,7 +1694,7 @@ getDeviceModel = (deps, opts) ->
return pine.patch
resource: 'device'
id: id
- body: support_expiry_date: expiryTimestamp
+ body: is_accessible_by_support_until__date: expiryTimestamp
.asCallback(callback)
###*
@@ -1693,7 +1723,7 @@ getDeviceModel = (deps, opts) ->
return pine.patch
resource: 'device'
id: id
- body: support_expiry_date: null
+ body: is_accessible_by_support_until__date: null
.asCallback(callback)
###*
diff --git a/lib/models/environment-variables.coffee b/lib/models/environment-variables.coffee
index 2532a5ae7..c7b13cc3c 100644
--- a/lib/models/environment-variables.coffee
+++ b/lib/models/environment-variables.coffee
@@ -229,9 +229,7 @@ getEnvironmentVariablesModel = (deps, opts) ->
return pine.get
resource: 'device_environment_variable'
options:
- filter:
- device: id
- expand: 'device'
+ filter: device: id
orderby: 'env_var_name asc'
.map(fixDeviceEnvVarNameKey)
.asCallback(callback)
@@ -272,8 +270,7 @@ getEnvironmentVariablesModel = (deps, opts) ->
device:
$any:
$alias: 'd',
- $expr: d: application: id
- expand: 'device'
+ $expr: d: belongs_to__application: id
orderby: 'env_var_name asc'
.map(fixDeviceEnvVarNameKey)
.asCallback(callback)
diff --git a/lib/resin.coffee b/lib/resin.coffee
index 8ede5d8ff..065596fde 100644
--- a/lib/resin.coffee
+++ b/lib/resin.coffee
@@ -78,9 +78,11 @@ getSdk = (opts = {}) ->
defaults opts,
apiUrl: 'https://api.resin.io/'
imageMakerUrl: 'https://img.resin.io/'
- apiVersion: 'v2'
isBrowser: window?
+ # You cannot externally set the API version (as SDK implementation depends on it)
+ opts.apiVersion = 'v3'
+
if opts.isBrowser
settings =
get: notImplemented
@@ -205,7 +207,7 @@ getSdk = (opts = {}) ->
# resin.pine.get({
# resource: 'build/$count',
# options: {
- # filter: { application: applicationId }
+ # filter: { belongs_to__application: applicationId }
# }
# });
###
@@ -255,7 +257,6 @@ getSdk = (opts = {}) ->
# resin.setSharedOptions({
# apiUrl: 'https://api.resin.io/',
# imageMakerUrl: 'https://img.resin.io/',
-# apiVersion: 'v2',
# isBrowser: true,
# });
###
diff --git a/lib/util/index.coffee b/lib/util/index.coffee
index 519253f45..5cd04b5cf 100644
--- a/lib/util/index.coffee
+++ b/lib/util/index.coffee
@@ -56,6 +56,11 @@ exports.notFoundResponse =
code: 'ResinRequestError'
statusCode: 404
+exports.noDeviceForKeyResponse =
+ code: 'ResinRequestError'
+ statusCode: 500
+ body: 'No device found to associate with the api key'
+
exports.noApplicationForKeyResponse =
code: 'ResinRequestError'
statusCode: 500
@@ -133,8 +138,6 @@ exports.mergePineOptions = (defaults, extras) ->
if value?
if not isArray(value)
value = [value]
- if !includes(value, 'id')
- value.unshift('id')
result[option] = value
diff --git a/package.json b/package.json
index ee6352d55..4b2805cf9 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "resin-sdk",
- "version": "6.15.0",
+ "version": "7.0.0",
"description": "The Resin.io JavaScript SDK",
"main": "build/resin.js",
"homepage": "https://github.com/resin-io/resin-sdk",
@@ -35,6 +35,9 @@
},
"author": "Juan Cruz Viotti ",
"license": "Apache-2.0",
+ "engines": {
+ "node": ">=6.0"
+ },
"devDependencies": {
"browserify": "^14.3.0",
"catch-uncommitted": "^1.0.0",
@@ -71,7 +74,7 @@
"promise-memoize": "^1.2.0",
"resin-device-logs": "^3.1.0",
"resin-device-status": "^1.0.1",
- "resin-errors": "^2.9.0",
+ "resin-errors": "^2.10.0",
"resin-pine": "^5.0.2",
"resin-register-device": "^4.0.1",
"resin-request": "^8.6.0",
diff --git a/tests/integration/models/application.spec.coffee b/tests/integration/models/application.spec.coffee
index 7df9b3e0e..72d2f7ae7 100644
--- a/tests/integration/models/application.spec.coffee
+++ b/tests/integration/models/application.spec.coffee
@@ -15,10 +15,10 @@ describe 'Application Model', ->
promise = resin.models.application.getAll()
m.chai.expect(promise).to.become([])
- describe 'resin.models.application.getAppWithOwner()', ->
+ describe 'resin.models.application.getAppByOwner()', ->
it 'should eventually reject', ->
- promise = resin.models.application.getAppWithOwner('testapp', 'FooBar')
+ promise = resin.models.application.getAppByOwner('testapp', 'FooBar')
m.chai.expect(promise).to.be.rejected
describe 'resin.models.application.hasAny()', ->
@@ -36,16 +36,20 @@ describe 'Application Model', ->
it 'should be able to create a child application', ->
resin.models.application.create('FooBar', 'raspberry-pi').then (parentApplication) ->
- resin.models.application.create('FooBarChild', 'edge', parentApplication.id)
+ resin.models.application.create('FooBarChild', 'generic-amd64', parentApplication.id)
.then ->
resin.models.application.getAll()
.then ([ parentApplication, childApplication ]) ->
- m.chai.expect(childApplication.application.__id).to.equal(parentApplication.id)
+ m.chai.expect(childApplication.depends_on__application.__id).to.equal(parentApplication.id)
it 'should be rejected if the device type is invalid', ->
promise = resin.models.application.create('FooBar', 'foobarbaz')
m.chai.expect(promise).to.be.rejectedWith('Invalid device type: foobarbaz')
+ it 'should be rejected if the device type is discontinuted', ->
+ promise = resin.models.application.create('FooBar', 'edge')
+ m.chai.expect(promise).to.be.rejectedWith('Discontinued device type: edge')
+
it 'should be rejected if the name has less than three characters', ->
promise = resin.models.application.create('Fo', 'raspberry-pi')
m.chai.expect(promise).to.be.rejected
@@ -82,14 +86,14 @@ describe 'Application Model', ->
promise = resin.models.application.hasAny()
m.chai.expect(promise).to.eventually.be.true
- describe 'resin.models.application.getAppWithOwner()', ->
+ describe 'resin.models.application.getAppByOwner()', ->
it 'should find the created application', ->
- resin.models.application.getAppWithOwner('FooBar', credentials.username).then (application) =>
+ resin.models.application.getAppByOwner('FooBar', credentials.username).then (application) =>
m.chai.expect(application.id).to.equal(@application.id)
it 'should not find the created application with a different username', ->
- promise = resin.models.application.getAppWithOwner('FooBar', 'test_username')
+ promise = resin.models.application.getAppByOwner('FooBar', 'test_username')
m.chai.expect(promise).to.eventually.reject
describe 'resin.models.application.getAll()', ->
@@ -102,14 +106,6 @@ describe 'Application Model', ->
resin.models.application.getAll().then (applications) =>
m.chai.expect(applications[0].id).to.equal(@application.id)
- it 'should add a devices_length property', ->
- resin.models.application.getAll().then (applications) ->
- m.chai.expect(applications[0].devices_length).to.equal(0)
-
- it 'should add an online_devices property', ->
- resin.models.application.getAll().then (applications) ->
- m.chai.expect(applications[0].online_devices).to.equal(0)
-
it 'should support arbitrary pinejs options', ->
resin.models.application.getAll(expand: 'user')
.then (applications) ->
@@ -280,7 +276,7 @@ describe 'Application Model', ->
.then =>
resin.models.application.get(@application.id)
.then (app) ->
- Date.parse(app.support_expiry_date)
+ Date.parse(app.is_accessible_by_support_until__date)
m.chai.expect(promise).to.eventually.equal(expiryTime)
@@ -293,7 +289,7 @@ describe 'Application Model', ->
.then =>
resin.models.application.get(@application.id)
.then (app) ->
- app.support_expiry_date
+ app.is_accessible_by_support_until__date
m.chai.expect(promise).to.eventually.equal(null)
diff --git a/tests/integration/models/device.spec.coffee b/tests/integration/models/device.spec.coffee
index 20a9dcda4..f80bc43e2 100644
--- a/tests/integration/models/device.spec.coffee
+++ b/tests/integration/models/device.spec.coffee
@@ -197,14 +197,6 @@ describe 'Device Model', ->
m.chai.expect(devices).to.have.length(1)
m.chai.expect(devices[0].id).to.equal(@device.id)
- it 'should add an application_name property', ->
- resin.models.device.getAll().then (devices) =>
- m.chai.expect(devices[0].application_name).to.equal(@application.app_name)
-
- it 'should add a dashboard_url property', ->
- resin.models.device.getAll().then (devices) =>
- m.chai.expect(devices[0].dashboard_url).to.equal(resin.models.device.getDashboardUrl({ appId: @application.id, deviceId: @device.id }))
-
it 'should support arbitrary pinejs options', ->
resin.models.device.getAll(select: [ 'id' ])
.then ([ device ]) =>
@@ -223,14 +215,6 @@ describe 'Device Model', ->
m.chai.expect(devices).to.have.length(1)
m.chai.expect(devices[0].id).to.equal(@device.id)
- it 'should include an application_name property in the result', ->
- resin.models.device.getAllByApplication(@application.id).then (devices) =>
- m.chai.expect(devices[0].application_name).to.equal(@application.app_name)
-
- it 'should add a dashboard_url property', ->
- resin.models.device.getAllByApplication(@application.id).then (devices) =>
- m.chai.expect(devices[0].dashboard_url).to.equal(resin.models.device.getDashboardUrl({ appId: @application.id, deviceId: @device.id }))
-
it 'should be rejected if the application name does not exist', ->
promise = resin.models.device.getAllByApplication('HelloWorldApp')
m.chai.expect(promise).to.be.rejectedWith('Application not found: HelloWorldApp')
@@ -260,11 +244,11 @@ describe 'Device Model', ->
resin.pine.post
resource: 'device'
body:
- user: userId
- application: @childApplication.id
+ belongs_to__user: userId
+ belongs_to__application: @childApplication.id
device_type: @childApplication.device_type
uuid: resin.models.device.generateUniqueKey()
- device: @device.id
+ is_managed_by__device: @device.id
.then (device) =>
@childDevice = device
@@ -278,10 +262,6 @@ describe 'Device Model', ->
m.chai.expect(childDevices).to.have.length(1)
m.chai.expect(childDevices[0].id).to.equal(@childDevice.id)
- it 'should include an application_name property in the result (with the child app name)', ->
- resin.models.device.getAllByParentDevice(@device.id).then ([ childDevice ]) =>
- m.chai.expect(childDevice.application_name).to.equal(@childApplication.app_name)
-
it 'should be empty if the parent device has no children', ->
promise = resin.models.device.getAllByParentDevice(@childDevice.id).then (childDevices) ->
m.chai.expect(childDevices).to.have.length(0)
@@ -306,14 +286,6 @@ describe 'Device Model', ->
resin.models.device.get(@device.id).then (device) =>
m.chai.expect(device.id).to.equal(@device.id)
- it 'should add an application_name property', ->
- resin.models.device.get(@device.id).then (device) =>
- m.chai.expect(device.application_name).to.equal(@application.app_name)
-
- it 'should add a dashboard_url property', ->
- resin.models.device.get(@device.id).then (device) =>
- m.chai.expect(device.dashboard_url).to.equal(resin.models.device.getDashboardUrl({ appId: @application.id, deviceId: @device.id }))
-
it 'should be rejected if the device name does not exist', ->
promise = resin.models.device.get('asdfghjkl')
m.chai.expect(promise).to.be.rejectedWith('Device not found: asdfghjkl')
@@ -339,14 +311,6 @@ describe 'Device Model', ->
m.chai.expect(devices).to.have.length(1)
m.chai.expect(devices[0].id).to.equal(@device.id)
- it 'should add an application_name property', ->
- resin.models.device.getByName(@device.name).then (devices) =>
- m.chai.expect(devices[0].application_name).to.equal(@application.app_name)
-
- it 'should add a dashboard_url property', ->
- resin.models.device.getByName(@device.name).then (devices) =>
- m.chai.expect(devices[0].dashboard_url).to.equal(resin.models.device.getDashboardUrl({ appId: @application.id, deviceId: @device.id }))
-
it 'should be rejected if the device does not exist', ->
promise = resin.models.device.getByName('HelloWorldDevice')
m.chai.expect(promise).to.be.rejectedWith('Device not found: HelloWorldDevice')
@@ -774,8 +738,8 @@ describe 'Device Model', ->
promise = resin.models.device.grantSupportAccess(@device.id, expiryTimestamp)
.then =>
resin.models.device.get(@device.id)
- .then ({ support_expiry_date }) ->
- Date.parse(support_expiry_date)
+ .then ({ is_accessible_by_support_until__date }) ->
+ Date.parse(is_accessible_by_support_until__date)
m.chai.expect(promise).to.eventually.equal(expiryTimestamp)
@@ -786,8 +750,8 @@ describe 'Device Model', ->
resin.models.device.revokeSupportAccess(@device.id)
.then =>
resin.models.device.get(@device.id)
- .then ({ support_expiry_date }) ->
- m.chai.expect(support_expiry_date).to.be.null
+ .then ({ is_accessible_by_support_until__date }) ->
+ m.chai.expect(is_accessible_by_support_until__date).to.be.null
describe 'given a single application with a device id whose shorter uuid is only numbers', ->
diff --git a/tests/integration/setup.coffee b/tests/integration/setup.coffee
index f2bc1287b..60c97a206 100644
--- a/tests/integration/setup.coffee
+++ b/tests/integration/setup.coffee
@@ -23,7 +23,6 @@ else
dataDirectory: settings.get('dataDirectory')
_.assign opts,
- apiVersion: 'v2'
apiKey: null
isBrowser: IS_BROWSER,
retries: 3
diff --git a/tests/util.spec.coffee b/tests/util.spec.coffee
index 3accac517..d7db4a836 100644
--- a/tests/util.spec.coffee
+++ b/tests/util.spec.coffee
@@ -42,15 +42,6 @@ describe 'Pine option merging', ->
skip: 4
orderby: 'id asc'
- it 'overrides select options, but always includes id', ->
- result = mergePineOptions
- select: ['id', 'other']
- ,
- select: ['app_name']
-
- m.chai.expect(result).to.deep.equal
- select: ['id', 'app_name']
-
it 'combines filter options with $and', ->
result = mergePineOptions
filter: id: 1
diff --git a/yarn.lock b/yarn.lock
index a3cf63839..0b77cf4c9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4082,19 +4082,19 @@ resin-errors@^2.0.0:
dependencies:
typed-error "^0.1.0"
+resin-errors@^2.10.0:
+ version "2.10.0"
+ resolved "https://registry.yarnpkg.com/resin-errors/-/resin-errors-2.10.0.tgz#1e24d07f0ef7d4f1edb519fad4ae4e659c1e0c66"
+ dependencies:
+ tslib "^1.7.1"
+ typed-error "^2.0.0"
+
resin-errors@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/resin-errors/-/resin-errors-2.7.0.tgz#93ade640792107556d916df8692b5ecd97dda297"
dependencies:
typed-error "^0.1.0"
-resin-errors@^2.9.0:
- version "2.9.0"
- resolved "https://registry.yarnpkg.com/resin-errors/-/resin-errors-2.9.0.tgz#1f5de94238d2a70c0736dca84b7bf63a144e4e50"
- dependencies:
- tslib "^1.7.1"
- typed-error "^2.0.0"
-
resin-pine@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/resin-pine/-/resin-pine-5.0.2.tgz#a7337acd1604d44d4ff450fbbeb8bbd9936af103"