Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

contentful-management

Package Overview
Dependencies
Maintainers
4
Versions
584
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

contentful-management - npm Package Compare versions

Comparing version 0.8.6 to 1.0.0

browser-dist/contentful-management.js

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"
}
}
}

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc