contentful-management
Advanced tools
Comparing version 0.8.6 to 1.0.0
724
index.js
@@ -1,714 +0,20 @@ | ||
'use strict'; | ||
var _ = require('underscore-contrib'); | ||
var axios = require('axios'); | ||
var redefine = require('redefine'); | ||
var querystring = require('querystring'); | ||
var APIError = require('./lib/api-error'); | ||
var PropError = require('./lib/prop-error'); | ||
var createBackoff = require('./lib/backoff'); | ||
var rateLimit = require('./lib/rate-limit'); | ||
// Identifiable | ||
// Object{sys: {id: Id}} -> Id | ||
// String -> Id | ||
function getId(identifiable) { | ||
if (_.isString(identifiable)) { | ||
return identifiable; | ||
// To understand why axios is vendored, check SETUP.md | ||
var axios = require('contentful-sdk-core/vendor-node/axios') | ||
var contentfulManagement | ||
try { | ||
contentfulManagement = require('./dist/contentful-management').default | ||
} catch (err) { | ||
if (err.code === 'MODULE_NOT_FOUND') { | ||
require('babel-register') | ||
contentfulManagement = require('./lib/contentful-management').default | ||
} else { | ||
console.log(err) | ||
process.exit(1) | ||
} | ||
if (!_.hasPath(identifiable, ['sys', 'id'])) { | ||
throw new PropError('Expected resource to have an ID in sys.id', identifiable); | ||
} | ||
return _.getPath(identifiable, ['sys', 'id']); | ||
} | ||
// Versioned | ||
// {sys: {version: Version}} -> Version | ||
function getVersion(resource) { | ||
if (!_.hasPath(resource, ['sys', 'version'])) { | ||
throw new PropError('Expected resource to have a version in sys.version', resource); | ||
module.exports = { | ||
createClient: function (params) { | ||
return contentfulManagement(axios, params) | ||
} | ||
return _.getPath(resource, ['sys', 'version']); | ||
} | ||
// {sys: Object, ...} -> {...} | ||
function getData(resource) { | ||
return _.omit(resource, 'sys'); | ||
} | ||
function creationMethodForResource(resource) { | ||
var hasId = _.hasPath(resource, ['sys', 'id']); | ||
return hasId ? 'PUT' : 'POST'; | ||
} | ||
function creationPathForResource(space, type, resource) { | ||
var hasId = _.hasPath(resource, ['sys', 'id']); | ||
var resourceName = { | ||
Asset: 'assets', | ||
ContentType: 'content_types', | ||
Entry: 'entries' | ||
}[type]; | ||
var path = '/spaces/' + space.sys.id + '/' + resourceName; | ||
if (hasId) { | ||
var id = _.getPath(resource, ['sys', 'id']); | ||
path += '/' + id; | ||
} | ||
return path; | ||
} | ||
var Client = redefine.Class({ | ||
constructor: function Client(options) { | ||
enforcep(options, 'accessToken'); | ||
this.options = _.defaults({}, options, { | ||
host: 'api.contentful.com', | ||
secure: true, | ||
rateLimit: 6, | ||
retryOnTooManyRequests: true, | ||
maxRetries: 5, | ||
}); | ||
this.agent = options.agent; | ||
// decorate this.request with a rate limiter | ||
this.request = rateLimit(this.options.rateLimit, 1000, this.request); | ||
}, | ||
request: function(path, options, backoff) { | ||
if (!options) options = {}; | ||
if (!options.method) options.method = 'GET'; | ||
if (!options.headers) options.headers = {}; | ||
if (!options.query) options.query = {}; | ||
options.headers['Content-Type'] = 'application/vnd.contentful.management.v1+json'; | ||
options.headers['X-Contentful-User-Agent'] = 'contentful-management.js/0.x'; | ||
options.query.access_token = this.options.accessToken; | ||
if (!backoff && this.options.retryOnTooManyRequests) { | ||
backoff = createBackoff(this.options.maxRetries); | ||
} | ||
var uri = [ | ||
this.options.secure ? 'https' : 'http', | ||
'://', | ||
_.first(this.options.host.split(':')), | ||
':', | ||
this.options.host.split(':')[1] || (this.options.secure ? '443' : '80'), | ||
path, | ||
'?', | ||
querystring.stringify(options.query) | ||
].join(''); | ||
options.url = uri; | ||
if(this.agent) options.agent = this.agent; | ||
var self = this; | ||
var response = axios(options).then(extractData); | ||
if (backoff) { | ||
response = response.catch(function(error) { | ||
// Rate-limited by the server, maybe backoff and retry | ||
if (error.status === 429) { | ||
return backoff(error, function () { | ||
return self.request(path, options, backoff); | ||
}); | ||
} | ||
throw error; | ||
}); | ||
} | ||
return response.catch(function (error) { | ||
if (error && !error.data) { | ||
// Attach request info to errors that don't have a response body | ||
error.request = { | ||
method: options.method, | ||
uri: uri, | ||
body: options.data | ||
}; | ||
throw error; | ||
} | ||
// Otherwise parse, wrap, and rethrow the error | ||
var parsedError = extractData(error); | ||
if (parsedError) { | ||
throw new APIError(parsedError, { | ||
method: options.method, | ||
uri: uri, | ||
body: options.data, | ||
headers: options.headers | ||
}); | ||
} else { | ||
throw new APIError(error, { | ||
method: options.method, | ||
uri: uri, | ||
body: options.data, | ||
headers: options.headers | ||
}); | ||
} | ||
}); | ||
}, | ||
createSpace: function(space, organizationId) { | ||
var headers = {}; | ||
if (organizationId) { | ||
headers['X-Contentful-Organization'] = organizationId; | ||
} | ||
return this.request('/spaces', { | ||
method: 'POST', | ||
data: JSON.stringify(space), | ||
headers: headers | ||
}).then(_.partial(Space.parse, this)); | ||
}, | ||
getSpace: function(identifiable) { | ||
var id = getId(identifiable); | ||
return this.request('/spaces/' + id).then(_.partial(Space.parse, this)); | ||
}, | ||
getSpaces: function() { | ||
return this.request('/spaces').then(_.partial(SearchResult.parse, this)); | ||
}, | ||
updateSpace: function(space) { | ||
var id = getId(space); | ||
var version = getVersion(space); | ||
return this.request('/spaces/' + id, { | ||
method: 'PUT', | ||
headers: { | ||
'X-Contentful-Version': version | ||
}, | ||
data: JSON.stringify(getData(space)) | ||
}).then(_.partial(Space.parse, this.client)); | ||
}, | ||
deleteSpace: function(identifiable) { | ||
var id = getId(identifiable); | ||
return this.request('/spaces/' + id, { | ||
method: 'DELETE', | ||
ignoreResponseBody: true | ||
}); | ||
} | ||
}); | ||
var Space = redefine.Class({ | ||
constructor: function Space() {}, | ||
statics: { | ||
parse: function(client, object) { | ||
return redefine(_.extend(new Space(), object), {client: client}); | ||
} | ||
}, | ||
// | ||
// Content Type functions | ||
// | ||
createContentType: function(contentType) { | ||
var path = creationPathForResource(this, 'ContentType', contentType); | ||
return this.client.request(path, { | ||
method: creationMethodForResource(contentType), | ||
data: JSON.stringify(contentType) | ||
}).then(_.partial(ContentType.parse, this.client)); | ||
}, | ||
getContentType: function(id) { | ||
return this.client.request('/spaces/' + this.sys.id + '/content_types/' + id) | ||
.then(_.partial(ContentType.parse, this.client)); | ||
}, | ||
getContentTypes: function(object) { | ||
var query = Query.parse(object); | ||
return this.client.request('/spaces/' + this.sys.id + '/content_types', {query: query}) | ||
.then(_.partial(SearchResult.parse, this.client)); | ||
}, | ||
getPublishedContentTypes: function(object) { | ||
var query = Query.parse(object); | ||
return this.client.request('/spaces/' + this.sys.id + '/public/content_types', {query: query}) | ||
.then(_.partial(SearchResult.parse, this.client)); | ||
}, | ||
updateContentType: function(contentType) { | ||
var spaceId = getId(this); | ||
var id = getId(contentType); | ||
var version = getVersion(contentType); | ||
return this.client.request('/spaces/' + spaceId + '/content_types/' + id, { | ||
method: 'PUT', | ||
headers: { | ||
'X-Contentful-Version': version | ||
}, | ||
data: JSON.stringify(getData(contentType)) | ||
}).then(_.partial(ContentType.parse, this.client)); | ||
}, | ||
deleteContentType: function(contentType) { | ||
var spaceId = getId(this); | ||
var id = getId(contentType); | ||
return this.client.request('/spaces/' + spaceId + '/content_types/' + id, { | ||
method: 'DELETE', | ||
ignoreResponseBody: true | ||
}); | ||
}, | ||
publishContentType: function(contentType, publishVersion) { | ||
var spaceId = getId(this); | ||
var id = getId(contentType); | ||
var version = publishVersion || getVersion(contentType); | ||
return this.client.request('/spaces/' + spaceId + '/content_types/' + id + '/published', { | ||
method: 'PUT', | ||
headers: { | ||
'X-Contentful-Version': version | ||
} | ||
}).then(_.partial(ContentType.parse, this.client)); | ||
}, | ||
unpublishContentType: function(contentType) { | ||
var spaceId = getId(this); | ||
var id = getId(contentType); | ||
return this.client.request('/spaces/' + spaceId + '/content_types/' + id + '/published', { | ||
method: 'DELETE' | ||
}).then(_.partial(ContentType.parse, this.client)); | ||
}, | ||
// | ||
// Entry functions | ||
// | ||
createEntry: function(contentType, entry) { | ||
var contentTypeId = getId(contentType); | ||
if(!contentTypeId) { | ||
throw new PropError('Entry creation needs a content type id', { | ||
contentType: contentType, | ||
entry: entry | ||
}); | ||
} | ||
var path = creationPathForResource(this, 'Entry', entry); | ||
return this.client.request(path, { | ||
method: creationMethodForResource(entry), | ||
headers: { | ||
'X-Contentful-Content-Type': contentTypeId | ||
}, | ||
data: JSON.stringify(getData(entry)) | ||
}).then(_.partial(Entry.parse, this.client)); | ||
}, | ||
updateEntry: function(entry) { | ||
var spaceId = getId(this); | ||
var id = getId(entry); | ||
var version = getVersion(entry); | ||
return this.client.request('/spaces/' + spaceId + '/entries/' + id, { | ||
method: 'PUT', | ||
headers: { | ||
'X-Contentful-Version': version | ||
}, | ||
data: JSON.stringify(getData(entry)) | ||
}).then(_.partial(Entry.parse, this.client)); | ||
}, | ||
getEntry: function(id) { | ||
return this.client.request('/spaces/' + this.sys.id + '/entries/' + id) | ||
.then(_.partial(Entry.parse, this.client)); | ||
}, | ||
getEntries: function(object) { | ||
var query = Query.parse(object); | ||
return this.client.request('/spaces/' + this.sys.id + '/entries', {query: query}) | ||
.then(_.partial(SearchResult.parse, this.client)); | ||
}, | ||
getPublishedEntries: function(object) { | ||
var query = Query.parse(object); | ||
return this.client.request('/spaces/' + this.sys.id + '/public/entries', {query: query}) | ||
.then(_.partial(SearchResult.parse, this.client)); | ||
}, | ||
publishEntry: function(entry, publishVersion) { | ||
var spaceId = getId(this); | ||
var id = getId(entry); | ||
var version = publishVersion || getVersion(entry); | ||
return this.client.request('/spaces/' + spaceId + '/entries/' + id + '/published', { | ||
method: 'PUT', | ||
headers: { | ||
'X-Contentful-Version': version | ||
} | ||
}).then(_.partial(Entry.parse, this.client)); | ||
}, | ||
unpublishEntry: function(entry) { | ||
var spaceId = getId(this); | ||
var id = getId(entry); | ||
return this.client.request('/spaces/' + spaceId + '/entries/' + id + '/published', { | ||
method: 'DELETE' | ||
}).then(_.partial(Entry.parse, this.client)); | ||
}, | ||
deleteEntry: function(identifiable) { | ||
var spaceId = getId(this); | ||
var id = getId(identifiable); | ||
return this.client.request('/spaces/' + spaceId + '/entries/' + id, { | ||
method: 'DELETE', | ||
ignoreResponseBody: true | ||
}); | ||
}, | ||
archiveEntry: function(entry) { | ||
var spaceId = getId(this); | ||
var id = getId(entry); | ||
return this.client.request('/spaces/' + spaceId + '/entries/' + id + '/archived', { | ||
method: 'PUT' | ||
}).then(_.partial(Entry.parse, this.client)); | ||
}, | ||
unarchiveEntry: function(entry) { | ||
var spaceId = getId(this); | ||
var id = getId(entry); | ||
return this.client.request('/spaces/' + spaceId + '/entries/' + id + '/archived', { | ||
method: 'DELETE' | ||
}).then(_.partial(Entry.parse, this.client)); | ||
}, | ||
// | ||
// Asset functions | ||
// | ||
createAsset: function(asset) { | ||
var path = creationPathForResource(this, 'Asset', asset); | ||
return this.client.request(path, { | ||
method: creationMethodForResource(asset), | ||
data: JSON.stringify(asset) | ||
}).then(_.partial(Asset.parse, this.client)); | ||
}, | ||
getAsset: function(identifiable) { | ||
var id = getId(identifiable); | ||
return this.client.request('/spaces/' + this.sys.id + '/assets/' + id) | ||
.then(_.partial(Asset.parse, this.client)); | ||
}, | ||
getAssets: function(object) { | ||
var query = Query.parse(object); | ||
return this.client.request('/spaces/' + this.sys.id + '/assets', {query: query}) | ||
.then(_.partial(SearchResult.parse, this.client)); | ||
}, | ||
getPublishedAssets: function(object) { | ||
var query = Query.parse(object); | ||
return this.client.request('/spaces/' + this.sys.id + '/public/assets', {query: query}) | ||
.then(_.partial(SearchResult.parse, this.client)); | ||
}, | ||
updateAsset: function(asset) { | ||
var spaceId = getId(this); | ||
var id = getId(asset); | ||
var version = getVersion(asset); | ||
return this.client.request('/spaces/' + spaceId + '/assets/' + id, { | ||
method: 'PUT', | ||
headers: { | ||
'X-Contentful-Version': version | ||
}, | ||
data: JSON.stringify(getData(asset)) | ||
}).then(_.partial(Asset.parse, this.client)); | ||
}, | ||
processAssetFile: function(asset, fileId, processVersion) { | ||
var spaceId = getId(this); | ||
var id = getId(asset); | ||
var version = processVersion || getVersion(asset); | ||
return this.client.request('/spaces/' + spaceId + '/assets/' + id + '/files/' + fileId + '/process', { | ||
method: 'PUT', | ||
headers: { | ||
'X-Contentful-Version': version | ||
}, | ||
ignoreResponseBody: true | ||
}); | ||
}, | ||
publishAsset: function(asset, publishVersion) { | ||
var spaceId = getId(this); | ||
var id = getId(asset); | ||
var version = publishVersion || getVersion(asset); | ||
return this.client.request('/spaces/' + spaceId + '/assets/' + id + '/published', { | ||
method: 'PUT', | ||
headers: { | ||
'X-Contentful-Version': version | ||
} | ||
}).then(_.partial(Asset.parse, this.client)); | ||
}, | ||
unpublishAsset: function(asset) { | ||
var spaceId = getId(this); | ||
var id = getId(asset); | ||
return this.client.request('/spaces/' + spaceId + '/assets/' + id + '/published', { | ||
method: 'DELETE' | ||
}).then(_.partial(Asset.parse, this.client)); | ||
}, | ||
deleteAsset: function(identifiable) { | ||
var spaceId = getId(this); | ||
var id = getId(identifiable); | ||
return this.client.request('/spaces/' + spaceId + '/assets/' + id, { | ||
method: 'DELETE', | ||
ignoreResponseBody: true | ||
}); | ||
}, | ||
archiveAsset: function(asset) { | ||
var spaceId = getId(this); | ||
var id = getId(asset); | ||
return this.client.request('/spaces/' + spaceId + '/assets/' + id + '/archived', { | ||
method: 'PUT' | ||
}).then(_.partial(Asset.parse, this.client)); | ||
}, | ||
unarchiveAsset: function(asset) { | ||
var spaceId = getId(this); | ||
var id = getId(asset); | ||
return this.client.request('/spaces/' + spaceId + '/assets/' + id + '/archived', { | ||
method: 'DELETE' | ||
}).then(_.partial(Entry.parse, this.client)); | ||
}, | ||
getLocales: function() { | ||
return this.client.request('/spaces/' + this.sys.id + '/locales') | ||
.then(_.partial(SearchResult.parse, this.client)); | ||
}, | ||
createLocale: function(locale) { | ||
return this.client.request('/spaces/' + this.sys.id + '/locales', { | ||
method: 'POST', | ||
data: JSON.stringify(locale) | ||
}).then(_.partial(Locale.parse, this.client)); | ||
}, | ||
updateLocale: function(locale) { | ||
var id = getId(locale); | ||
var version = getVersion(locale); | ||
return this.client.request('/spaces/' + this.sys.id + '/locales/' + id, { | ||
method: 'PUT', | ||
headers: { | ||
'X-Contentful-Version': version | ||
}, | ||
data: JSON.stringify(locale) | ||
}).then(_.partial(Locale.parse, this.client)); | ||
}, | ||
deleteLocale: function(identifiable) { | ||
var id = getId(identifiable); | ||
return this.client.request('/spaces/' + this.sys.id + '/locales/' + id, { | ||
method: 'DELETE' | ||
}); | ||
} | ||
}); | ||
var Asset = redefine.Class({ | ||
constructor: function Asset() {}, | ||
statics: { | ||
parse: function(client, object) { | ||
return redefine(_.extend(new Asset(), { | ||
sys: Sys.parse(object.sys), | ||
fields: object.fields | ||
}), { | ||
client: client | ||
}); | ||
} | ||
} | ||
}); | ||
var Entry = redefine.Class({ | ||
constructor: function Entry() {}, | ||
statics: { | ||
parse: function(client, object) { | ||
return redefine(_.extend(new Entry(), { | ||
sys: Sys.parse(object.sys), | ||
fields: object.fields | ||
}), { | ||
client: client | ||
}); | ||
} | ||
} | ||
}); | ||
var Locale = redefine.Class({ | ||
constructor: function Locale() {}, | ||
statics: { | ||
parse: function(client, object) { | ||
return redefine(_.extend(new Locale(), { | ||
sys: Sys.parse(object.sys), | ||
code: object.code, | ||
name: object.name, | ||
contentDeliveryApi: object.contentDeliveryApi, | ||
contentManagementApi: object.contentManagementApi | ||
}), { | ||
client: client | ||
}); | ||
} | ||
} | ||
}); | ||
var ContentType = redefine.Class({ | ||
constructor: function ContentType() {}, | ||
statics: { | ||
parse: function(client, object) { | ||
return redefine(_.extend(new ContentType(), { | ||
sys: Sys.parse(object.sys), | ||
fields: _.map(object.fields, Field.parse), | ||
}, _.pick(object, 'name', 'description', 'displayField')), { | ||
client: client | ||
}); | ||
} | ||
} | ||
}); | ||
var Field = redefine.Class({ | ||
constructor: function Field() {}, | ||
statics: { | ||
parse: function(object) { | ||
return _.extend(new Field(), object); | ||
} | ||
} | ||
}); | ||
var SearchResult = redefine.Class({ | ||
constructor: function SearchResult() {}, | ||
statics: { | ||
parse: function(client, object) { | ||
walkMutate(object, isParseableResource, _.partial(parseResource, client)); | ||
return redefine( | ||
object.items, { | ||
limit: object.limit, | ||
skip: object.skip, | ||
total: object.total | ||
} | ||
); | ||
} | ||
} | ||
}); | ||
var Query = redefine.Class({ | ||
constructor: function Query() {}, | ||
toQueryString: function() { | ||
return querystring.stringify(this); | ||
}, | ||
statics: { | ||
parse: function(object) { | ||
return _.extend(new Query(), stringifyArrayValues(object)); | ||
}, | ||
} | ||
}); | ||
var Sys = redefine.Class({ | ||
constructor: function Sys() {}, | ||
statics: { | ||
parse: function(object) { | ||
return _.extend( | ||
new Sys(), | ||
_.pick(object, 'id', 'version', 'type', 'locale', 'archivedVersion', 'publishedVersion', 'revision'), | ||
compacto({ | ||
archivedAt: object.archivedAt && new Date(object.archivedAt), | ||
archivedBy: object.archivedBy && Link.parse(object.archivedBy), | ||
contentType: object.contentType && Link.parse(object.contentType), | ||
createdAt: object.createdAt && new Date(object.createdAt), | ||
createdBy: object.createdBy && Link.parse(object.createdBy), | ||
linkType: object.linkType, | ||
publishedAt: object.publishedAt && new Date(object.publishedAt), | ||
publishedBy: object.publishedBy && Link.parse(object.publishedBy), | ||
updatedAt: object.updatedAt && new Date(object.updatedAt), | ||
updatedBy: object.updatedBy && Link.parse(object.updatedBy), | ||
space: object.space && Link.parse(object.space) | ||
}) | ||
); | ||
} | ||
} | ||
}); | ||
var Link = redefine.Class({ | ||
constructor: function Link() {}, | ||
statics: { | ||
parse: function(object) { | ||
return _.extend(new Link(), { | ||
sys: Sys.parse(object.sys) | ||
}); | ||
} | ||
} | ||
}); | ||
exports.createClient = _.fnull(function(options) { | ||
return new Client(options); | ||
}, {}); | ||
exports.APIError = APIError; | ||
function compacto(object) { | ||
return _.reduce(object, function(compacted, value, key) { | ||
if (_.truthy(value)) compacted[key] = value; | ||
return compacted; | ||
}, {}); | ||
} | ||
function enforcep(object, property) { | ||
if (!_.exists(object[property])) | ||
throw new PropError('Expected property ' + property, object); | ||
} | ||
var parseableResourceTypes = { | ||
Asset: Asset, | ||
ContentType: ContentType, | ||
Entry: Entry, | ||
Space: Space, | ||
Locale: Locale | ||
}; | ||
function isParseableResource(object) { | ||
return _.getPath(object, ['sys', 'type']) in parseableResourceTypes; | ||
} | ||
function parseResource(client) { | ||
var resource, Type; | ||
if (arguments.length === 2) { | ||
resource = arguments[1]; | ||
Type = parseableResourceTypes[resource.sys.type]; | ||
return Type.parse(client, resource); | ||
} else if (arguments.length === 3) { | ||
var space = arguments[1]; | ||
resource = arguments[2]; | ||
Type = parseableResourceTypes[resource.sys.type]; | ||
return Type.parse(client, space, resource); | ||
} | ||
} | ||
function stringifyArrayValues(object) { | ||
return _.reduce(object, function(object, value, key) { | ||
object[key] = _.isArray(value) ? value.join(',') : value; | ||
return object; | ||
}, {}); | ||
} | ||
function walkMutate(input, pred, mutator) { | ||
if (pred(input)) | ||
return mutator(input); | ||
if (_.isArray(input) || _.isObject(input)) { | ||
_.each(input, function(item, key) { | ||
input[key] = walkMutate(item, pred, mutator); | ||
}); | ||
return input; | ||
} | ||
return input; | ||
} | ||
function extractData(response) { | ||
if (!response.data) return; | ||
return response.data; | ||
} |
{ | ||
"version": "1.0.0", | ||
"name": "contentful-management", | ||
"description": "Client for Contentful's Content Management API", | ||
"version": "0.8.6", | ||
"homepage": "https://www.contentful.com/developers/documentation/content-management-api/", | ||
"main": "index.js", | ||
"browser": { | ||
"questor": "./questor.min.js" | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/contentful/contentful-management.js.git" | ||
}, | ||
"repository": "git@github.com:contentful/contentful-management.js.git", | ||
"author": "Stephan Seidt <stephan@contentful.com>", | ||
"author": "Contentful <opensource@contentful.com>", | ||
"license": "MIT", | ||
"tonicExampleFilename": "tonic-example.js", | ||
"scripts": { | ||
"clean": "rimraf dist && rimraf browser-dist && rimraf coverage && rimraf out", | ||
"build": "npm run clean && npm run vendor:version && npm run build:dist && npm run build:standalone", | ||
"build:dist": "babel lib --out-dir dist", | ||
"build:standalone": "webpack && webpack -p --output-filename contentful-management.min.js", | ||
"link-dev-deps": "mkdirp node_modules && ln -s ../../contentful-sdk-core/src node_modules/contentful-sdk-core", | ||
"unlink-dev-deps": "rimraf node_modules/contentful-sdk-core", | ||
"docs:build": "jsdoc -r -c ./jsdoc.json dist", | ||
"docs:dev": "npm run build && npm run docs:build", | ||
"docs:watch": "watchy -w lib npm run docs:dev", | ||
"docs:publish": "npm run docs:build && ./node_modules/contentful-sdk-jsdoc/bin/publish-docs.sh contentful-management.js contentfulManagement", | ||
"test:ci": "npm run test:cover && npm run build && npm run test:integration", | ||
"test:cover": "BABEL_ENV=test babel-node ./node_modules/istanbul/lib/cli.js cover test/runner", | ||
"test:only": "BABEL_ENV=test babel-node ./test/runner", | ||
"test:debug": "BABEL_ENV=test babel-node debug ./test/runner", | ||
"test:integration": "babel-node ./test/integration/integration-tests.js", | ||
"test:browser-local": "BABEL_ENV=test ./node_modules/.bin/karma start karma.conf.local.js", | ||
"test:browser-remote": "BABEL_ENV=test ./node_modules/.bin/karma start karma.conf.saucelabs.js", | ||
"vendor:version": "echo \"module.exports = '`cat package.json|json version`'\" > version.js", | ||
"browser-coverage": "npm run test:cover && opener coverage/lcov-report/index.html", | ||
"prepublish": "in-publish && npm run build || not-in-publish", | ||
"postpublish": "npm run docs:publish && npm run clean", | ||
"pretest": "standard lib/*.js && standard lib/**/*.js && standard test/**/*.js", | ||
"test": "npm run test:cover && npm run test:integration && npm run test:browser-local", | ||
"semantic-release": "semantic-release pre && npm publish && semantic-release post" | ||
}, | ||
"browser": "./browser.js", | ||
"files": [ | ||
"browser.js", | ||
"index.js", | ||
"version.js", | ||
"dist", | ||
"browser-dist", | ||
"tonic-example.js" | ||
], | ||
"dependencies": { | ||
"axios": "^0.8.1", | ||
"inherits": "^2.0.1", | ||
"redefine": "^0.2.0", | ||
"underscore-contrib": "0.2.2" | ||
"contentful-sdk-core": "^2.2.2" | ||
}, | ||
"devDependencies": { | ||
"es6-promise": "^2.3.0", | ||
"browserify": "~3.20.0", | ||
"browserstack-cli": "~0.3.1", | ||
"buster": "~0.7.6", | ||
"envify": "~1.0.1", | ||
"lodash": "~2.4.1", | ||
"testem": "~0.6.2", | ||
"yargs": "~1.2.1" | ||
"babel-cli": "^6.7.5", | ||
"babel-eslint": "^6.0.2", | ||
"babel-loader": "^6.2.4", | ||
"babel-plugin-rewire": "^1.0.0-rc-2", | ||
"babel-plugin-transform-runtime": "^6.7.5", | ||
"babel-preset-es2015": "^6.6.0", | ||
"babel-register": "^6.7.2", | ||
"blue-tape": "^0.2.0", | ||
"contentful-sdk-jsdoc": "^1.1.0", | ||
"coveralls": "^2.11.9", | ||
"cz-conventional-changelog": "^1.1.6", | ||
"in-publish": "^2.0.0", | ||
"istanbul": "^1.0.0-alpha.2", | ||
"jsdoc": "^3.4.0", | ||
"json": "^9.0.3", | ||
"karma": "^0.13.22", | ||
"karma-babel-preprocessor": "^6.0.1", | ||
"karma-chrome-launcher": "^0.2.3", | ||
"karma-sauce-launcher": "^0.3.1", | ||
"karma-tap": "^1.0.4", | ||
"karma-webpack": "^1.7.0", | ||
"mkdirp": "^0.5.1", | ||
"require-all": "^2.0.0", | ||
"rimraf": "^2.5.2", | ||
"semantic-release": "^4.3.5", | ||
"sinon": "^2.0.0-pre", | ||
"standard": "^6.0.8", | ||
"webpack": "^1.12.15" | ||
}, | ||
"scripts": { | ||
"bundle": "browserify -s contentful-management index.js > dist/contentful-management.js", | ||
"minify-bundle": "uglifyjs dist/contentful-management.js -m -c > dist/contentful-management.min.js", | ||
"prepare-browser-test": "browserify -d -t envify -x buster test/helper.js > test/bundle-helper.js", | ||
"test": "buster-test -r tap" | ||
"standard": { | ||
"parser": "babel-eslint" | ||
}, | ||
"config": { | ||
"commitizen": { | ||
"path": "./node_modules/cz-conventional-changelog" | ||
} | ||
} | ||
} |
752
README.md
@@ -1,737 +0,143 @@ | ||
# contentful-management.js | ||
[![npm](https://img.shields.io/npm/v/contentful-management.svg)](https://www.npmjs.com/package/contentful-management) | ||
[![Build Status](https://travis-ci.org/contentful/contentful-management.js.svg?branch=master)](https://travis-ci.org/contentful/contentful-management.js) | ||
[![Coverage Status](https://coveralls.io/repos/github/contentful/contentful-management.js/badge.svg?branch=master)](https://coveralls.io/github/contentful/contentful-management.js?branch=master) | ||
[![Dependency Status](https://david-dm.org/contentful/contentful-management.js.svg)](https://david-dm.org/contentful/contentful-management.js) | ||
[![devDependency Status](https://david-dm.org/contentful/contentful-management.js/dev-status.svg)](https://david-dm.org/contentful/contentful-management.js#info=devDependencies) | ||
Javascript client for [Contentful's](https://www.contentful.com) Content Management API: | ||
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) | ||
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/) | ||
- [API Documentation](#api) | ||
- [REST API Documentation](https://www.contentful.com/developers/documentation/content-management-api) | ||
- [Examples](#examples) | ||
- [Create an access token for the Content Management API (need account)](https://www.contentful.com/developers/documentation/content-management-api/#getting-started) | ||
Javascript SDK for [Contentful's](https://www.contentful.com) Content Management API. | ||
Supported browsers/environments: | ||
# About | ||
- Chrome | ||
- Firefox | ||
- IE10 | ||
- node.js >= 0.8 | ||
[Contentful](https://www.contentful.com) is a content management platform for web applications, mobile apps and connected devices. It allows you to create, edit & manage content in the cloud and publish it anywhere via a powerful API. Contentful offers tools for managing editorial teams and enabling cooperation between organizations. | ||
## Install | ||
## Features | ||
In node, using [npm](http://npmjs.org): | ||
- Content management and retrieval through Contentful's [Content Management API](https://www.contentful.com/developers/docs/references/content-management-api/). | ||
- Built in rate limiting with recovery procedures | ||
- Asset processing helpers | ||
``` sh | ||
npm install contentful-management | ||
``` | ||
## Supported environments | ||
Note: The next minor version release of `dist/contentful-management.min.js` will | ||
be much smaller. Please use a package manager to keep your JS | ||
dependencies up to date and get the newest version right when it's | ||
ready! | ||
Browsers and Node.js: | ||
- Chrome | ||
- Firefox | ||
- IE11 / Edge | ||
- Safari | ||
- node.js (0.10, iojs-3.x, 4.x, 5.x) | ||
## Promises | ||
Other browsers should also work, but at the moment we're only running automated tests on the browsers and Node.js versions specified above. | ||
contentful-management.js uses [axios](https://github.com/mzabriskie/axios) under the hood, which depends on a native ES6 Promise implementation to be supported. If your environment doesn't support ES6 Promises, you can [polyfill](https://github.com/jakearchibald/es6-promise#auto-polyfill) it. | ||
# Getting started | ||
In order to get started with the Contentful Management JS SDK you'll need not only to install it, but also to get credentials which will allow you to have access to your content in Contentful. | ||
## Examples | ||
## Installation | ||
This library comes with a few example scripts | ||
In node, using [npm](http://npmjs.org): | ||
### Cloning a Space | ||
If you're looking for the old clone-space.js script, check out our new tool, [contentful-space-sync](https://github.com/contentful/contentful-space-sync) | ||
### Migrating Entry fields | ||
Sometimes you need to migrate content from one field to another. | ||
This is a script which migrates all values from one field to another | ||
field, using a specific mapping function if it's provided. | ||
It'll do this for each entry of a specific Content Type in a Space, | ||
going through it slice by slice. | ||
Currently this supports mapping from Text to Symbol. | ||
But it would be very simple to convert e.g. numbers to symbols | ||
or even location strings to locations by geocoding. | ||
PRs are very welcome! | ||
[View Source](example/migrate-field.js) | ||
``` sh | ||
$ example/migrate-fields.js \ | ||
--access-token $CONTENTFUL_MANAGEMENT_API_ACCESS_TOKEN \ | ||
--space-id $SPACE_ID \ | ||
--content-type-id $CONTENT_TYPE_ID \ | ||
--source-field-id $SOURCE_FIELD_ID \ | ||
--destination-field-id $DESTINATION_FIELD_ID | ||
npm install contentful-management | ||
``` | ||
## API | ||
Or, if you'd like to use a standalone built file you can use the following script tag or just download it from [npmcdn](https://npmcdn.com), under the `browser-dist` directory: | ||
### createClient(opts) -> Client | ||
To use the Content Management API you will need an access token. The easiest | ||
way to get a token for local scripts/experimentation is by using the OAuth app | ||
embedded in our [Developer center documentation][get-token]. | ||
``` js | ||
var contentful = require('contentful-management'); | ||
var client = contentful.createClient({ | ||
// A valid access token for your user (see above on how to create a valid access token) | ||
accessToken: 'b4c0n73n7fu1', | ||
// Enable or disable SSL. Enabled by default. | ||
secure: true | ||
}); | ||
``` html | ||
<script src="https://npmcdn.com/contentful-management@latest/browser-dist/contentful-management.min.js"></script> | ||
``` | ||
**It is not recommended to use the above URL for production.** | ||
If you'd like to use contentful.js with an http proxy, look into [https-proxy-agent](https://www.npmjs.com/package/https-proxy-agent). If you pass down an agent through the relevant initialization option it gets passed down to axios and subsequently to Node's http module. | ||
Using `contentful@latest` will always get you the latest version, but you can also specify a specific version number: | ||
### Client#getSpace(id) -> SpacePromise | ||
```js | ||
client.getSpace('foobar') | ||
``` html | ||
<script src="https://npmcdn.com/contentful-management@1.0.0/browser-dist/contentful-management.min.js"></script> | ||
``` | ||
Returns a promise for a [Space][] object. | ||
Check the [releases](https://github.com/contentful/contentful-management.js/releases) page to know which versions are available. | ||
### Client#createSpace(opts) -> SpacePromise | ||
## Authentication | ||
Create a space with the name 'CMA Example Space'. | ||
To get content from Contentful, an app should authenticate with an with an OAuth bearer token. | ||
```js | ||
client.createSpace({name: 'CMA Example Space'}) | ||
``` | ||
If you want to use this SDK for a simple tool or a local app that you won't redistribute or make available to other users, you can get an API key for the Management API at our [Authentication page](https://www.contentful.com/developers/docs/references/authentication/). | ||
Returns a promise for a [Space][] object. | ||
If you'd like to create an app which would make use of this SDK but that would be available for other users, where they could authenticate with their own Contentful credentials, make sure to also check out the section about [Creating an OAuth Application](https://www.contentful.com/developers/docs/references/authentication/#creating-an-oauth-20-application) | ||
### Client#deleteSpace -> Promise | ||
## Your first request | ||
Delete a space and all of its content. **Warning:** there is no undo! | ||
The following code snippet is the most basic one you can use to get some content from Contentful with this SDK: | ||
```js | ||
client.deleteSpace(space); | ||
``` | ||
Returns a promise for nothing, which should still be checked for errors. | ||
### Space API | ||
A space is a top level container for all other resources. In addition to the | ||
methods documented below, a space has the following data properties: | ||
```js | ||
{ | ||
"name": "Example Space", | ||
"sys": { | ||
"type": "Space", | ||
"id": "1vlwe1hnkhmk", | ||
"version": 0, | ||
"createdBy": { | ||
"sys": { | ||
"type": "Link", | ||
"linkType": "User", | ||
"id": "0lEP0wVJL8WSQSbRuVUdcJ" | ||
} | ||
}, | ||
"createdAt": "2013-09-22T17:34:53Z", | ||
"updatedBy": { | ||
"sys": { | ||
"type": "Link", | ||
"linkType": "User", | ||
"id": "0lEP0wVJL8WSQSbRuVUdcJ" | ||
} | ||
}, | ||
"updatedAt": "2013-09-22T17:34:53Z" | ||
} | ||
} | ||
``` | ||
#### Space#createContentType(data) -> ContentTypePromise | ||
Create a new content type by providing a name, fields, optional description, | ||
and an optional ID. If you do not provide the `sys.id` property, an ID will be | ||
generated for you. | ||
```js | ||
space.createContentType({ | ||
sys: {id: 'blog-post'}, | ||
name: 'Blog Post', | ||
description: 'For like, blogging', | ||
fields: [ | ||
{id: 'title', name: 'Title', type: 'Text'}, | ||
{id: 'body', name: 'Body', type: 'Text'} | ||
] | ||
var contentful = require('contentful-management') | ||
var client = contentful.createClient({ | ||
// This is the access token for this space. Normally you get both ID and the token in the Contentful web app | ||
accessToken: 'YOUR_ACCESS_TOKEN' | ||
}) | ||
``` | ||
The easiest way to find out what field types are available and how to represent | ||
them in JSON is to use the content type editor built into the [Contentful | ||
app][cf-app]. (Note that you will need administrative privileges for a space to | ||
edit content types). | ||
Returns a promise for a [ContentType][]. | ||
#### Space#updateContentType(data) -> ContentTypePromise | ||
Updates an existing content type. The provided data object needs to have | ||
`sys.id` and `sys.version` properties. The version provided should be the version | ||
of the content type retrieved from the server. | ||
Read more about [updating resources](https://www.contentful.com/developers/docs/references/content-management-api/#/introduction/updating-resources) on the CMA documentation. | ||
#### Space#getContentType(id) -> ContentTypePromise | ||
Retrieve a content type by its ID (**not** its name). Returns a promise for a | ||
[ContentType][]. | ||
#### Space#getContentTypes() -> ContentTypeCollectionPromise | ||
Retrieve all content types for the space. Returns a promise for a [collection][] | ||
of [ContentType][] objects. | ||
#### Space#getPublishedContentTypes() -> ContentTypeCollectionPromise | ||
Retrieve all published content types for the space. Returns a promise for a [collection][] | ||
of [ContentType][] objects. | ||
#### Space#publishContentType(contentType) -> ContentTypePromise | ||
Publish a [content type][], making it available for use by [create-entry], as | ||
well as visible to the [Content Delivery API][]. | ||
```js | ||
space.publishContentType(contentType) | ||
``` | ||
Returns a promise for an updated version of the content type. | ||
#### Space#unpublishContentType(contentType) -> ContentTypePromise | ||
Unpublish a [content type][]. This operation is not allowed if there | ||
are any entries of this content type (because entries may only be created for | ||
published content types). If you wish to delete a content type and all of its | ||
entries, you will need to iterate over the entries and delete them before | ||
unpublishing and deleting the content type. | ||
```js | ||
space.unpublishContentType(contentType) | ||
``` | ||
Returns a promise for an updated version of the content type. | ||
#### Space#deleteContentType(contentType) -> Promise | ||
Delete a content type, note that the content type must be unpublished (and | ||
therefore have no entries) before it can be deleted. | ||
```js | ||
space.deleteContentType(contentType) | ||
``` | ||
#### Space#createEntry(contentType, entry) -> EntryPromise | ||
Create a new entry by providing field values and and an optional ID. If you do | ||
not provide the `sys.id` property, an ID will be generated for you. | ||
```js | ||
space.createEntry(contentType, { | ||
sys: {id: 'hello-world'}, | ||
fields: { | ||
title: {'en-US': 'Hello, World!'}, | ||
body: {'en-US': 'Bacon is healthy!'} | ||
} | ||
// This API call will request a space with the specified ID | ||
client.getSpace('spaceId') | ||
.then((space) => { | ||
// Now that we have a space, we can get entries from that space | ||
space.getEntries() | ||
.then((entries) => { | ||
console.log(entries.items) | ||
}) | ||
}) | ||
``` | ||
For more information on what is allowed in the `fields` property, see [Entry | ||
fields][]. | ||
You can try and change the above example at [Tonic](https://tonicdev.com/npm/contentful-management). | ||
Returns a promise for an [Entry][]. | ||
## Documentation/References | ||
#### Space#updateEntry(data) -> ContentTypePromise | ||
To help you get the most out of this SDK, we've prepared reference documentation, tutorials and other examples that will help you learn and understand how to use this library. | ||
Updates an existing entry. The provided data object needs to have | ||
`sys.id` and `sys.version` properties. The version provided should be the version | ||
of the entry retrieved from the server. | ||
### Reference documentation | ||
Read more about [updating resources](https://www.contentful.com/developers/docs/references/content-management-api/#/introduction/updating-resources) on the CMA documentation. | ||
The [Contentful's JS SDK reference](https://contentful.github.io/contentful-management.js) documents what objects and methods are exposed by this library, what arguments they expect and what kind of data is returned. | ||
#### Space#getEntries(query) -> EntryCollectionPromise | ||
Most methods also have examples which show you how to use them. | ||
Search & filter all of the entries in a space. The `query` parameter should be | ||
an object of querystring key-value pairs. The [query examples](#query-examples) | ||
section containts more examples of the kinds of queries you can perform. | ||
You can start by looking at the top level [`contentfulManagement`](./contentfulManagement.html) namespace. | ||
```js | ||
space.getEntries({content_type: 'blog-post'}) | ||
``` | ||
From version 1.0.0 onwards, you can access documentation for a specific version by visiting `https://contentful.github.io/contentful-management.js/contentful/<VERSION>` | ||
Returns a promise for a [collection][] of [Entry][] objects. | ||
### Contentful JavaScript resources | ||
#### Space#getEntry(id) -> EntryPromise | ||
Check the [Contentful for JavaScript](https://www.contentful.com/developers/docs/javascript/) page for Tutorials, Demo Apps, and more information on other ways of using JavaScript with Contentful | ||
Retrieve an entry by its ID. Returns a promise for an [Entry][]. | ||
### REST API reference | ||
```js | ||
space.getEntry('hello-world') | ||
``` | ||
This library is a wrapper around our Contentful Management REST API. Some more specific details such as search parameters and pagination are better explained on the [REST API reference](https://www.contentful.com/developers/docs/references/content-management-api/), and you can also get a better understanding of how the requests look under the hood. | ||
#### Space#getEntries(query) -> EntryCollectionPromise | ||
### Legacy contentful-management.js | ||
Search & filter all of the entries in a space. The `query` parameter should be | ||
an object of querystring key-value pairs. The [query examples](#query-examples) | ||
section containts more examples of the kinds of queries you can perform. | ||
For versions prior to 1.0.0, you can access documentation at [https://github.com/contentful/contentful-management.js/tree/legacy](https://github.com/contentful/contentful.js/tree/legacy) | ||
```js | ||
space.getEntries({content_type: 'blog-post'}) | ||
``` | ||
## Versioning | ||
Returns a promise for a [collection][] of [Entry][] objects. | ||
This project strictly follows [Semantic Versioning](http://semver.org/) by use of [semantic-release](https://github.com/semantic-release/semantic-release). | ||
#### Space#getPublishedEntries(query) -> EntryCollectionPromise | ||
This means that new versions are released automatically as fixes, features or breaking changes are released. | ||
Search & filter all of the published entries in a space. Works like getEntries. | ||
You can check the changelog on the [releases](https://github.com/contentful/contentful-management.js/releases) page. | ||
Returns a promise for a [collection][] of [Entry][] objects. | ||
## Migration from contentful-management.js 1.x and older | ||
#### Space#publishEntry(entry) -> EntryPromise | ||
contentful.js 1.x was a major rewrite, with some API changes. While the base functionality remains the same, some method names have changed, as well as some internal behaviors. | ||
Publish an [Entry][], making it visible to the [Content Delivery API][]. | ||
See the [migration guide](MIGRATION.md) for more information. | ||
```js | ||
space.publishEntry(entry) | ||
``` | ||
## Support | ||
Returns a promise for an updated version of the entry. | ||
If you have a problem with this library, please file an [issue](https://github.com/contentful/contentful-management.js/issues/new) here on Github. | ||
#### Space#unpublishEntry(entry) -> EntryPromise | ||
If you have other problems with Contentful not related to this library, you can contact [Customer Support](https://support.contentful.com). | ||
Unpublish an [Entry][], this appears to the [Content Delivery API][] as though | ||
the entry was deleted. | ||
## Contributing | ||
```js | ||
space.unpublishEntry(entry) | ||
``` | ||
See [CONTRIBUTING.md](CONTRIBUTING.md) | ||
Returns a promise for an updated version of the entry. | ||
#### Space#archiveEntry(entry) -> EntryPromise | ||
Archive an [Entry][]. The Entry needs to be previously unpublished. | ||
```js | ||
space.archiveEntry(entry) | ||
``` | ||
Returns a promise for an updated version of the entry. | ||
#### Space#unarchiveEntry(entry) -> EntryPromise | ||
Unarchive an [Entry][]. | ||
```js | ||
space.unarchiveEntry(entry) | ||
``` | ||
Returns a promise for an updated version of the entry. | ||
#### Space#deleteEntry(entry) -> Promise | ||
Delete an entry. Note that entries must be unpublished before deleting them. | ||
```js | ||
space.deleteEntry(entry) | ||
``` | ||
Returns a promise for nothing, which should still be checked for errors. | ||
#### Space#createAsset(data) -> AssetPromise | ||
Create a new asset by providing field values and and an optional ID. If you do | ||
not provide the `sys.id` property, an ID will be generated for you. | ||
```js | ||
space.createAsset({ | ||
sys: {id: 'dinosaurs'}, | ||
fields: { | ||
title: {'en-US': 'Dinosaur'}, | ||
file: { | ||
'en-US': { | ||
upload: 'http://www.qwantz.com/comics/comic2-2870.png' | ||
} | ||
} | ||
} | ||
}) | ||
``` | ||
Returns a promise for an [Asset][], which must be [processed][process-asset] | ||
before it can be published. | ||
#### Space#updateAsset(data) -> ContentTypePromise | ||
Updates an existing asset. The provided data object needs to have | ||
`sys.id` and `sys.version` properties. The version provided should be the version | ||
of the asset retrieved from the server. | ||
Read more about [updating resources](https://www.contentful.com/developers/docs/references/content-management-api/#/introduction/updating-resources) on the CMA documentation. | ||
#### Space#processAssetFile(asset, locale) -> Promise | ||
Process the file for a particular asset & locale. Note that this operation is | ||
asynchronous on the Contentful backend; you will receive a successful response | ||
before the asset is fully processed. | ||
```js | ||
space.processAssetFile(asset, 'en-US'); | ||
``` | ||
Returns a promise for nothing, which should still be checked for errors. In | ||
order to detect when an asset has finished processing, retrieve the asset using | ||
`space.getAsset` and test for the presence of `asset.fields.file[locale].url`. | ||
#### Space#getAsset(id) -> AssetPromise | ||
Retrieve an asset by its ID. Returns a promise for an [Asset][]. | ||
```js | ||
space.getAsset('dinosaurs') | ||
``` | ||
#### Space#getAssets(query) -> AssetCollectionPromise | ||
Search & filter all of the assets in a space. The `query` parameter should be | ||
an object of querystring key-value pairs. The [query examples](#query-examples) | ||
section containts more examples of the kinds of queries you can perform. | ||
```js | ||
space.getAssets({'fields.file.url[exists]': false}) | ||
``` | ||
Returns a promise for a [collection][] of [Asset][] objects. | ||
#### Space#getPublishedAssets(query) -> AssetCollectionPromise | ||
Search & filter all of the assets in a space. Works like getAssets. | ||
Returns a promise for a [collection][] of [Asset][] objects. | ||
#### Space#publishAsset(asset) -> AssetPromise | ||
Publish an [Asset][], making it visible to the [Content Delivery API][]. | ||
```js | ||
space.publishAsset(asset) | ||
``` | ||
Returns a promise for an updated version of the asset. | ||
#### Space#unpublishAsset(asset) -> AssetPromise | ||
Unpublish an [Asset][], this appears to the [Content Delivery API][] as though | ||
the asset was deleted. | ||
```js | ||
space.unpublishAsset(asset) | ||
``` | ||
Returns a promise for an updated version of the asset. | ||
#### Space#archiveAsset(asset) -> AssetPromise | ||
Archive an [Asset][]. The Asset needs to be previously unpublished. | ||
```js | ||
space.archiveAsset(asset) | ||
``` | ||
Returns a promise for an updated version of the asset. | ||
#### Space#unarchiveAsset(asset) -> AssetPromise | ||
Unarchive an [Asset][]. | ||
```js | ||
space.unarchiveAsset(asset) | ||
``` | ||
Returns a promise for an updated version of the asset. | ||
#### Space#createLocale(data) -> LocalePromise | ||
Create a new locale by providing a name, and locale code. You can also specify | ||
if the locale should be made available in the Content Management API and | ||
Content Delivery API (both are enabled by default) | ||
```js | ||
space.createLocale({ | ||
name: 'German', | ||
code: 'de', | ||
contentManagementApi: true, | ||
contentDeliveryApi: true | ||
}) | ||
``` | ||
Returns a promise for a [Locale][]. | ||
#### Space#updateLocale(data) -> LocalePromise | ||
Updates an existing locale. The provided data object needs to have | ||
`sys.id` and `sys.version` properties. The version provided should be the version | ||
of the locale retrieved from the server. | ||
Read more about [updating resources](https://www.contentful.com/developers/docs/references/content-management-api/#/introduction/updating-resources) on the CMA documentation. | ||
#### Space#getLocale(id) -> LocalePromise | ||
Retrieve a locale its ID (**not** its name or code). Returns a promise for a | ||
[Locale][]. | ||
#### Space#deleteLocale(locale) -> Promise | ||
Delete a locale. Any content for this locale in existing entries will be gone. | ||
```js | ||
space.deleteLocale(locale) | ||
``` | ||
### ContentType properties | ||
Each content type defines a schema for entries in its `fields` array. Every | ||
entry has a corresponding content type, and its _own_ `fields` property, which | ||
is an object. The allowed keys and values in an entries `fields` object | ||
correspond to the field ids defined in that entries content type. | ||
A complete content type (the one created in [create-content-type][]) looks like: | ||
```js | ||
{ | ||
"name": "Blog Post", | ||
"fields": [ | ||
{ "id": "title", "name": "Title", "type": "Text" }, | ||
{ "id": "body", "name": "Body", "type": "Text" } | ||
], | ||
"sys": { | ||
"id": "blog-post", | ||
"type": "ContentType", | ||
"space": { | ||
"sys": { "type": "Link", "linkType": "Space", "id": "7daovfk1olns" } | ||
}, | ||
"createdAt": "2013-09-22T21:42:00.184Z", | ||
"createdBy": { | ||
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" } | ||
}, | ||
"version": 1, | ||
"updatedAt": "2013-09-22T21:42:00.187Z", | ||
"updatedBy": { | ||
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" } | ||
} | ||
} | ||
} | ||
``` | ||
### Entry properties | ||
An entry is a piece of content containing fields and values. Every entry has a | ||
corresponding content type (denoted by its `sys.contentType` property) that | ||
defines what keys are allowed in its `fields` property, and what types those | ||
keys can contain. Note that field values are always nested in an object whose | ||
keys correspond to the locales available in a space. | ||
```js | ||
{ | ||
"fields": { | ||
"title": { "en-US": "Hello, World!" }, | ||
"body": { "en-US": "Bacon is healthy!" } | ||
}, | ||
"sys": { | ||
"id": "hello-world", | ||
"type": "Entry", | ||
"space": { | ||
"sys": { "type": "Link", "linkType": "Space", "id": "7daovfk1olns" } | ||
}, | ||
"createdAt": "2013-09-22T23:05:03.271Z", | ||
"createdBy": { | ||
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" } | ||
}, | ||
"contentType": { | ||
"sys": { "type": "Link", "linkType": "ContentType", "id": "blog-post" } | ||
}, | ||
"version": 1, | ||
"updatedAt": "2013-09-22T23:05:03.271Z", | ||
"updatedBy": { | ||
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" } | ||
} | ||
} | ||
} | ||
``` | ||
### Asset properties | ||
An asset is special kind of entry containing metadata for a binary file (e.g. an | ||
image or video). Note that asset files have multiple states. | ||
```js | ||
{ | ||
"fields": { | ||
"title": { "en-US": "Dinosaurs" }, | ||
"file": { "en-US": { /* See comments regarding asset file states below */ } } | ||
}, | ||
"sys": { | ||
"id": "dinosaurs", | ||
"type": "Asset", | ||
"space": { | ||
"sys": { "type": "Link", "linkType": "Space", "id": "7daovfk1olns" } | ||
}, | ||
"createdAt": "2013-09-22T23:05:03.271Z", | ||
"createdBy": { | ||
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" } | ||
}, | ||
"version": 1, | ||
"updatedAt": "2013-09-22T23:05:03.271Z", | ||
"updatedBy": { | ||
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" } | ||
} | ||
} | ||
} | ||
``` | ||
#### Asset file states | ||
Assets may contain references to multiple files (one for each locale of their | ||
space) and each one of those files may be in one of three states: "new", | ||
"ready to process", or "processed". | ||
To determine the state of an asset file, you can test for the presence of | ||
`fields.file[locale].upload` and `fields.file[locale].url`. If the `url` | ||
property is set, then the file has already been processed. If the `url` property | ||
is not set, but the `upload` property is, you can attempt processing of the | ||
file. | ||
If neither property is present, the `upload` property must be set to a valid | ||
publically accessible URL before calling [Space#processAssetFile][process-asset]. | ||
Note that an asset with unprocessed files can not be published. | ||
### Query Examples | ||
You can filter & search the entries and assets in your space by passing query | ||
params to [`Space#getEntries`](#spacegetentriesquery---entrycollectionpromise) | ||
and [`Space#getAssets`](#spacegetassetsquery---assetcollectionpromise). There are | ||
a few predefined query parameter names (such as `content_type` and `order`), and | ||
you can also query against document properties by using a dot-separated property | ||
path (followed by an optional operator in square brackets) as a query parameter | ||
name. | ||
For example: `fields.name[ne]` means "entries where `fields.name` is not-equal | ||
to ...". Full documentation of the allowed query parameters & field operators | ||
can be found in [our API Documentation][search-parameters], but below are some | ||
examples of common queries to get you started: | ||
Search entries that have been updated since the 1st of January, 2013: | ||
```js | ||
space.getEntries({ 'sys.updatedAt[gte]': '2013-01-01T00:00:00Z' }) | ||
``` | ||
Retrieve a specific set of entries by their `sys.id`: | ||
```js | ||
space.getEntries({ 'sys.id[in]': [ 'finn', 'jake' ] }) | ||
``` | ||
Search for `cat` entries that have less than three lives left: | ||
```js | ||
space.getEntries({ | ||
'content_type': 'cat', | ||
'fields.lives[lt]': 3 | ||
}) | ||
``` | ||
> Specifying the `content_type` query parameter is _required_ when querying on | ||
> fields (such as `fields.lives` above). Note that `'cat'` is the content type | ||
> **ID** and not its name. | ||
Full-text search for entries with "bacon" anywhere in their textual content: | ||
```js | ||
space.getEntries({ query: 'bacon' }) | ||
``` | ||
Full-text search for dogs with "bacon" specifically in the `description` field: | ||
```js | ||
space.getEntries({ | ||
'content_type': 'dog', | ||
'fields.description[match]': 'bacon' | ||
}) | ||
``` | ||
Get the 50 most recently created entries, and the next 50: | ||
```js | ||
space.getEntries({ | ||
order: '-sys.createdAt', | ||
limit: 50 | ||
}) | ||
space.getEntries({ | ||
order: '-sys.createdAt', | ||
skip: 50, | ||
limit: 50 | ||
}) | ||
``` | ||
See also: [Collections and pagination][collection]. | ||
### Collections and pagination | ||
Many methods return collections of resources. These collections are represented | ||
as a JSON object containing items and pagination details: | ||
``` | ||
{ | ||
"sys": { | ||
"type": "Array" | ||
}, | ||
"total": 1, // Total number of items matching the query | ||
"skip": 0, // Offset into the result set represented by this response | ||
"limit": 100, // Effective limit on # of items returned in this response | ||
"items": [ | ||
// Full representations of each item | ||
] | ||
} | ||
``` | ||
The `getEntries` and `getAssets` methods both accept `limit`, `skip`, and | ||
`order` as query parameters, allowing you to paginate through larger result | ||
sets. Note that specifying a stable property (such as `'sys.createdAt'`) for | ||
ordering results is recommended. | ||
## Unit Tests | ||
Set the following environment variables to valid values: | ||
- `CONTENTFUL_ACCESS_TOKEN` - a valid access token value | ||
- `CONTENTFUL_MANAGEMENT_HOSTNAME` - the Contentful host name (without protocol) | ||
Then execute the unit tests: | ||
``` sh | ||
npm test | ||
``` | ||
## License | ||
MIT | ||
[get-token]: https://www.contentful.com/developers/docs/references/authentication/#the-management-api | ||
[search-parameters]: http://docs.contentfulcda.apiary.io/#reference/search-parameters | ||
[collection]: #collections-and-pagination | ||
[Space]: #space-api | ||
[ContentType]: #contenttype-properties | ||
[Entry]: #entry-properties | ||
[Asset]: #asset-properties | ||
[process-asset]: #spaceprocessassetfileasset-locale---promise | ||
[create-content-type]: #spacecreatecontenttype---contenttypepromise |
Sorry, the diff of this file is too big to display
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
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
574198
1
29
13683
0
0
1
28
144
+ Addedcontentful-sdk-core@^2.2.2
+ Addedbabel-runtime@6.26.0(transitive)
+ Addedcall-bind@1.0.7(transitive)
+ Addedcontentful-sdk-core@2.5.0(transitive)
+ Addedcore-js@2.6.12(transitive)
+ Addeddefine-data-property@1.1.4(transitive)
+ Addedes-define-property@1.0.0(transitive)
+ Addedes-errors@1.3.0(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedget-intrinsic@1.2.4(transitive)
+ Addedgopd@1.0.1(transitive)
+ Addedhas-property-descriptors@1.0.2(transitive)
+ Addedhas-proto@1.0.3(transitive)
+ Addedhas-symbols@1.0.3(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedlodash@4.17.21(transitive)
+ Addedobject-inspect@1.13.3(transitive)
+ Addedqs@6.13.0(transitive)
+ Addedregenerator-runtime@0.11.1(transitive)
+ Addedset-function-length@1.2.2(transitive)
+ Addedside-channel@1.0.6(transitive)
- Removedaxios@^0.8.1
- Removedinherits@^2.0.1
- Removedredefine@^0.2.0
- Removedunderscore-contrib@0.2.2
- Removedaxios@0.8.1(transitive)
- Removedinherits@2.0.4(transitive)
- Removedredefine@0.2.1(transitive)
- Removedunderscore@1.13.7(transitive)
- Removedunderscore-contrib@0.2.2(transitive)