├── .eslintignore ├── .gitignore ├── .travis.yml ├── .flowconfig ├── .babelrc ├── tests ├── helper.js ├── .eslintrc.json ├── config.spec.js ├── seedCompany.spec.js ├── producer.spec.js ├── edible.spec.js ├── strain.spec.js ├── flower.spec.js ├── extract.spec.js └── product.spec.js ├── .npmignore ├── src ├── config.js ├── index.js ├── seed-company.js ├── util.js ├── producer.js ├── extract.js ├── flower.js ├── product.js ├── edible.js ├── strain.js ├── dispensary.js └── redirects.js ├── lib ├── config.js ├── index.js ├── seed-company.js ├── util.js ├── producer.js ├── edible.js ├── flower.js ├── extract.js ├── product.js ├── strain.js ├── dispensary.js └── redirects.js ├── .editorconfig ├── .eslintrc.json ├── LICENSE ├── package.json └── README.md /.eslintignore: -------------------------------------------------------------------------------- 1 | lib 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | *.log 3 | npm-debug.log* 4 | pids 5 | *.pid 6 | *.seed 7 | node_modules 8 | .DS_Store 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | script: 5 | - npm run build 6 | - npm run test 7 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | .*/node_modules/.* 3 | .*/lib/.* 4 | .*/tests/.* 5 | 6 | [options] 7 | module.ignore_non_literal_requires=true 8 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "stage-2" 5 | ], 6 | "plugins": [ 7 | "transform-flow-strip-types", 8 | "add-module-exports", 9 | "transform-runtime" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /tests/helper.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { addPath } from 'app-module-path'; 3 | import path from 'path'; 4 | 5 | global.expect = expect; 6 | 7 | addPath(path.resolve(__dirname, `../${process.env.TEST_PATH}`)); 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tests 3 | .DS_Store 4 | logs 5 | *.log 6 | npm-debug.log* 7 | pids 8 | *.pid 9 | *.seed 10 | node_modules 11 | .editorconfig 12 | .eslintignore 13 | .eslintrc.json 14 | .flowconfig 15 | .gitignore 16 | .babelrc 17 | -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | let apiKey = process.env.CANNABIS_REPORTS_API_KEY; 3 | const setCannabisReportsKey = (key: string): null => { 4 | apiKey = key; 5 | return null; 6 | }; 7 | 8 | export { 9 | apiKey, 10 | setCannabisReportsKey, 11 | }; 12 | -------------------------------------------------------------------------------- /tests/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "flow-vars/define-flow-type": 0, 4 | "flow-vars/use-flow-type": 0, 5 | "flowtype/require-parameter-type": 0, 6 | "flowtype/require-return-type": 0, 7 | "flowtype/space-after-type-colon": 0, 8 | "flowtype/space-before-type-colon": 0, 9 | "flowtype/type-id-match": 0 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/config.spec.js: -------------------------------------------------------------------------------- 1 | import { apiKey } from 'config'; 2 | import { setCannabisReportsKey } from 'index'; 3 | 4 | describe('setCannabisReportsKey()', () => { 5 | it('sets apiKey', () => { 6 | const oldKey = apiKey; 7 | setCannabisReportsKey('1234'); 8 | expect(apiKey).to.be.equal('1234'); 9 | return setCannabisReportsKey(oldKey); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /lib/config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | var apiKey = process.env.CANNABIS_REPORTS_API_KEY; 7 | var setCannabisReportsKey = function setCannabisReportsKey(key) { 8 | exports.apiKey = apiKey = key; 9 | return null; 10 | }; 11 | 12 | exports.apiKey = apiKey; 13 | exports.setCannabisReportsKey = setCannabisReportsKey; -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import { setCannabisReportsKey } from './config'; 2 | 3 | const Dispensary = require('./dispensary')(); 4 | const Edible = require('./edible')(); 5 | const Extract = require('./extract')(); 6 | const Flower = require('./flower')(); 7 | const Producer = require('./producer')(); 8 | const Product = require('./product')(); 9 | const SeedCompany = require('./seed-company')(); 10 | const Strain = require('./strain')(); 11 | 12 | export { 13 | Dispensary, 14 | Edible, 15 | Extract, 16 | Flower, 17 | Producer, 18 | Product, 19 | SeedCompany, 20 | setCannabisReportsKey, 21 | Strain, 22 | }; 23 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # Matches multiple files with brace expansion notation 12 | # Set default charset 13 | [*.{js,json,md}] 14 | charset = utf-8 15 | 16 | # 2 space indentation 17 | [*.js] 18 | indent_style = space 19 | indent_size = 2 20 | 21 | # Matches the exact files either package.json or .travis.yml 22 | [{package.json,.travis.yml,.eslintrc.json}] 23 | indent_style = space 24 | indent_size = 2 25 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.Strain = exports.setCannabisReportsKey = exports.SeedCompany = exports.Product = exports.Producer = exports.Flower = exports.Extract = exports.Edible = exports.Dispensary = undefined; 7 | 8 | var _config = require('./config'); 9 | 10 | var Dispensary = require('./dispensary')(); 11 | var Edible = require('./edible')(); 12 | var Extract = require('./extract')(); 13 | var Flower = require('./flower')(); 14 | var Producer = require('./producer')(); 15 | var Product = require('./product')(); 16 | var SeedCompany = require('./seed-company')(); 17 | var Strain = require('./strain')(); 18 | 19 | exports.Dispensary = Dispensary; 20 | exports.Edible = Edible; 21 | exports.Extract = Extract; 22 | exports.Flower = Flower; 23 | exports.Producer = Producer; 24 | exports.Product = Product; 25 | exports.SeedCompany = SeedCompany; 26 | exports.setCannabisReportsKey = _config.setCannabisReportsKey; 27 | exports.Strain = Strain; -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": "airbnb/base", 4 | "parser": "babel-eslint", 5 | "plugins": [ 6 | "flow-vars", 7 | "flowtype" 8 | ], 9 | "env": { 10 | "es6": true, 11 | "node": true, 12 | "mocha": true 13 | }, 14 | "globals": { 15 | "expect": false 16 | }, 17 | "rules": { 18 | "quotes": [2, "single"], 19 | "curly": 2, 20 | "semi": [2, "always"], 21 | "flow-vars/define-flow-type": 2, 22 | "flow-vars/use-flow-type": 2, 23 | "flowtype/require-parameter-type": 2, 24 | "flowtype/require-return-type": [ 25 | 2, 26 | "always", 27 | { "annotateUndefined": "always" } 28 | ], 29 | "flowtype/space-after-type-colon": [ 30 | 2, 31 | "always" 32 | ], 33 | "flowtype/space-before-type-colon": [ 34 | 2, 35 | "never" 36 | ], 37 | "flowtype/type-id-match": [ 38 | 2, 39 | "^([A-Z][a-z0-9]+)+Type$" 40 | ] 41 | }, 42 | "settings": { 43 | "flowtype": { 44 | "onlyFilesWithFlowAnnotation": false 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016~present AJ Funk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/seedCompany.spec.js: -------------------------------------------------------------------------------- 1 | import { SeedCompany } from 'index'; 2 | 3 | describe('SeedCompany.seedCompany()', () => { 4 | it('returns object', () => 5 | SeedCompany.seedCompany('VUJCJ00000000000000000000') 6 | .then((data) => expect(typeof(data)).to.equal('object')) 7 | ); 8 | it('returns error message', () => 9 | SeedCompany.seedCompany('VUJCJ4TYMG00!000000&00000') 10 | .catch((err) => expect(err).to.be.an('error')) 11 | ); 12 | }); 13 | 14 | describe('SeedCompany.strains()', () => { 15 | it('returns array', () => 16 | SeedCompany.strains('VUJCJ00000000000000000000') 17 | .then((data) => expect(data).to.be.instanceof(Array)) 18 | ); 19 | it('returns array', () => 20 | SeedCompany.strains('VUJCJ00000000000000000000', { page: 2 }) 21 | .then((data) => expect(data).to.be.instanceof(Array)) 22 | ); 23 | it('returns error message', () => 24 | SeedCompany.strains('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 25 | ); 26 | }); 27 | 28 | describe('SeedCompany.reviews()', () => { 29 | it('returns array', () => 30 | SeedCompany.reviews('VUJCJ00000000000000000000') 31 | .then((data) => expect(data).to.be.instanceof(Array)) 32 | ); 33 | it('returns array', () => 34 | SeedCompany.reviews('VUJCJ00000000000000000000', { page: 2 }) 35 | .then((data) => expect(data).to.be.instanceof(Array)) 36 | ); 37 | it('returns error message', () => 38 | SeedCompany.reviews('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 39 | ); 40 | }); 41 | -------------------------------------------------------------------------------- /src/seed-company.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { 3 | handleResult, 4 | sendRequest, 5 | validateUcpc, 6 | } from './util'; 7 | 8 | export default function seedCompany(): Object { 9 | return { 10 | 11 | seedCompany: (ucpc: string): Promise => 12 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 13 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 14 | return sendRequest( 15 | `seed-companies/${ucpc}`, 16 | null, 17 | resolve, 18 | reject, 19 | handleResult 20 | ); 21 | }), 22 | 23 | strains: (ucpc: string, options: Object = {}): Promise => 24 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 25 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 26 | return sendRequest( 27 | `seed-companies/${ucpc}/strains`, 28 | options, 29 | resolve, 30 | reject, 31 | handleResult 32 | ); 33 | }), 34 | 35 | reviews: (ucpc: string, options: Object = {}): Promise => 36 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 37 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 38 | return sendRequest( 39 | `seed-companies/${ucpc}/reviews`, 40 | options, 41 | resolve, 42 | reject, 43 | handleResult 44 | ); 45 | }), 46 | 47 | }; 48 | } 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cannabis-reports", 3 | "version": "1.1.9", 4 | "description": "SDK for Cannabis Reports API", 5 | "author": "AJ Funk ", 6 | "main": "lib/index.js", 7 | "engines": { 8 | "node": ">=5.0", 9 | "npm": ">=3.3" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/AJFunk/cannabis-reports" 14 | }, 15 | "license": "MIT", 16 | "scripts": { 17 | "test": "export TEST_PATH=lib && mocha --timeout 8000 tests/* --compilers js:babel-register --require ./tests/helper.js --recursive", 18 | "test-source": "export TEST_PATH=src && mocha --timeout 8000 tests/* --compilers js:babel-register --require ./tests/helper.js --recursive", 19 | "start": "babel-node ./src/index.js", 20 | "lint": "eslint --ext .js ./", 21 | "build": "npm run lint && babel src -d lib", 22 | "flow": "flow" 23 | }, 24 | "devDependencies": { 25 | "app-module-path": "^1.0.6", 26 | "babel-cli": "^6.7.5", 27 | "babel-eslint": "^6.0.2", 28 | "babel-plugin-add-module-exports": "^0.1.2", 29 | "babel-plugin-transform-flow-strip-types": "^6.7.0", 30 | "babel-plugin-transform-runtime": "^6.23.0", 31 | "babel-preset-es2015": "^6.6.0", 32 | "babel-preset-stage-2": "^6.5.0", 33 | "babel-register": "^6.7.2", 34 | "chai": "^3.5.0", 35 | "eslint": "^2.7.0", 36 | "eslint-config-airbnb": "^7.0.0", 37 | "eslint-plugin-babel": "^3.2.0", 38 | "eslint-plugin-flow-vars": "^0.5.0", 39 | "eslint-plugin-flowtype": "^2.4.0", 40 | "flow-bin": "^0.44.0", 41 | "mocha": "^2.4.5" 42 | }, 43 | "dependencies": { 44 | "babel-runtime": "^6.23.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/seed-company.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _promise = require('babel-runtime/core-js/promise'); 8 | 9 | var _promise2 = _interopRequireDefault(_promise); 10 | 11 | exports.default = seedCompany; 12 | 13 | var _util = require('./util'); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function seedCompany() { 18 | return { 19 | 20 | seedCompany: function seedCompany(ucpc) { 21 | return new _promise2.default(function (resolve, reject) { 22 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 23 | return (0, _util.sendRequest)('seed-companies/' + ucpc, null, resolve, reject, _util.handleResult); 24 | }); 25 | }, 26 | 27 | strains: function strains(ucpc) { 28 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 29 | return new _promise2.default(function (resolve, reject) { 30 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 31 | return (0, _util.sendRequest)('seed-companies/' + ucpc + '/strains', options, resolve, reject, _util.handleResult); 32 | }); 33 | }, 34 | 35 | reviews: function reviews(ucpc) { 36 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 37 | return new _promise2.default(function (resolve, reject) { 38 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 39 | return (0, _util.sendRequest)('seed-companies/' + ucpc + '/reviews', options, resolve, reject, _util.handleResult); 40 | }); 41 | } 42 | 43 | }; 44 | } 45 | module.exports = exports['default']; -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | // $FlowFixMe 3 | import { https } from './redirects'; 4 | import { apiKey } from './config'; 5 | 6 | const handleResult = (resolve: (data: Object) => void, 7 | reject: (reason: Error) => void, 8 | err: Error | null, 9 | data?: Object): mixed => { 10 | if (err) return reject(err); 11 | return data ? resolve(data) : reject(new Error('No data found')); 12 | }; 13 | 14 | const sendRequest = (endpoint: string, 15 | options: Object | null = {}, 16 | resolve: (data: Object) => void, 17 | reject: (reason: Error) => void, 18 | cb: Function): void => { 19 | let url = `${endpoint}?`; 20 | if (options) { 21 | for (const key in options) { 22 | if (options.hasOwnProperty(key)) { 23 | url = `${url}${key}=${options[key]}&`; 24 | } 25 | } 26 | } 27 | url = url.replace(/\s/g, '%20'); 28 | if (url[url.length - 1] === '&' || url[url.length - 1] === '?') { 29 | url = url.substr(0, url.length - 1); 30 | } 31 | 32 | const params = { 33 | host: 'www.cannabisreports.com', 34 | path: `/api/v1.0/${url}`, 35 | method: 'GET', 36 | headers: { 37 | 'X-API-Key': apiKey, 38 | }, 39 | }; 40 | 41 | const req = https.request(params, (res: Object): null => { 42 | if (res.statusCode < 200 || res.statusCode >= 300) { 43 | return cb(resolve, reject, new Error(`statusCode=${res.statusCode}`)); 44 | } 45 | let body = ''; 46 | res.on('data', (c: Object): void => { 47 | body += c.toString(); 48 | }); 49 | res.on('end', (): Object => { 50 | const d = JSON.parse(body); 51 | return cb(resolve, reject, null, d.data); 52 | }); 53 | return null; 54 | }); 55 | req.on('error', (err: Object): Object => cb(resolve, reject, err)); 56 | req.end(); 57 | }; 58 | 59 | const validateUcpc = (ucpc: string): boolean => { 60 | if (!ucpc || ucpc.length !== 25) return false; 61 | if (typeof(ucpc) !== 'string' || /[^a-zA-Z0-9]/.test(ucpc)) return false; 62 | return true; 63 | }; 64 | 65 | export { 66 | handleResult, 67 | sendRequest, 68 | validateUcpc, 69 | }; 70 | -------------------------------------------------------------------------------- /lib/util.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.validateUcpc = exports.sendRequest = exports.handleResult = undefined; 7 | 8 | var _redirects = require('./redirects'); 9 | 10 | var _config = require('./config'); 11 | 12 | // $FlowFixMe 13 | var handleResult = function handleResult(resolve, reject, err, data) { 14 | if (err) return reject(err); 15 | return data ? resolve(data) : reject(new Error('No data found')); 16 | }; 17 | 18 | var sendRequest = function sendRequest(endpoint) { 19 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 20 | var resolve = arguments[2]; 21 | var reject = arguments[3]; 22 | var cb = arguments[4]; 23 | 24 | var url = endpoint + '?'; 25 | if (options) { 26 | for (var key in options) { 27 | if (options.hasOwnProperty(key)) { 28 | url = '' + url + key + '=' + options[key] + '&'; 29 | } 30 | } 31 | } 32 | url = url.replace(/\s/g, '%20'); 33 | if (url[url.length - 1] === '&' || url[url.length - 1] === '?') { 34 | url = url.substr(0, url.length - 1); 35 | } 36 | 37 | var params = { 38 | host: 'www.cannabisreports.com', 39 | path: '/api/v1.0/' + url, 40 | method: 'GET', 41 | headers: { 42 | 'X-API-Key': _config.apiKey 43 | } 44 | }; 45 | 46 | var req = _redirects.https.request(params, function (res) { 47 | if (res.statusCode < 200 || res.statusCode >= 300) { 48 | return cb(resolve, reject, new Error('statusCode=' + res.statusCode)); 49 | } 50 | var body = ''; 51 | res.on('data', function (c) { 52 | body += c.toString(); 53 | }); 54 | res.on('end', function () { 55 | var d = JSON.parse(body); 56 | return cb(resolve, reject, null, d.data); 57 | }); 58 | return null; 59 | }); 60 | req.on('error', function (err) { 61 | return cb(resolve, reject, err); 62 | }); 63 | req.end(); 64 | }; 65 | 66 | var validateUcpc = function validateUcpc(ucpc) { 67 | if (!ucpc || ucpc.length !== 25) return false; 68 | if (typeof ucpc !== 'string' || /[^a-zA-Z0-9]/.test(ucpc)) return false; 69 | return true; 70 | }; 71 | 72 | exports.handleResult = handleResult; 73 | exports.sendRequest = sendRequest; 74 | exports.validateUcpc = validateUcpc; -------------------------------------------------------------------------------- /src/producer.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { 3 | handleResult, 4 | sendRequest, 5 | validateUcpc, 6 | } from './util'; 7 | 8 | export default function producer(): Object { 9 | return { 10 | 11 | all: (options: Object = {}): Promise => 12 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => 13 | sendRequest( 14 | 'producers', 15 | options, 16 | resolve, 17 | reject, 18 | handleResult 19 | ) 20 | ), 21 | 22 | producer: (ucpc: string): Promise => 23 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 24 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 25 | return sendRequest( 26 | `producers/${ucpc}`, 27 | null, 28 | resolve, 29 | reject, 30 | handleResult 31 | ); 32 | }), 33 | 34 | extracts: (ucpc: string, options: Object = {}): Promise => 35 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 36 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 37 | return sendRequest( 38 | `producers/${ucpc}/extracts`, 39 | options, 40 | resolve, 41 | reject, 42 | handleResult 43 | ); 44 | }), 45 | 46 | edibles: (ucpc: string, options: Object = {}): Promise => 47 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 48 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 49 | return sendRequest( 50 | `producers/${ucpc}/edibles`, 51 | options, 52 | resolve, 53 | reject, 54 | handleResult 55 | ); 56 | }), 57 | 58 | products: (ucpc: string, options: Object = {}): Promise => 59 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 60 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 61 | return sendRequest( 62 | `producers/${ucpc}/products`, 63 | options, 64 | resolve, 65 | reject, 66 | handleResult 67 | ); 68 | }), 69 | 70 | availability: (ucpc: string, lat: string, lng: string, options: Object = {}): Promise => 71 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 72 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 73 | if (typeof lat === 'undefined') return reject(new Error('Latitude is required')); 74 | if (typeof lng === 'undefined') return reject(new Error('Longitude is required')); 75 | const radius = (options && options.radius) ? `/${options.radius}` : ''; 76 | return sendRequest( 77 | `producers/${ucpc}/availability/geo/${lat}/${lng}${radius}`, 78 | options, 79 | resolve, 80 | reject, 81 | handleResult 82 | ); 83 | }), 84 | 85 | }; 86 | } 87 | -------------------------------------------------------------------------------- /lib/producer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _promise = require('babel-runtime/core-js/promise'); 8 | 9 | var _promise2 = _interopRequireDefault(_promise); 10 | 11 | exports.default = producer; 12 | 13 | var _util = require('./util'); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function producer() { 18 | return { 19 | 20 | all: function all() { 21 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 22 | return new _promise2.default(function (resolve, reject) { 23 | return (0, _util.sendRequest)('producers', options, resolve, reject, _util.handleResult); 24 | }); 25 | }, 26 | 27 | producer: function producer(ucpc) { 28 | return new _promise2.default(function (resolve, reject) { 29 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 30 | return (0, _util.sendRequest)('producers/' + ucpc, null, resolve, reject, _util.handleResult); 31 | }); 32 | }, 33 | 34 | extracts: function extracts(ucpc) { 35 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 36 | return new _promise2.default(function (resolve, reject) { 37 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 38 | return (0, _util.sendRequest)('producers/' + ucpc + '/extracts', options, resolve, reject, _util.handleResult); 39 | }); 40 | }, 41 | 42 | edibles: function edibles(ucpc) { 43 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 44 | return new _promise2.default(function (resolve, reject) { 45 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 46 | return (0, _util.sendRequest)('producers/' + ucpc + '/edibles', options, resolve, reject, _util.handleResult); 47 | }); 48 | }, 49 | 50 | products: function products(ucpc) { 51 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 52 | return new _promise2.default(function (resolve, reject) { 53 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 54 | return (0, _util.sendRequest)('producers/' + ucpc + '/products', options, resolve, reject, _util.handleResult); 55 | }); 56 | }, 57 | 58 | availability: function availability(ucpc, lat, lng) { 59 | var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; 60 | return new _promise2.default(function (resolve, reject) { 61 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 62 | if (typeof lat === 'undefined') return reject(new Error('Latitude is required')); 63 | if (typeof lng === 'undefined') return reject(new Error('Longitude is required')); 64 | var radius = options && options.radius ? '/' + options.radius : ''; 65 | return (0, _util.sendRequest)('producers/' + ucpc + '/availability/geo/' + lat + '/' + lng + radius, options, resolve, reject, _util.handleResult); 66 | }); 67 | } 68 | 69 | }; 70 | } 71 | module.exports = exports['default']; -------------------------------------------------------------------------------- /lib/edible.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _promise = require('babel-runtime/core-js/promise'); 8 | 9 | var _promise2 = _interopRequireDefault(_promise); 10 | 11 | exports.default = edible; 12 | 13 | var _util = require('./util'); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function edible() { 18 | return { 19 | 20 | all: function all() { 21 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 22 | return new _promise2.default(function (resolve, reject) { 23 | return (0, _util.sendRequest)('edibles', options, resolve, reject, _util.handleResult); 24 | }); 25 | }, 26 | 27 | type: function type(edibleType) { 28 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 29 | return new _promise2.default(function (resolve, reject) { 30 | return (0, _util.sendRequest)('edibles/type/' + edibleType, options, resolve, reject, _util.handleResult); 31 | }); 32 | }, 33 | 34 | edible: function edible(ucpc) { 35 | return new _promise2.default(function (resolve, reject) { 36 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 37 | return (0, _util.sendRequest)('edibles/' + ucpc, null, resolve, reject, _util.handleResult); 38 | }); 39 | }, 40 | 41 | user: function user(ucpc) { 42 | return new _promise2.default(function (resolve, reject) { 43 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 44 | return (0, _util.sendRequest)('edibles/' + ucpc + '/user', null, resolve, reject, _util.handleResult); 45 | }); 46 | }, 47 | 48 | reviews: function reviews(ucpc) { 49 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 50 | return new _promise2.default(function (resolve, reject) { 51 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 52 | return (0, _util.sendRequest)('edibles/' + ucpc + '/reviews', options, resolve, reject, _util.handleResult); 53 | }); 54 | }, 55 | 56 | effectsFlavors: function effectsFlavors(ucpc) { 57 | return new _promise2.default(function (resolve, reject) { 58 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 59 | return (0, _util.sendRequest)('edibles/' + ucpc + '/effectsFlavors', null, resolve, reject, _util.handleResult); 60 | }); 61 | }, 62 | 63 | producer: function producer(ucpc) { 64 | return new _promise2.default(function (resolve, reject) { 65 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 66 | return (0, _util.sendRequest)('edibles/' + ucpc + '/producer', null, resolve, reject, _util.handleResult); 67 | }); 68 | }, 69 | 70 | strain: function strain(ucpc) { 71 | return new _promise2.default(function (resolve, reject) { 72 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 73 | return (0, _util.sendRequest)('edibles/' + ucpc + '/strain', null, resolve, reject, _util.handleResult); 74 | }); 75 | }, 76 | 77 | availability: function availability(ucpc, lat, lng) { 78 | var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; 79 | return new _promise2.default(function (resolve, reject) { 80 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 81 | if (typeof lat === 'undefined') return reject(new Error('Latitude is required')); 82 | if (typeof lng === 'undefined') return reject(new Error('Longitude is required')); 83 | var radius = options && options.radius ? '/' + options.radius : ''; 84 | return (0, _util.sendRequest)('edibles/' + ucpc + '/availability/geo/' + lat + '/' + lng + radius, options, resolve, reject, _util.handleResult); 85 | }); 86 | } 87 | 88 | }; 89 | } 90 | module.exports = exports['default']; -------------------------------------------------------------------------------- /lib/flower.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _promise = require('babel-runtime/core-js/promise'); 8 | 9 | var _promise2 = _interopRequireDefault(_promise); 10 | 11 | exports.default = flower; 12 | 13 | var _util = require('./util'); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function flower() { 18 | return { 19 | 20 | all: function all() { 21 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 22 | return new _promise2.default(function (resolve, reject) { 23 | return (0, _util.sendRequest)('flowers', options, resolve, reject, _util.handleResult); 24 | }); 25 | }, 26 | 27 | type: function type(flowerType) { 28 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 29 | return new _promise2.default(function (resolve, reject) { 30 | return (0, _util.sendRequest)('flowers/type/' + flowerType, options, resolve, reject, _util.handleResult); 31 | }); 32 | }, 33 | 34 | flower: function flower(ucpc) { 35 | return new _promise2.default(function (resolve, reject) { 36 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 37 | return (0, _util.sendRequest)('flowers/' + ucpc, null, resolve, reject, _util.handleResult); 38 | }); 39 | }, 40 | 41 | user: function user(ucpc) { 42 | return new _promise2.default(function (resolve, reject) { 43 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 44 | return (0, _util.sendRequest)('flowers/' + ucpc + '/user', null, resolve, reject, _util.handleResult); 45 | }); 46 | }, 47 | 48 | reviews: function reviews(ucpc) { 49 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 50 | return new _promise2.default(function (resolve, reject) { 51 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 52 | return (0, _util.sendRequest)('flowers/' + ucpc + '/reviews', options, resolve, reject, _util.handleResult); 53 | }); 54 | }, 55 | 56 | effectsFlavors: function effectsFlavors(ucpc) { 57 | return new _promise2.default(function (resolve, reject) { 58 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 59 | return (0, _util.sendRequest)('flowers/' + ucpc + '/effectsFlavors', null, resolve, reject, _util.handleResult); 60 | }); 61 | }, 62 | 63 | producer: function producer(ucpc) { 64 | return new _promise2.default(function (resolve, reject) { 65 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 66 | return (0, _util.sendRequest)('flowers/' + ucpc + '/producer', null, resolve, reject, _util.handleResult); 67 | }); 68 | }, 69 | 70 | strain: function strain(ucpc) { 71 | return new _promise2.default(function (resolve, reject) { 72 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 73 | return (0, _util.sendRequest)('flowers/' + ucpc + '/strain', null, resolve, reject, _util.handleResult); 74 | }); 75 | }, 76 | 77 | availability: function availability(ucpc, lat, lng) { 78 | var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; 79 | return new _promise2.default(function (resolve, reject) { 80 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 81 | if (typeof lat === 'undefined') return reject(new Error('Latitude is required')); 82 | if (typeof lng === 'undefined') return reject(new Error('Longitude is required')); 83 | var radius = options && options.radius ? '/' + options.radius : ''; 84 | return (0, _util.sendRequest)('flowers/' + ucpc + '/availability/geo/' + lat + '/' + lng + radius, options, resolve, reject, _util.handleResult); 85 | }); 86 | } 87 | 88 | }; 89 | } 90 | module.exports = exports['default']; -------------------------------------------------------------------------------- /lib/extract.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _promise = require('babel-runtime/core-js/promise'); 8 | 9 | var _promise2 = _interopRequireDefault(_promise); 10 | 11 | exports.default = extract; 12 | 13 | var _util = require('./util'); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function extract() { 18 | return { 19 | 20 | all: function all() { 21 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 22 | return new _promise2.default(function (resolve, reject) { 23 | return (0, _util.sendRequest)('extracts', options, resolve, reject, _util.handleResult); 24 | }); 25 | }, 26 | 27 | type: function type(extractType) { 28 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 29 | return new _promise2.default(function (resolve, reject) { 30 | return (0, _util.sendRequest)('extracts/type/' + extractType, options, resolve, reject, _util.handleResult); 31 | }); 32 | }, 33 | 34 | extract: function extract(ucpc) { 35 | return new _promise2.default(function (resolve, reject) { 36 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 37 | return (0, _util.sendRequest)('extracts/' + ucpc, null, resolve, reject, _util.handleResult); 38 | }); 39 | }, 40 | 41 | user: function user(ucpc) { 42 | return new _promise2.default(function (resolve, reject) { 43 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 44 | return (0, _util.sendRequest)('extracts/' + ucpc + '/user', null, resolve, reject, _util.handleResult); 45 | }); 46 | }, 47 | 48 | reviews: function reviews(ucpc) { 49 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 50 | return new _promise2.default(function (resolve, reject) { 51 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 52 | return (0, _util.sendRequest)('extracts/' + ucpc + '/reviews', options, resolve, reject, _util.handleResult); 53 | }); 54 | }, 55 | 56 | effectsFlavors: function effectsFlavors(ucpc) { 57 | return new _promise2.default(function (resolve, reject) { 58 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 59 | return (0, _util.sendRequest)('extracts/' + ucpc + '/effectsFlavors', null, resolve, reject, _util.handleResult); 60 | }); 61 | }, 62 | 63 | producer: function producer(ucpc) { 64 | return new _promise2.default(function (resolve, reject) { 65 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 66 | return (0, _util.sendRequest)('extracts/' + ucpc + '/producer', null, resolve, reject, _util.handleResult); 67 | }); 68 | }, 69 | 70 | strain: function strain(ucpc) { 71 | return new _promise2.default(function (resolve, reject) { 72 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 73 | return (0, _util.sendRequest)('extracts/' + ucpc + '/strain', null, resolve, reject, _util.handleResult); 74 | }); 75 | }, 76 | 77 | availability: function availability(ucpc, lat, lng) { 78 | var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; 79 | return new _promise2.default(function (resolve, reject) { 80 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 81 | if (typeof lat === 'undefined') return reject(new Error('Latitude is required')); 82 | if (typeof lng === 'undefined') return reject(new Error('Longitude is required')); 83 | var radius = options && options.radius ? '/' + options.radius : ''; 84 | return (0, _util.sendRequest)('extracts/' + ucpc + '/availability/geo/' + lat + '/' + lng + radius, options, resolve, reject, _util.handleResult); 85 | }); 86 | } 87 | 88 | }; 89 | } 90 | module.exports = exports['default']; -------------------------------------------------------------------------------- /lib/product.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _promise = require('babel-runtime/core-js/promise'); 8 | 9 | var _promise2 = _interopRequireDefault(_promise); 10 | 11 | exports.default = product; 12 | 13 | var _util = require('./util'); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function product() { 18 | return { 19 | 20 | all: function all() { 21 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 22 | return new _promise2.default(function (resolve, reject) { 23 | return (0, _util.sendRequest)('products', options, resolve, reject, _util.handleResult); 24 | }); 25 | }, 26 | 27 | type: function type(productType) { 28 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 29 | return new _promise2.default(function (resolve, reject) { 30 | return (0, _util.sendRequest)('products/type/' + productType, options, resolve, reject, _util.handleResult); 31 | }); 32 | }, 33 | 34 | product: function product(ucpc) { 35 | return new _promise2.default(function (resolve, reject) { 36 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 37 | return (0, _util.sendRequest)('products/' + ucpc, null, resolve, reject, _util.handleResult); 38 | }); 39 | }, 40 | 41 | user: function user(ucpc) { 42 | return new _promise2.default(function (resolve, reject) { 43 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 44 | return (0, _util.sendRequest)('products/' + ucpc + '/user', null, resolve, reject, _util.handleResult); 45 | }); 46 | }, 47 | 48 | reviews: function reviews(ucpc) { 49 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 50 | return new _promise2.default(function (resolve, reject) { 51 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 52 | return (0, _util.sendRequest)('products/' + ucpc + '/reviews', options, resolve, reject, _util.handleResult); 53 | }); 54 | }, 55 | 56 | effectsFlavors: function effectsFlavors(ucpc) { 57 | return new _promise2.default(function (resolve, reject) { 58 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 59 | return (0, _util.sendRequest)('products/' + ucpc + '/effectsFlavors', null, resolve, reject, _util.handleResult); 60 | }); 61 | }, 62 | 63 | producer: function producer(ucpc) { 64 | return new _promise2.default(function (resolve, reject) { 65 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 66 | return (0, _util.sendRequest)('products/' + ucpc + '/producer', null, resolve, reject, _util.handleResult); 67 | }); 68 | }, 69 | 70 | strain: function strain(ucpc) { 71 | return new _promise2.default(function (resolve, reject) { 72 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 73 | return (0, _util.sendRequest)('products/' + ucpc + '/strain', null, resolve, reject, _util.handleResult); 74 | }); 75 | }, 76 | 77 | availability: function availability(ucpc, lat, lng) { 78 | var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; 79 | return new _promise2.default(function (resolve, reject) { 80 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 81 | if (typeof lat === 'undefined') return reject(new Error('Latitude is required')); 82 | if (typeof lng === 'undefined') return reject(new Error('Longitude is required')); 83 | var radius = options && options.radius ? '/' + options.radius : ''; 84 | return (0, _util.sendRequest)('products/' + ucpc + '/availability/geo/' + lat + '/' + lng + radius, options, resolve, reject, _util.handleResult); 85 | }); 86 | } 87 | 88 | }; 89 | } 90 | module.exports = exports['default']; -------------------------------------------------------------------------------- /src/extract.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { 3 | handleResult, 4 | sendRequest, 5 | validateUcpc, 6 | } from './util'; 7 | 8 | export default function extract(): Object { 9 | return { 10 | 11 | all: (options: Object = {}): Promise => 12 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => 13 | sendRequest( 14 | 'extracts', 15 | options, 16 | resolve, 17 | reject, 18 | handleResult 19 | ) 20 | ), 21 | 22 | type: (extractType: string, options: Object = {}): Promise => 23 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => 24 | sendRequest( 25 | `extracts/type/${extractType}`, 26 | options, 27 | resolve, 28 | reject, 29 | handleResult 30 | ) 31 | ), 32 | 33 | extract: (ucpc: string): Promise => 34 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 35 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 36 | return sendRequest( 37 | `extracts/${ucpc}`, 38 | null, 39 | resolve, 40 | reject, 41 | handleResult 42 | ); 43 | }), 44 | 45 | user: (ucpc: string): Promise => 46 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 47 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 48 | return sendRequest( 49 | `extracts/${ucpc}/user`, 50 | null, 51 | resolve, 52 | reject, 53 | handleResult 54 | ); 55 | }), 56 | 57 | reviews: (ucpc: string, options: Object = {}): Promise => 58 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 59 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 60 | return sendRequest( 61 | `extracts/${ucpc}/reviews`, 62 | options, 63 | resolve, 64 | reject, 65 | handleResult 66 | ); 67 | }), 68 | 69 | effectsFlavors: (ucpc: string): Promise => 70 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 71 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 72 | return sendRequest(`extracts/${ucpc}/effectsFlavors`, 73 | null, 74 | resolve, 75 | reject, 76 | handleResult 77 | ); 78 | }), 79 | 80 | producer: (ucpc: string): Promise => 81 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 82 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 83 | return sendRequest( 84 | `extracts/${ucpc}/producer`, 85 | null, 86 | resolve, 87 | reject, 88 | handleResult 89 | ); 90 | }), 91 | 92 | strain: (ucpc: string): Promise => 93 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 94 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 95 | return sendRequest( 96 | `extracts/${ucpc}/strain`, 97 | null, 98 | resolve, 99 | reject, 100 | handleResult 101 | ); 102 | }), 103 | 104 | availability: (ucpc: string, lat: string, lng: string, options: Object = {}): Promise => 105 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 106 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 107 | if (typeof lat === 'undefined') return reject(new Error('Latitude is required')); 108 | if (typeof lng === 'undefined') return reject(new Error('Longitude is required')); 109 | const radius = (options && options.radius) ? `/${options.radius}` : ''; 110 | return sendRequest(`extracts/${ucpc}/availability/geo/${lat}/${lng}${radius}`, 111 | options, 112 | resolve, 113 | reject, 114 | handleResult 115 | ); 116 | }), 117 | 118 | }; 119 | } 120 | -------------------------------------------------------------------------------- /src/flower.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { 3 | handleResult, 4 | sendRequest, 5 | validateUcpc, 6 | } from './util'; 7 | 8 | export default function flower(): Object { 9 | return { 10 | 11 | all: (options: Object = {}): Promise => 12 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => 13 | sendRequest( 14 | 'flowers', 15 | options, 16 | resolve, 17 | reject, 18 | handleResult 19 | ) 20 | ), 21 | 22 | type: (flowerType: string, options: Object = {}): Promise => 23 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => 24 | sendRequest( 25 | `flowers/type/${flowerType}`, 26 | options, 27 | resolve, 28 | reject, 29 | handleResult 30 | ) 31 | ), 32 | 33 | flower: (ucpc: string): Promise => 34 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 35 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 36 | return sendRequest( 37 | `flowers/${ucpc}`, 38 | null, 39 | resolve, 40 | reject, 41 | handleResult 42 | ); 43 | }), 44 | 45 | user: (ucpc: string): Promise => 46 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 47 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 48 | return sendRequest( 49 | `flowers/${ucpc}/user`, 50 | null, 51 | resolve, 52 | reject, 53 | handleResult 54 | ); 55 | }), 56 | 57 | reviews: (ucpc: string, options: Object = {}): Promise => 58 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 59 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 60 | return sendRequest( 61 | `flowers/${ucpc}/reviews`, 62 | options, 63 | resolve, 64 | reject, 65 | handleResult 66 | ); 67 | }), 68 | 69 | effectsFlavors: (ucpc: string): Promise => 70 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 71 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 72 | return sendRequest( 73 | `flowers/${ucpc}/effectsFlavors`, 74 | null, 75 | resolve, 76 | reject, 77 | handleResult 78 | ); 79 | }), 80 | 81 | producer: (ucpc: string): Promise => 82 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 83 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 84 | return sendRequest( 85 | `flowers/${ucpc}/producer`, 86 | null, 87 | resolve, 88 | reject, 89 | handleResult 90 | ); 91 | }), 92 | 93 | strain: (ucpc: string): Promise => 94 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 95 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 96 | return sendRequest( 97 | `flowers/${ucpc}/strain`, 98 | null, 99 | resolve, 100 | reject, 101 | handleResult 102 | ); 103 | }), 104 | 105 | availability: (ucpc: string, lat: string, lng: string, options: Object = {}): Promise => 106 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 107 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 108 | if (typeof lat === 'undefined') return reject(new Error('Latitude is required')); 109 | if (typeof lng === 'undefined') return reject(new Error('Longitude is required')); 110 | const radius = (options && options.radius) ? `/${options.radius}` : ''; 111 | return sendRequest(`flowers/${ucpc}/availability/geo/${lat}/${lng}${radius}`, 112 | options, 113 | resolve, 114 | reject, 115 | handleResult 116 | ); 117 | }), 118 | 119 | }; 120 | } 121 | -------------------------------------------------------------------------------- /src/product.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { 3 | handleResult, 4 | sendRequest, 5 | validateUcpc, 6 | } from './util'; 7 | 8 | export default function product(): Object { 9 | return { 10 | 11 | all: (options: Object = {}): Promise => 12 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => 13 | sendRequest( 14 | 'products', 15 | options, 16 | resolve, 17 | reject, 18 | handleResult 19 | ) 20 | ), 21 | 22 | type: (productType: string, options: Object = {}): Promise => 23 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => 24 | sendRequest(`products/type/${productType}`, 25 | options, 26 | resolve, 27 | reject, 28 | handleResult 29 | ) 30 | ), 31 | 32 | product: (ucpc: string): Promise => 33 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 34 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 35 | return sendRequest( 36 | `products/${ucpc}`, 37 | null, 38 | resolve, 39 | reject, 40 | handleResult 41 | ); 42 | }), 43 | 44 | user: (ucpc: string): Promise => 45 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 46 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 47 | return sendRequest( 48 | `products/${ucpc}/user`, 49 | null, 50 | resolve, 51 | reject, 52 | handleResult 53 | ); 54 | }), 55 | 56 | reviews: (ucpc: string, options: Object = {}): Promise => 57 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 58 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 59 | return sendRequest( 60 | `products/${ucpc}/reviews`, 61 | options, 62 | resolve, 63 | reject, 64 | handleResult 65 | ); 66 | }), 67 | 68 | effectsFlavors: (ucpc: string): Promise => 69 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 70 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 71 | return sendRequest( 72 | `products/${ucpc}/effectsFlavors`, 73 | null, 74 | resolve, 75 | reject, 76 | handleResult 77 | ); 78 | }), 79 | 80 | producer: (ucpc: string): Promise => 81 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 82 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 83 | return sendRequest( 84 | `products/${ucpc}/producer`, 85 | null, 86 | resolve, 87 | reject, 88 | handleResult 89 | ); 90 | }), 91 | 92 | strain: (ucpc: string): Promise => 93 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 94 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 95 | return sendRequest( 96 | `products/${ucpc}/strain`, 97 | null, 98 | resolve, 99 | reject, 100 | handleResult 101 | ); 102 | }), 103 | 104 | availability: (ucpc: string, lat: string, lng: string, options: Object = {}): Promise => 105 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 106 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 107 | if (typeof lat === 'undefined') return reject(new Error('Latitude is required')); 108 | if (typeof lng === 'undefined') return reject(new Error('Longitude is required')); 109 | const radius = (options && options.radius) ? `/${options.radius}` : ''; 110 | return sendRequest( 111 | `products/${ucpc}/availability/geo/${lat}/${lng}${radius}`, 112 | options, 113 | resolve, 114 | reject, 115 | handleResult 116 | ); 117 | }), 118 | 119 | }; 120 | } 121 | -------------------------------------------------------------------------------- /src/edible.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { 3 | handleResult, 4 | sendRequest, 5 | validateUcpc, 6 | } from './util'; 7 | 8 | export default function edible(): Object { 9 | return { 10 | 11 | all: (options: Object = {}): Promise => 12 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => 13 | sendRequest( 14 | 'edibles', 15 | options, 16 | resolve, 17 | reject, 18 | handleResult 19 | ) 20 | ), 21 | 22 | type: (edibleType: string, options: Object = {}): Promise => 23 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => 24 | sendRequest( 25 | `edibles/type/${edibleType}`, 26 | options, 27 | resolve, 28 | reject, 29 | handleResult 30 | ) 31 | ), 32 | 33 | edible: (ucpc: string): Promise => 34 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 35 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 36 | return sendRequest( 37 | `edibles/${ucpc}`, 38 | null, 39 | resolve, 40 | reject, 41 | handleResult 42 | ); 43 | }), 44 | 45 | user: (ucpc: string): Promise => 46 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 47 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 48 | return sendRequest( 49 | `edibles/${ucpc}/user`, 50 | null, 51 | resolve, 52 | reject, 53 | handleResult 54 | ); 55 | }), 56 | 57 | reviews: (ucpc: string, options: Object = {}): Promise => 58 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 59 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 60 | return sendRequest( 61 | `edibles/${ucpc}/reviews`, 62 | options, 63 | resolve, 64 | reject, 65 | handleResult 66 | ); 67 | }), 68 | 69 | effectsFlavors: (ucpc: string): Promise => 70 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 71 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 72 | return sendRequest( 73 | `edibles/${ucpc}/effectsFlavors`, 74 | null, 75 | resolve, 76 | reject, 77 | handleResult 78 | ); 79 | }), 80 | 81 | producer: (ucpc: string): Promise => 82 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 83 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 84 | return sendRequest( 85 | `edibles/${ucpc}/producer`, 86 | null, 87 | resolve, 88 | reject, 89 | handleResult 90 | ); 91 | }), 92 | 93 | strain: (ucpc: string): Promise => 94 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 95 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 96 | return sendRequest( 97 | `edibles/${ucpc}/strain`, 98 | null, 99 | resolve, 100 | reject, 101 | handleResult 102 | ); 103 | }), 104 | 105 | availability: (ucpc: string, lat: string, lng: string, options: Object = {}): Promise => 106 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 107 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 108 | if (typeof lat === 'undefined') return reject(new Error('Latitude is required')); 109 | if (typeof lng === 'undefined') return reject(new Error('Longitude is required')); 110 | const radius = (options && options.radius) ? `/${options.radius}` : ''; 111 | return sendRequest( 112 | `edibles/${ucpc}/availability/geo/${lat}/${lng}${radius}`, 113 | options, 114 | resolve, 115 | reject, 116 | handleResult 117 | ); 118 | }), 119 | 120 | }; 121 | } 122 | -------------------------------------------------------------------------------- /tests/producer.spec.js: -------------------------------------------------------------------------------- 1 | import { Producer } from 'index'; 2 | 3 | describe('Producer.all()', () => { 4 | it('returns array', () => 5 | Producer.all().then((data) => expect(data).to.be.instanceof(Array)) 6 | ); 7 | it('returns array sorted by createdAt', () => 8 | Producer.all({ sort: 'createdAt' }).then((data) => expect(data).to.be.instanceof(Array)) 9 | ); 10 | it('returns array sorted by createdAt', () => 11 | Producer.all({ sort: '-createdAt', page: 5 }) 12 | .then((data) => expect(data).to.be.instanceof(Array)) 13 | ); 14 | it('returns array', () => 15 | Producer.all({ page: 3 }).then((data) => expect(data).to.be.instanceof(Array)) 16 | ); 17 | }); 18 | 19 | describe('Producer.producer()', () => { 20 | it('returns object', () => 21 | Producer.producer('0000000000L6M7E0000000000') 22 | .then((data) => expect(typeof(data)).to.equal('object')) 23 | ); 24 | it('returns error message', () => 25 | Producer.producer('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 26 | ); 27 | }); 28 | 29 | describe('Producer.extracts()', () => { 30 | it('returns array', () => 31 | Producer.extracts('0000000000L6M7E0000000000') 32 | .then((data) => expect(data).to.be.instanceof(Array)) 33 | ); 34 | it('returns array', () => 35 | Producer.extracts('0000000000L6M7E0000000000', { page: 2 }) 36 | .then((data) => expect(data).to.be.instanceof(Array)) 37 | ); 38 | it('returns error message', () => 39 | Producer.extracts('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 40 | ); 41 | }); 42 | 43 | describe('Producer.edibles()', () => { 44 | it('returns array', () => 45 | Producer.edibles('0000000000L6M7E0000000000') 46 | .then((data) => expect(data).to.be.instanceof(Array)) 47 | ); 48 | it('returns array', () => 49 | Producer.edibles('0000000000L6M7E0000000000', { page: 2 }) 50 | .then((data) => expect(data).to.be.instanceof(Array)) 51 | ); 52 | it('returns error message', () => 53 | Producer.edibles('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 54 | ); 55 | }); 56 | 57 | describe('Producer.products()', () => { 58 | it('returns array', () => 59 | Producer.products('0000000000L6M7E0000000000') 60 | .then((data) => expect(data).to.be.instanceof(Array)) 61 | ); 62 | it('returns array', () => 63 | Producer.products('0000000000L6M7E0000000000', { page: 2 }) 64 | .then((data) => expect(data).to.be.instanceof(Array)) 65 | ); 66 | it('returns error message', () => 67 | Producer.products('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 68 | ); 69 | }); 70 | 71 | describe('Producer.availability()', () => { 72 | it('returns array', () => 73 | Producer.availability('0000000000L6M7E0000000000', 37.7749295, -122.4194155) 74 | .then((data) => expect(data).to.be.instanceof(Array)) 75 | ); 76 | it('returns array', () => 77 | Producer.availability('0000000000L6M7E0000000000', '37.7749295', '-122.4194155') 78 | .then((data) => expect(data).to.be.instanceof(Array)) 79 | ); 80 | it('returns array', () => 81 | Producer.availability('0000000000L6M7E0000000000', 37.7749295, -122.4194155, { page: 2 }) 82 | .then((data) => expect(data).to.be.instanceof(Array)) 83 | ); 84 | it('returns array', () => 85 | Producer.availability('0000000000L6M7E0000000000', '37.7749295', '-122.4194155', { page: 2 }) 86 | .then((data) => expect(data).to.be.instanceof(Array)) 87 | ); 88 | it('returns error message', () => 89 | Producer.availability('VUJCJ4TYMG00000000000000', [37.7749295], -122.4194155) 90 | .catch((err) => expect(err).to.be.an('error')) 91 | ); 92 | it('returns error message', () => 93 | Producer.availability('VUJCJ4TYMG00000000000000', 37.7749295, [-122.4194155]) 94 | .catch((err) => expect(err).to.be.an('error')) 95 | ); 96 | it('returns error message', () => 97 | Producer.availability('VUJCJ4TYMG00000000000000').catch((err) => expect(err).to.be.an('error')) 98 | ); 99 | it('returns error message', () => 100 | Producer.availability('VUJCJ4TYMG00000000000000', 37.7749295) 101 | .catch((err) => expect(err).to.be.an('error')) 102 | ); 103 | it('returns error message', () => 104 | Producer.availability('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 105 | ); 106 | }); 107 | -------------------------------------------------------------------------------- /lib/strain.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _promise = require('babel-runtime/core-js/promise'); 8 | 9 | var _promise2 = _interopRequireDefault(_promise); 10 | 11 | exports.default = strain; 12 | 13 | var _util = require('./util'); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function strain() { 18 | return { 19 | 20 | all: function all() { 21 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 22 | return new _promise2.default(function (resolve, reject) { 23 | return (0, _util.sendRequest)('strains', options, resolve, reject, _util.handleResult); 24 | }); 25 | }, 26 | 27 | search: function search(query) { 28 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 29 | return new _promise2.default(function (resolve, reject) { 30 | if (!query || typeof query !== 'string') { 31 | return reject(new Error('A string query is required.')); 32 | } 33 | return (0, _util.sendRequest)('strains/search/' + query, options, resolve, reject, _util.handleResult); 34 | }); 35 | }, 36 | 37 | strain: function strain(ucpc) { 38 | return new _promise2.default(function (resolve, reject) { 39 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 40 | return (0, _util.sendRequest)('strains/' + ucpc, null, resolve, reject, _util.handleResult); 41 | }); 42 | }, 43 | 44 | user: function user(ucpc) { 45 | return new _promise2.default(function (resolve, reject) { 46 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 47 | return (0, _util.sendRequest)('strains/' + ucpc + '/user', null, resolve, reject, _util.handleResult); 48 | }); 49 | }, 50 | 51 | reviews: function reviews(ucpc) { 52 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 53 | return new _promise2.default(function (resolve, reject) { 54 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 55 | return (0, _util.sendRequest)('strains/' + ucpc + '/reviews', options, resolve, reject, _util.handleResult); 56 | }); 57 | }, 58 | 59 | effectsFlavors: function effectsFlavors(ucpc) { 60 | return new _promise2.default(function (resolve, reject) { 61 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 62 | return (0, _util.sendRequest)('strains/' + ucpc + '/effectsFlavors', null, resolve, reject, _util.handleResult); 63 | }); 64 | }, 65 | 66 | seedCompany: function seedCompany(ucpc) { 67 | return new _promise2.default(function (resolve, reject) { 68 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 69 | return (0, _util.sendRequest)('strains/' + ucpc + '/seedCompany', null, resolve, reject, _util.handleResult); 70 | }); 71 | }, 72 | 73 | genetics: function genetics(ucpc) { 74 | return new _promise2.default(function (resolve, reject) { 75 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 76 | return (0, _util.sendRequest)('strains/' + ucpc + '/genetics', null, resolve, reject, _util.handleResult); 77 | }); 78 | }, 79 | 80 | children: function children(ucpc) { 81 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 82 | return new _promise2.default(function (resolve, reject) { 83 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 84 | return (0, _util.sendRequest)('strains/' + ucpc + '/children', options, resolve, reject, _util.handleResult); 85 | }); 86 | }, 87 | 88 | availability: function availability(ucpc, lat, lng) { 89 | var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; 90 | return new _promise2.default(function (resolve, reject) { 91 | if (!(0, _util.validateUcpc)(ucpc)) return reject(new Error('Invalid UCPC.')); 92 | if (typeof lat === 'undefined') return reject(new Error('Latitude is required')); 93 | if (typeof lng === 'undefined') return reject(new Error('Longitude is required')); 94 | var radius = options && options.radius ? '/' + options.radius : ''; 95 | return (0, _util.sendRequest)('strains/' + ucpc + '/availability/geo/' + lat + '/' + lng + '/' + radius, options, resolve, reject, _util.handleResult); 96 | }); 97 | } 98 | 99 | }; 100 | } 101 | module.exports = exports['default']; -------------------------------------------------------------------------------- /src/strain.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { 3 | handleResult, 4 | sendRequest, 5 | validateUcpc, 6 | } from './util'; 7 | 8 | export default function strain(): Object { 9 | return { 10 | 11 | all: (options: Object = {}): Promise => 12 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => 13 | sendRequest( 14 | 'strains', 15 | options, 16 | resolve, 17 | reject, 18 | handleResult 19 | ) 20 | ), 21 | 22 | search: (query: string, options: Object = {}): Promise => 23 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 24 | if (!query || typeof(query) !== 'string') { 25 | return reject(new Error('A string query is required.')); 26 | } 27 | return sendRequest( 28 | `strains/search/${query}`, 29 | options, 30 | resolve, 31 | reject, 32 | handleResult 33 | ); 34 | }), 35 | 36 | strain: (ucpc: string): Promise => 37 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 38 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 39 | return sendRequest( 40 | `strains/${ucpc}`, 41 | null, 42 | resolve, 43 | reject, 44 | handleResult 45 | ); 46 | }), 47 | 48 | user: (ucpc: string): Promise => 49 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 50 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 51 | return sendRequest( 52 | `strains/${ucpc}/user`, 53 | null, 54 | resolve, 55 | reject, 56 | handleResult 57 | ); 58 | }), 59 | 60 | reviews: (ucpc: string, options: Object = {}): Promise => 61 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 62 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 63 | return sendRequest( 64 | `strains/${ucpc}/reviews`, 65 | options, 66 | resolve, 67 | reject, 68 | handleResult 69 | ); 70 | }), 71 | 72 | effectsFlavors: (ucpc: string): Promise => 73 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 74 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 75 | return sendRequest( 76 | `strains/${ucpc}/effectsFlavors`, 77 | null, 78 | resolve, 79 | reject, 80 | handleResult 81 | ); 82 | }), 83 | 84 | seedCompany: (ucpc: string): Promise => 85 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 86 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 87 | return sendRequest( 88 | `strains/${ucpc}/seedCompany`, 89 | null, 90 | resolve, 91 | reject, 92 | handleResult 93 | ); 94 | }), 95 | 96 | genetics: (ucpc: string): Promise => 97 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 98 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 99 | return sendRequest( 100 | `strains/${ucpc}/genetics`, 101 | null, 102 | resolve, 103 | reject, 104 | handleResult 105 | ); 106 | }), 107 | 108 | children: (ucpc: string, options: Object = {}): Promise => 109 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 110 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 111 | return sendRequest( 112 | `strains/${ucpc}/children`, 113 | options, 114 | resolve, 115 | reject, 116 | handleResult 117 | ); 118 | }), 119 | 120 | availability: (ucpc: string, lat: string, lng: string, options: Object = {}): Promise => 121 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 122 | if (!validateUcpc(ucpc)) return reject(new Error('Invalid UCPC.')); 123 | if (typeof lat === 'undefined') return reject(new Error('Latitude is required')); 124 | if (typeof lng === 'undefined') return reject(new Error('Longitude is required')); 125 | const radius = (options && options.radius) ? `/${options.radius}` : ''; 126 | return sendRequest(`strains/${ucpc}/availability/geo/${lat}/${lng}/${radius}`, 127 | options, 128 | resolve, 129 | reject, 130 | handleResult 131 | ); 132 | }), 133 | 134 | }; 135 | } 136 | -------------------------------------------------------------------------------- /tests/edible.spec.js: -------------------------------------------------------------------------------- 1 | import { Edible } from 'index'; 2 | 3 | describe('Edible.all()', () => { 4 | it('returns array', () => 5 | Edible.all().then((data) => expect(data).to.be.instanceof(Array)) 6 | ); 7 | it('returns array sorted by createdAt', () => 8 | Edible.all({ sort: 'createdAt' }).then((data) => expect(data).to.be.instanceof(Array)) 9 | ); 10 | it('returns array sorted by createdAt', () => 11 | Edible.all({ sort: '-createdAt', page: 5 }).then((data) => expect(data).to.be.instanceof(Array)) 12 | ); 13 | it('returns array', () => 14 | Edible.all({ page: 3 }).then((data) => expect(data).to.be.instanceof(Array)) 15 | ); 16 | }); 17 | 18 | describe('Edible.type()', () => { 19 | it('returns array', () => 20 | Edible.type('baked goods').then((data) => expect(data).to.be.instanceof(Array)) 21 | ); 22 | it('returns array sorted by createdAt', () => 23 | Edible.type('cAndy', { sort: 'createdAt' }).then((data) => expect(data).to.be.instanceof(Array)) 24 | ); 25 | it('returns array sorted by createdAt', () => 26 | Edible.type('Ice Cream', { sort: '-createdAt', page: 5 }) 27 | .then((data) => expect(data).to.be.instanceof(Array)) 28 | ); 29 | it('returns array', () => 30 | Edible.type('CHOCOLATE', { page: 3 }).then((data) => expect(data).to.be.instanceof(Array)) 31 | ); 32 | it('returns error message', () => 33 | Edible.type('not a real type').catch((err) => expect(err).to.be.an('error')) 34 | ); 35 | }); 36 | 37 | describe('Edible.edible()', () => { 38 | it('returns object', () => 39 | Edible.edible('4KXM32V9YFC3G2EUNWP400000') 40 | .then((data) => expect(typeof(data)).to.equal('object')) 41 | ); 42 | it('returns error message', () => 43 | Edible.edible('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 44 | ); 45 | }); 46 | 47 | describe('Edible.user()', () => { 48 | it('returns object', () => 49 | Edible.user('4KXM32V9YFC3G2EUNWP400000') 50 | .then((data) => expect(typeof(data)).to.equal('object')) 51 | ); 52 | it('returns error message', () => 53 | Edible.user('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 54 | ); 55 | }); 56 | 57 | describe('Edible.reviews()', () => { 58 | it('returns array', () => 59 | Edible.reviews('4KXM32V9YFC3G2EUNWP400000') 60 | .then((data) => expect(data).to.be.instanceof(Array)) 61 | ); 62 | it('returns array', () => 63 | Edible.reviews('4KXM32V9YFC3G2EUNWP400000', { page: 2 }) 64 | .then((data) => expect(data).to.be.instanceof(Array)) 65 | ); 66 | it('returns error message', () => 67 | Edible.reviews('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 68 | ); 69 | }); 70 | 71 | describe('Edible.effectsFlavors()', () => { 72 | it('returns object', () => 73 | Edible.effectsFlavors('4KXM32V9YFC3G2EUNWP400000') 74 | .then((data) => expect(typeof(data)).to.equal('object')) 75 | ); 76 | it('returns error message', () => 77 | Edible.effectsFlavors('VUJCJ4TYMG00!000000&00000') 78 | .catch((err) => expect(err).to.be.an('error')) 79 | ); 80 | }); 81 | 82 | describe('Edible.producer()', () => { 83 | it('returns object', () => 84 | Edible.producer('4KXM32V9YFC3G2EUNWP400000') 85 | .then((data) => expect(typeof(data)).to.equal('object')) 86 | ); 87 | it('returns error message', () => 88 | Edible.producer('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 89 | ); 90 | }); 91 | 92 | describe('Edible.strain()', () => { 93 | it('returns object', () => 94 | Edible.strain('4KXM32V9YFC3G2EUNWP400000') 95 | .then((data) => expect(typeof(data)).to.equal('object')) 96 | ); 97 | it('returns error message', () => 98 | Edible.strain('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 99 | ); 100 | }); 101 | 102 | describe('Edible.availability()', () => { 103 | it('returns array', () => 104 | Edible.availability('4KXM32V9YFC3G2EUNWP400000', 37.7749295, -122.4194155) 105 | .then((data) => expect(data).to.be.instanceof(Array)) 106 | ); 107 | it('returns array', () => 108 | Edible.availability('4KXM32V9YFC3G2EUNWP400000', '37.7749295', '-122.4194155') 109 | .then((data) => expect(data).to.be.instanceof(Array)) 110 | ); 111 | it('returns array', () => 112 | Edible.availability('4KXM32V9YFC3G2EUNWP400000', 37.7749295, -122.4194155, { page: 2 }) 113 | .then((data) => expect(data).to.be.instanceof(Array)) 114 | ); 115 | it('returns array', () => 116 | Edible.availability('4KXM32V9YFC3G2EUNWP400000', '37.7749295', '-122.4194155', { page: 2 }) 117 | .then((data) => expect(data).to.be.instanceof(Array)) 118 | ); 119 | it('returns error message', () => 120 | Edible.availability('VUJCJ4TYMG00000000000000', [37.7749295], -122.4194155) 121 | .catch((err) => expect(err).to.be.an('error')) 122 | ); 123 | it('returns error message', () => 124 | Edible.availability('VUJCJ4TYMG00000000000000', 37.7749295, [-122.4194155]) 125 | .catch((err) => expect(err).to.be.an('error')) 126 | ); 127 | it('returns error message', () => 128 | Edible.availability('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 129 | ); 130 | }); 131 | -------------------------------------------------------------------------------- /tests/strain.spec.js: -------------------------------------------------------------------------------- 1 | import { Strain } from 'index'; 2 | 3 | describe('Strain.all()', () => { 4 | it('returns array', () => 5 | Strain.all().then((data) => expect(data).to.be.instanceof(Array)) 6 | ); 7 | it('returns array sorted by name', () => 8 | Strain.all({ sort: 'name' }).then((data) => { 9 | expect(data[0].name).to.be.below(data[1].name); 10 | expect(data[0].name).to.be.below(data[data.length - 1].name); 11 | }) 12 | ); 13 | it('returns array sorted by name', () => 14 | Strain.all({ sort: 'name', page: 5 }).then((data) => { 15 | expect(data[0].name).to.be.below(data[1].name); 16 | expect(data[0].name).to.be.below(data[data.length - 1].name); 17 | }) 18 | ); 19 | it('returns array', () => 20 | Strain.all({ page: 3 }).then((data) => expect(data).to.be.instanceof(Array)) 21 | ); 22 | }); 23 | 24 | describe('Strain.search()', () => { 25 | it('returns array', () => 26 | Strain.search('orange').then((data) => expect(data).to.be.instanceof(Array)) 27 | ); 28 | it('returns error message', () => 29 | Strain.search({ testing: 'testing' }).catch((err) => expect(err).to.be.an('error')) 30 | ); 31 | it('returns array', () => 32 | Strain.search('orange', { page: 2 }).then((data) => expect(data).to.be.instanceof(Array)) 33 | ); 34 | }); 35 | 36 | describe('Strain.strain()', () => { 37 | it('returns object', () => 38 | Strain.strain('VUJCJ4TYMG000000000000000') 39 | .then((data) => expect(typeof(data)).to.equal('object')) 40 | ); 41 | it('returns error message', () => 42 | Strain.strain('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 43 | ); 44 | }); 45 | 46 | describe('Strain.user()', () => { 47 | it('returns object', () => 48 | Strain.user('VUJCJ4TYMG000000000000000') 49 | .then((data) => expect(typeof(data)).to.equal('object')) 50 | ); 51 | it('returns error message', () => 52 | Strain.user('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 53 | ); 54 | }); 55 | 56 | describe('Strain.reviews()', () => { 57 | it('returns array', () => 58 | Strain.reviews('VUJCJ4TYMG000000000000000') 59 | .then((data) => expect(data).to.be.instanceof(Array)) 60 | ); 61 | it('returns array', () => 62 | Strain.reviews('VUJCJ4TYMG000000000000000', { page: 2 }) 63 | .then((data) => expect(data).to.be.instanceof(Array)) 64 | ); 65 | it('returns error message', () => 66 | Strain.reviews('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 67 | ); 68 | }); 69 | 70 | describe('Strain.effectsFlavors()', () => { 71 | it('returns object', () => 72 | Strain.effectsFlavors('VUJCJ4TYMG000000000000000') 73 | .then((data) => expect(typeof(data)).to.equal('object')) 74 | ); 75 | it('returns error message', () => 76 | Strain.effectsFlavors('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 77 | ); 78 | }); 79 | 80 | describe('Strain.seedCompany()', () => { 81 | it('returns object', () => 82 | Strain.seedCompany('VUJCJ4TYMG000000000000000') 83 | .then((data) => expect(typeof(data)).to.equal('object')) 84 | ); 85 | it('returns error message', () => 86 | Strain.seedCompany('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 87 | ); 88 | }); 89 | 90 | describe('Strain.genetics()', () => { 91 | it('returns object', () => 92 | Strain.genetics('VUJCJ4TYMG000000000000000') 93 | .then((data) => expect(data).to.be.instanceof(Array)) 94 | ); 95 | it('returns error message', () => 96 | Strain.genetics('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 97 | ); 98 | }); 99 | 100 | describe('Strain.children()', () => { 101 | it('returns array', () => 102 | Strain.children('VUJCJ4TYMG000000000000000') 103 | .then((data) => expect(data).to.be.instanceof(Array)) 104 | ); 105 | it('returns array', () => 106 | Strain.children('VUJCJ4TYMG000000000000000', { page: 2 }) 107 | .then((data) => expect(data).to.be.instanceof(Array)) 108 | ); 109 | it('returns error message', () => 110 | Strain.children('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 111 | ); 112 | }); 113 | 114 | describe('Strain.availability()', () => { 115 | it('returns array', () => 116 | Strain.availability('VUJCJ4TYMG000000000000000', 37.7749295, -122.4194155) 117 | .then((data) => expect(data).to.be.instanceof(Array)) 118 | ); 119 | it('returns array', () => 120 | Strain.availability('VUJCJ4TYMG000000000000000', '37.7749295', '-122.4194155') 121 | .then((data) => expect(data).to.be.instanceof(Array)) 122 | ); 123 | it('returns array', () => 124 | Strain.availability('VUJCJ4TYMG000000000000000', 37.7749295, -122.4194155, { page: 2 }) 125 | .then((data) => expect(data).to.be.instanceof(Array)) 126 | ); 127 | it('returns array', () => 128 | Strain.availability('VUJCJ4TYMG000000000000000', '37.7749295', '-122.4194155', { page: 2 }) 129 | .then((data) => expect(data).to.be.instanceof(Array)) 130 | ); 131 | it('returns error message', () => 132 | Strain.availability('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 133 | ); 134 | }); 135 | -------------------------------------------------------------------------------- /tests/flower.spec.js: -------------------------------------------------------------------------------- 1 | import { Flower } from 'index'; 2 | 3 | describe('Flower.all()', () => { 4 | it('returns array', () => 5 | Flower.all().then((data) => expect(data).to.be.instanceof(Array)) 6 | ); 7 | it('returns array sorted by createdAt', () => 8 | Flower.all({ sort: 'createdAt' }).then((data) => expect(data).to.be.instanceof(Array)) 9 | ); 10 | it('returns array sorted by createdAt', () => 11 | Flower.all({ sort: '-createdAt', page: 5 }).then((data) => expect(data).to.be.instanceof(Array)) 12 | ); 13 | it('returns array', () => 14 | Flower.all({ page: 3 }).then((data) => expect(data).to.be.instanceof(Array)) 15 | ); 16 | }); 17 | 18 | describe('Flower.type()', () => { 19 | it('returns array', () => 20 | Flower.type('flowers').then((data) => expect(data).to.be.instanceof(Array)) 21 | ); 22 | it('returns array sorted by createdAt', () => 23 | Flower.type('sEeds', { sort: 'createdAt' }).then((data) => expect(data).to.be.instanceof(Array)) 24 | ); 25 | it('returns array sorted by createdAt', () => 26 | Flower.type('clONes', { sort: '-createdAt', page: 5 }) 27 | .then((data) => expect(data).to.be.instanceof(Array)) 28 | ); 29 | it('returns array', () => 30 | Flower.type('Shake', { page: 3 }).then((data) => expect(data).to.be.instanceof(Array)) 31 | ); 32 | it('returns error message', () => 33 | Flower.type('not a real type').catch((err) => expect(err).to.be.an('error')) 34 | ); 35 | }); 36 | 37 | describe('Flower.flower()', () => { 38 | it('returns object', () => 39 | Flower.flower('AHZ7H4N6467FVUDY3DAY00000') 40 | .then((data) => expect(typeof(data)).to.equal('object')) 41 | ); 42 | it('returns error message', () => 43 | Flower.flower('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 44 | ); 45 | }); 46 | 47 | describe('Flower.user()', () => { 48 | it('returns object', () => 49 | Flower.user('AHZ7H4N6467FVUDY3DAY00000') 50 | .then((data) => expect(typeof(data)).to.equal('object')) 51 | ); 52 | it('returns error message', () => 53 | Flower.user('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 54 | ); 55 | }); 56 | 57 | describe('Flower.reviews()', () => { 58 | it('returns array', () => 59 | Flower.reviews('AHZ7H4N6467FVUDY3DAY00000') 60 | .then((data) => expect(data).to.be.instanceof(Array)) 61 | ); 62 | it('returns array', () => 63 | Flower.reviews('AHZ7H4N6467FVUDY3DAY00000', { page: 2 }) 64 | .then((data) => expect(data).to.be.instanceof(Array)) 65 | ); 66 | it('returns error message', () => 67 | Flower.reviews('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 68 | ); 69 | }); 70 | 71 | describe('Flower.effectsFlavors()', () => { 72 | it('returns object', () => 73 | Flower.effectsFlavors('AHZ7H4N6467FVUDY3DAY00000') 74 | .then((data) => expect(typeof(data)).to.equal('object')) 75 | ); 76 | it('returns error message', () => 77 | Flower.effectsFlavors('VUJCJ4TYMG00!000000&00000') 78 | .catch((err) => expect(err).to.be.an('error')) 79 | ); 80 | }); 81 | 82 | describe('Flower.producer()', () => { 83 | it('returns object', () => 84 | Flower.producer('AHZ7H4N6467FVUDY3DAY00000') 85 | .then((data) => expect(typeof(data)).to.equal('object')) 86 | ); 87 | it('returns error message', () => 88 | Flower.producer('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 89 | ); 90 | }); 91 | 92 | describe('Flower.strain()', () => { 93 | it('returns object', () => 94 | Flower.strain('AHZ7H4N6467FVUDY3DAY00000') 95 | .then((data) => expect(typeof(data)).to.equal('object')) 96 | ); 97 | it('returns error message', () => 98 | Flower.strain('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 99 | ); 100 | }); 101 | 102 | describe('Flower.availability()', () => { 103 | it('returns array', () => 104 | Flower.availability('AHZ7H4N6467FVUDY3DAY00000', 37.7749295, -122.4194155) 105 | .then((data) => expect(data).to.be.instanceof(Array)) 106 | ); 107 | it('returns array', () => 108 | Flower.availability('AHZ7H4N6467FVUDY3DAY00000', '37.7749295', '-122.4194155') 109 | .then((data) => expect(data).to.be.instanceof(Array)) 110 | ); 111 | it('returns array', () => 112 | Flower.availability('AHZ7H4N6467FVUDY3DAY00000', 37.7749295, -122.4194155, { page: 2 }) 113 | .then((data) => expect(data).to.be.instanceof(Array)) 114 | ); 115 | it('returns array', () => 116 | Flower.availability('AHZ7H4N6467FVUDY3DAY00000', '37.7749295', '-122.4194155', { page: 2 }) 117 | .then((data) => expect(data).to.be.instanceof(Array)) 118 | ); 119 | it('returns error message', () => 120 | Flower.availability('VUJCJ4TYMG00000000000000', [37.7749295], -122.4194155) 121 | .catch((err) => expect(err).to.be.an('error')) 122 | ); 123 | it('returns error message', () => 124 | Flower.availability('VUJCJ4TYMG00000000000000', 37.7749295, [-122.4194155]) 125 | .catch((err) => expect(err).to.be.an('error')) 126 | ); 127 | it('returns error message', () => 128 | Flower.availability('VUJCJ4TYMG00000000000000').catch((err) => expect(err).to.be.an('error')) 129 | ); 130 | it('returns error message', () => 131 | Flower.availability('VUJCJ4TYMG00000000000000', 37.7749295) 132 | .catch((err) => expect(err).to.be.an('error')) 133 | ); 134 | it('returns error message', () => 135 | Flower.availability('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 136 | ); 137 | }); 138 | -------------------------------------------------------------------------------- /tests/extract.spec.js: -------------------------------------------------------------------------------- 1 | import { Extract } from 'index'; 2 | 3 | describe('Extract.all()', () => { 4 | it('returns array', () => 5 | Extract.all().then((data) => expect(data).to.be.instanceof(Array)) 6 | ); 7 | it('returns array sorted by createdAt', () => 8 | Extract.all({ sort: 'createdAt' }).then((data) => expect(data).to.be.instanceof(Array)) 9 | ); 10 | it('returns array sorted by createdAt', () => 11 | Extract.all({ sort: '-createdAt', page: 5 }) 12 | .then((data) => expect(data).to.be.instanceof(Array)) 13 | ); 14 | it('returns array', () => 15 | Extract.all({ page: 3 }).then((data) => expect(data).to.be.instanceof(Array)) 16 | ); 17 | }); 18 | 19 | describe('Extract.type()', () => { 20 | it('returns array', () => 21 | Extract.type('Kief').then((data) => expect(data).to.be.instanceof(Array)) 22 | ); 23 | it('returns array sorted by createdAt', () => 24 | Extract.type('Hash', { sort: 'createdAt' }) 25 | .then((data) => expect(data).to.be.instanceof(Array)) 26 | ); 27 | it('returns array sorted by createdAt', () => 28 | Extract.type('Oil', { sort: '-createdAt', page: 5 }) 29 | .then((data) => expect(data).to.be.instanceof(Array)) 30 | ); 31 | it('returns array', () => 32 | Extract.type('Wax', { page: 3 }).then((data) => expect(data).to.be.instanceof(Array)) 33 | ); 34 | it('returns error message', () => 35 | Extract.type('not a real type').catch((err) => expect(err).to.be.an('error')) 36 | ); 37 | }); 38 | 39 | describe('Extract.extract()', () => { 40 | it('returns object', () => 41 | Extract.extract('QLG39RN2AFPMR6WLTPLW00000') 42 | .then((data) => expect(typeof(data)).to.equal('object')) 43 | ); 44 | it('returns error message', () => 45 | Extract.extract('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 46 | ); 47 | }); 48 | 49 | describe('Extract.user()', () => { 50 | it('returns object', () => 51 | Extract.user('QLG39RN2AFPMR6WLTPLW00000') 52 | .then((data) => expect(typeof(data)).to.equal('object')) 53 | ); 54 | it('returns error message', () => 55 | Extract.user('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 56 | ); 57 | }); 58 | 59 | describe('Extract.reviews()', () => { 60 | it('returns array', () => 61 | Extract.reviews('QLG39RN2AFPMR6WLTPLW00000') 62 | .then((data) => expect(data).to.be.instanceof(Array)) 63 | ); 64 | it('returns array', () => 65 | Extract.reviews('QLG39RN2AFPMR6WLTPLW00000', { page: 2 }) 66 | .then((data) => expect(data).to.be.instanceof(Array)) 67 | ); 68 | it('returns error message', () => 69 | Extract.reviews('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 70 | ); 71 | }); 72 | 73 | describe('Extract.effectsFlavors()', () => { 74 | it('returns object', () => 75 | Extract.effectsFlavors('QLG39RN2AFPMR6WLTPLW00000') 76 | .then((data) => expect(typeof(data)).to.equal('object')) 77 | ); 78 | it('returns error message', () => 79 | Extract.effectsFlavors('VUJCJ4TYMG00!000000&00000') 80 | .catch((err) => expect(err).to.be.an('error')) 81 | ); 82 | }); 83 | 84 | describe('Extract.producer()', () => { 85 | it('returns object', () => 86 | Extract.producer('QLG39RN2AFPMR6WLTPLW00000') 87 | .then((data) => expect(typeof(data)).to.equal('object')) 88 | ); 89 | it('returns error message', () => 90 | Extract.producer('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 91 | ); 92 | }); 93 | 94 | describe('Extract.strain()', () => { 95 | it('returns object', () => 96 | Extract.strain('QLG39RN2AFPMR6WLTPLW00000') 97 | .then((data) => expect(typeof(data)).to.equal('object')) 98 | ); 99 | it('returns error message', () => 100 | Extract.strain('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 101 | ); 102 | }); 103 | 104 | describe('Extract.availability()', () => { 105 | it('returns array', () => 106 | Extract.availability('QLG39RN2AFPMR6WLTPLW00000', 37.7749295, -122.4194155) 107 | .then((data) => expect(data).to.be.instanceof(Array)) 108 | ); 109 | it('returns array', () => 110 | Extract.availability('QLG39RN2AFPMR6WLTPLW00000', '37.7749295', '-122.4194155') 111 | .then((data) => expect(data).to.be.instanceof(Array)) 112 | ); 113 | it('returns array', () => 114 | Extract.availability('QLG39RN2AFPMR6WLTPLW00000', 37.7749295, -122.4194155, { page: 2 }) 115 | .then((data) => expect(data).to.be.instanceof(Array)) 116 | ); 117 | it('returns array', () => 118 | Extract.availability('QLG39RN2AFPMR6WLTPLW00000', '37.7749295', '-122.4194155', { page: 2 }) 119 | .then((data) => expect(data).to.be.instanceof(Array)) 120 | ); 121 | it('returns error message', () => 122 | Extract.availability('VUJCJ4TYMG00000000000000', [37.7749295], -122.4194155) 123 | .catch((err) => expect(err).to.be.an('error')) 124 | ); 125 | it('returns error message', () => 126 | Extract.availability('VUJCJ4TYMG00000000000000', 37.7749295, [-122.4194155]) 127 | .catch((err) => expect(err).to.be.an('error')) 128 | ); 129 | it('returns error message', () => 130 | Extract.availability('VUJCJ4TYMG00000000000000').catch((err) => expect(err).to.be.an('error')) 131 | ); 132 | it('returns error message', () => 133 | Extract.availability('VUJCJ4TYMG00000000000000', 37.7749295) 134 | .catch((err) => expect(err).to.be.an('error')) 135 | ); 136 | it('returns error message', () => 137 | Extract.availability('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 138 | ); 139 | }); 140 | -------------------------------------------------------------------------------- /tests/product.spec.js: -------------------------------------------------------------------------------- 1 | import { Product } from 'index'; 2 | 3 | describe('Product.all()', () => { 4 | it('returns array', () => 5 | Product.all().then((data) => expect(data).to.be.instanceof(Array)) 6 | ); 7 | it('returns array sorted by createdAt', () => 8 | Product.all({ sort: 'createdAt' }).then((data) => expect(data).to.be.instanceof(Array)) 9 | ); 10 | it('returns array sorted by createdAt', () => 11 | Product.all({ sort: '-createdAt', page: 5 }) 12 | .then((data) => expect(data).to.be.instanceof(Array)) 13 | ); 14 | it('returns array', () => 15 | Product.all({ page: 3 }).then((data) => expect(data).to.be.instanceof(Array)) 16 | ); 17 | }); 18 | 19 | describe('Product.type()', () => { 20 | it('returns array', () => 21 | Product.type('Bath').then((data) => expect(data).to.be.instanceof(Array)) 22 | ); 23 | it('returns array sorted by createdAt', () => 24 | Product.type('Topical', { sort: 'createdAt' }) 25 | .then((data) => expect(data).to.be.instanceof(Array)) 26 | ); 27 | it('returns array sorted by createdAt', () => 28 | Product.type('Skin Care', { sort: '-createdAt', page: 5 }) 29 | .then((data) => expect(data).to.be.instanceof(Array)) 30 | ); 31 | it('returns array', () => 32 | Product.type('Pre-Roll', { page: 3 }).then((data) => expect(data).to.be.instanceof(Array)) 33 | ); 34 | it('returns error message', () => 35 | Product.type('not a real type').catch((err) => expect(err).to.be.an('error')) 36 | ); 37 | }); 38 | 39 | describe('Product.product()', () => { 40 | it('returns object', () => 41 | Product.product('9XVU7NK3PEGLAJ372X4F00000') 42 | .then((data) => expect(typeof(data)).to.equal('object')) 43 | ); 44 | it('returns error message', () => 45 | Product.product('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 46 | ); 47 | }); 48 | 49 | describe('Product.user()', () => { 50 | it('returns object', () => 51 | Product.user('9XVU7NK3PEGLAJ372X4F00000') 52 | .then((data) => expect(typeof(data)).to.equal('object')) 53 | ); 54 | it('returns error message', () => 55 | Product.user('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 56 | ); 57 | }); 58 | 59 | describe('Product.reviews()', () => { 60 | it('returns array', () => 61 | Product.reviews('9XVU7NK3PEGLAJ372X4F00000') 62 | .then((data) => expect(data).to.be.instanceof(Array)) 63 | ); 64 | it('returns array', () => 65 | Product.reviews('9XVU7NK3PEGLAJ372X4F00000', { page: 2 }) 66 | .then((data) => expect(data).to.be.instanceof(Array)) 67 | ); 68 | it('returns error message', () => 69 | Product.reviews('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 70 | ); 71 | }); 72 | 73 | describe('Product.effectsFlavors()', () => { 74 | it('returns object', () => 75 | Product.effectsFlavors('9XVU7NK3PEGLAJ372X4F00000') 76 | .then((data) => expect(typeof(data)).to.equal('object')) 77 | ); 78 | it('returns error message', () => 79 | Product.effectsFlavors('VUJCJ4TYMG00!000000&00000') 80 | .catch((err) => expect(err).to.be.an('error')) 81 | ); 82 | }); 83 | 84 | describe('Product.producer()', () => { 85 | it('returns object', () => 86 | Product.producer('9XVU7NK3PEGLAJ372X4F00000') 87 | .then((data) => expect(typeof(data)).to.equal('object')) 88 | ); 89 | it('returns error message', () => 90 | Product.producer('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 91 | ); 92 | }); 93 | 94 | describe('Product.strain()', () => { 95 | it('returns object', () => 96 | Product.strain('9XVU7NK3PEGLAJ372X4F00000') 97 | .then((data) => expect(typeof(data)).to.equal('object')) 98 | ); 99 | it('returns error message', () => 100 | Product.strain('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 101 | ); 102 | }); 103 | 104 | describe('Product.availability()', () => { 105 | it('returns array', () => 106 | Product.availability('9XVU7NK3PEGLAJ372X4F00000', 37.7749295, -122.4194155) 107 | .then((data) => expect(data).to.be.instanceof(Array)) 108 | ); 109 | it('returns array', () => 110 | Product.availability('9XVU7NK3PEGLAJ372X4F00000', '37.7749295', '-122.4194155') 111 | .then((data) => expect(data).to.be.instanceof(Array)) 112 | ); 113 | it('returns array', () => 114 | Product.availability('9XVU7NK3PEGLAJ372X4F00000', 37.7749295, -122.4194155, { page: 2 }) 115 | .then((data) => expect(data).to.be.instanceof(Array)) 116 | ); 117 | it('returns array', () => 118 | Product.availability('9XVU7NK3PEGLAJ372X4F00000', '37.7749295', '-122.4194155', { page: 2 }) 119 | .then((data) => expect(data).to.be.instanceof(Array)) 120 | ); 121 | it('returns error message', () => 122 | Product.availability('VUJCJ4TYMG00000000000000', [37.7749295], -122.4194155) 123 | .catch((err) => expect(err).to.be.an('error')) 124 | ); 125 | it('returns error message', () => 126 | Product.availability('VUJCJ4TYMG00000000000000', 37.7749295, [-122.4194155]) 127 | .catch((err) => expect(err).to.be.an('error')) 128 | ); 129 | it('returns error message', () => 130 | Product.availability('VUJCJ4TYMG00000000000000').catch((err) => expect(err).to.be.an('error')) 131 | ); 132 | it('returns error message', () => 133 | Product.availability('VUJCJ4TYMG00000000000000', 37.7749295) 134 | .catch((err) => expect(err).to.be.an('error')) 135 | ); 136 | it('returns error message', () => 137 | Product.availability('VUJCJ4TYMG00!000000&00000').catch((err) => expect(err).to.be.an('error')) 138 | ); 139 | }); 140 | -------------------------------------------------------------------------------- /lib/dispensary.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _promise = require('babel-runtime/core-js/promise'); 8 | 9 | var _promise2 = _interopRequireDefault(_promise); 10 | 11 | exports.default = dispensary; 12 | 13 | var _util = require('./util'); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | // TODO validate city and slugs 18 | 19 | function dispensary() { 20 | function validateState(state) { 21 | var stateNames = ['ARIZONA', 'ALABAMA', 'ALASKA', 'ARIZONA', 'ARKANSAS', 'CALIFORNIA', 'COLORADO', 'CONNECTICUT', 'DELAWARE', 'FLORIDA', 'GEORGIA', 'HAWAII', 'IDAHO', 'ILLINOIS', 'INDIANA', 'IOWA', 'KANSAS', 'KENTUCKY', 'KENTUCKY', 'LOUISIANA', 'MAINE', 'MARYLAND', 'MASSACHUSETTS', 'MICHIGAN', 'MINNESOTA', 'MISSISSIPPI', 'MISSOURI', 'MONTANA', 'NEBRASKA', 'NEVADA', 'NEW HAMPSHIRE', 'NEW JERSEY', 'NEW MEXICO', 'NEW YORK', 'NORTH CAROLINA', 'NORTH DAKOTA', 'OHIO', 'OKLAHOMA', 'OREGON', 'PENNSYLVANIA', 'RHODE ISLAND', 'SOUTH CAROLINA', 'SOUTH DAKOTA', 'TENNESSEE', 'TEXAS', 'UTAH', 'VERMONT', 'VIRGINIA', 'WASHINGTON', 'WEST VIRGINIA', 'WISCONSIN', 'WYOMING']; 22 | var stateAbbr = ['AZ', 'AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'FL', 'GA', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'KY', 'LA', 'ME', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ', 'NM', 'NY', 'NC', 'ND', 'OH', 'OK', 'OR', 'PA', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', 'VA', 'WA', 'WV', 'WI', 'WY']; 23 | 24 | if (stateAbbr.indexOf(state.toUpperCase()) > -1) return state; 25 | var stateNameIdx = stateNames.indexOf(state.toUpperCase()); 26 | if (stateNameIdx > -1) return stateAbbr[stateNameIdx]; 27 | return ''; 28 | } 29 | 30 | return { 31 | 32 | all: function all() { 33 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 34 | return new _promise2.default(function (resolve, reject) { 35 | return (0, _util.sendRequest)('dispensaries', options, resolve, reject, _util.handleResult); 36 | }); 37 | }, 38 | 39 | dispensary: function dispensary(state, city, slug) { 40 | return new _promise2.default(function (resolve, reject) { 41 | if (!state) return reject(new Error('State is required')); 42 | var validState = validateState(state); 43 | if (!validState) return reject(new Error('Invalid State')); 44 | if (!city) return reject(new Error('City is required.')); 45 | if (!slug) return reject(new Error('Slug is required.')); 46 | return (0, _util.sendRequest)('dispensaries/' + validState + '/' + city + '/' + slug, null, resolve, reject, _util.handleResult); 47 | }); 48 | }, 49 | 50 | strains: function strains(state, city, slug) { 51 | var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; 52 | return new _promise2.default(function (resolve, reject) { 53 | if (!state) return reject(new Error('State is required')); 54 | var validState = validateState(state); 55 | if (!validState) return reject(new Error('Invalid State')); 56 | if (!city) return reject(new Error('City is required.')); 57 | if (!slug) return reject(new Error('Slug is required.')); 58 | return (0, _util.sendRequest)('dispensaries/' + validState + '/' + city + '/' + slug + '/strains', options, resolve, reject, _util.handleResult); 59 | }); 60 | }, 61 | 62 | extracts: function extracts(state, city, slug) { 63 | var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; 64 | return new _promise2.default(function (resolve, reject) { 65 | if (!state) return reject(new Error('State is required')); 66 | var validState = validateState(state); 67 | if (!validState) return reject(new Error('Invalid State')); 68 | if (!city) return reject(new Error('City is required.')); 69 | if (!slug) return reject(new Error('Slug is required.')); 70 | return (0, _util.sendRequest)('dispensaries/' + validState + '/' + city + '/' + slug + '/extracts', options, resolve, reject, _util.handleResult); 71 | }); 72 | }, 73 | 74 | edibles: function edibles(state, city, slug) { 75 | var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; 76 | return new _promise2.default(function (resolve, reject) { 77 | if (!state) return reject(new Error('State is required')); 78 | var validState = validateState(state); 79 | if (!validState) return reject(new Error('Invalid State')); 80 | if (!city) return reject(new Error('City is required.')); 81 | if (!slug) return reject(new Error('Slug is required.')); 82 | return (0, _util.sendRequest)('dispensaries/' + validState + '/' + city + '/' + slug + '/edibles', options, resolve, reject, _util.handleResult); 83 | }); 84 | }, 85 | 86 | products: function products(state, city, slug) { 87 | var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; 88 | return new _promise2.default(function (resolve, reject) { 89 | if (!state) return reject(new Error('State is required')); 90 | var validState = validateState(state); 91 | if (!validState) return reject(new Error('Invalid State')); 92 | if (!city) return reject(new Error('City is required.')); 93 | if (!slug) return reject(new Error('Slug is required.')); 94 | return (0, _util.sendRequest)('dispensaries/' + validState + '/' + city + '/' + slug + '/products', options, resolve, reject, _util.handleResult); 95 | }); 96 | } 97 | 98 | }; 99 | } 100 | module.exports = exports['default']; -------------------------------------------------------------------------------- /src/dispensary.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { 3 | handleResult, 4 | sendRequest, 5 | } from './util'; 6 | 7 | // TODO validate city and slugs 8 | 9 | export default function dispensary(): Object { 10 | function validateState(state: string): string { 11 | const stateNames = [ 12 | 'ARIZONA', 'ALABAMA', 'ALASKA', 'ARIZONA', 'ARKANSAS', 'CALIFORNIA', 'COLORADO', 13 | 'CONNECTICUT', 'DELAWARE', 'FLORIDA', 'GEORGIA', 'HAWAII', 'IDAHO', 'ILLINOIS', 'INDIANA', 14 | 'IOWA', 'KANSAS', 'KENTUCKY', 'KENTUCKY', 'LOUISIANA', 'MAINE', 'MARYLAND', 'MASSACHUSETTS', 15 | 'MICHIGAN', 'MINNESOTA', 'MISSISSIPPI', 'MISSOURI', 'MONTANA', 'NEBRASKA', 'NEVADA', 16 | 'NEW HAMPSHIRE', 'NEW JERSEY', 'NEW MEXICO', 'NEW YORK', 'NORTH CAROLINA', 'NORTH DAKOTA', 17 | 'OHIO', 'OKLAHOMA', 'OREGON', 'PENNSYLVANIA', 'RHODE ISLAND', 'SOUTH CAROLINA', 18 | 'SOUTH DAKOTA', 'TENNESSEE', 'TEXAS', 'UTAH', 'VERMONT', 'VIRGINIA', 'WASHINGTON', 19 | 'WEST VIRGINIA', 'WISCONSIN', 'WYOMING', 20 | ]; 21 | const stateAbbr = [ 22 | 'AZ', 'AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'FL', 'GA', 'HI', 'ID', 'IL', 'IN', 23 | 'IA', 'KS', 'KY', 'KY', 'LA', 'ME', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 24 | 'NH', 'NJ', 'NM', 'NY', 'NC', 'ND', 'OH', 'OK', 'OR', 'PA', 'RI', 'SC', 'SD', 'TN', 'TX', 25 | 'UT', 'VT', 'VA', 'WA', 'WV', 'WI', 'WY', 26 | ]; 27 | 28 | if (stateAbbr.indexOf(state.toUpperCase()) > -1) return state; 29 | const stateNameIdx = stateNames.indexOf(state.toUpperCase()); 30 | if (stateNameIdx > -1) return stateAbbr[stateNameIdx]; 31 | return ''; 32 | } 33 | 34 | return { 35 | 36 | all: (options: Object = {}): Promise => 37 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => 38 | sendRequest( 39 | 'dispensaries', 40 | options, 41 | resolve, 42 | reject, 43 | handleResult 44 | ) 45 | ), 46 | 47 | dispensary: (state: string, city: string, slug: string): Promise => 48 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 49 | if (!state) return reject(new Error('State is required')); 50 | const validState = validateState(state); 51 | if (!validState) return reject(new Error('Invalid State')); 52 | if (!city) return reject(new Error('City is required.')); 53 | if (!slug) return reject(new Error('Slug is required.')); 54 | return sendRequest( 55 | `dispensaries/${validState}/${city}/${slug}`, 56 | null, 57 | resolve, 58 | reject, 59 | handleResult 60 | ); 61 | }), 62 | 63 | strains: (state: string, city: string, slug: string, options: Object = {}): Promise => 64 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 65 | if (!state) return reject(new Error('State is required')); 66 | const validState = validateState(state); 67 | if (!validState) return reject(new Error('Invalid State')); 68 | if (!city) return reject(new Error('City is required.')); 69 | if (!slug) return reject(new Error('Slug is required.')); 70 | return sendRequest( 71 | `dispensaries/${validState}/${city}/${slug}/strains`, 72 | options, 73 | resolve, 74 | reject, 75 | handleResult 76 | ); 77 | }), 78 | 79 | extracts: (state: string, city: string, slug: string, options: Object = {}): Promise => 80 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 81 | if (!state) return reject(new Error('State is required')); 82 | const validState = validateState(state); 83 | if (!validState) return reject(new Error('Invalid State')); 84 | if (!city) return reject(new Error('City is required.')); 85 | if (!slug) return reject(new Error('Slug is required.')); 86 | return sendRequest( 87 | `dispensaries/${validState}/${city}/${slug}/extracts`, 88 | options, 89 | resolve, 90 | reject, 91 | handleResult 92 | ); 93 | }), 94 | 95 | edibles: (state: string, city: string, slug: string, options: Object = {}): Promise => 96 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 97 | if (!state) return reject(new Error('State is required')); 98 | const validState = validateState(state); 99 | if (!validState) return reject(new Error('Invalid State')); 100 | if (!city) return reject(new Error('City is required.')); 101 | if (!slug) return reject(new Error('Slug is required.')); 102 | return sendRequest( 103 | `dispensaries/${validState}/${city}/${slug}/edibles`, 104 | options, 105 | resolve, 106 | reject, 107 | handleResult 108 | ); 109 | }), 110 | 111 | products: (state: string, city: string, slug: string, options: Object = {}): Promise => 112 | new Promise((resolve: (data: Object) => void, reject: (reason: Error) => void): mixed => { 113 | if (!state) return reject(new Error('State is required')); 114 | const validState = validateState(state); 115 | if (!validState) return reject(new Error('Invalid State')); 116 | if (!city) return reject(new Error('City is required.')); 117 | if (!slug) return reject(new Error('Slug is required.')); 118 | return sendRequest( 119 | `dispensaries/${validState}/${city}/${slug}/products`, 120 | options, 121 | resolve, 122 | reject, 123 | handleResult 124 | ); 125 | }), 126 | 127 | }; 128 | } 129 | -------------------------------------------------------------------------------- /src/redirects.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | const url = require('url'); 3 | const assert = require('assert'); 4 | const http = require('http'); 5 | const https = require('https'); 6 | const Writable: Function = require('stream').Writable; 7 | 8 | const nativeProtocols = { 9 | 'http:': http, 10 | 'https:': https, 11 | }; 12 | const schemes = {}; 13 | const safeMethods = { 14 | GET: true, 15 | HEAD: true, 16 | OPTIONS: true, 17 | TRACE: true, 18 | }; 19 | 20 | const eventHandlers = Object.create(null); 21 | 22 | ['abort', 'aborted', 'error', 'socket'].forEach((event: string): void => { 23 | eventHandlers[event] = function a(arg: Object): void { 24 | this._redirectable.emit(event, arg); 25 | }; 26 | }); 27 | 28 | function RedirectableRequest(options: Object, responseCallback: Object): void { 29 | Writable.call(this); 30 | this._options = options; 31 | this._redirectCount = 0; 32 | this._bufferedWrites = []; 33 | if (responseCallback) this.on('response', responseCallback); 34 | this._onNativeResponse = (response: Object): Object => this._processResponse(response); 35 | this._performRequest(); 36 | } 37 | 38 | RedirectableRequest.prototype = Object.create(Writable.prototype); 39 | 40 | RedirectableRequest.prototype._performRequest = function b(): void { 41 | const protocol = this._options.protocol; 42 | if (this._options.agents) this._options.agent = this._options.agents[schemes[protocol]]; 43 | 44 | const nativeProtocol = nativeProtocols[protocol]; 45 | const request = this._currentRequest = 46 | nativeProtocol.request(this._options, this._onNativeResponse); 47 | this._currentUrl = url.format(this._options); 48 | 49 | request._redirectable = this; 50 | for (const event in eventHandlers) { 51 | if (event) request.on(event, eventHandlers[event]); 52 | } 53 | 54 | if (this._isRedirect) { 55 | const bufferedWrites = this._bufferedWrites; 56 | if (bufferedWrites.length === 0) { 57 | request.end(); 58 | } else { 59 | let i = 0; 60 | const writeNext = (): void => { 61 | if (i < bufferedWrites.length) { 62 | const bufferedWrite = bufferedWrites[i++]; 63 | request.write(bufferedWrite.data, bufferedWrite.encoding, writeNext); 64 | } else { 65 | request.end(); 66 | } 67 | }; 68 | writeNext(); 69 | } 70 | } 71 | }; 72 | 73 | RedirectableRequest.prototype._processResponse = function c(response: Object): null { 74 | const location = response.headers.location; 75 | if (location && this._options.followRedirects !== false && 76 | response.statusCode >= 300 && response.statusCode < 400) { 77 | if (++this._redirectCount > this._options.maxRedirects) { 78 | return this.emit('error', new Error('Max redirects exceeded.')); 79 | } 80 | 81 | const headers = this._options.headers; 82 | if (response.statusCode !== 307 && !(this._options.method in safeMethods)) { 83 | this._options.method = 'GET'; 84 | this._bufferedWrites = []; 85 | for (const header in headers) { 86 | if (/^content-/i.test(header)) delete headers[header]; 87 | } 88 | } 89 | 90 | if (!this._isRedirect) { 91 | for (const header in headers) { 92 | if (/^host$/i.test(header)) delete headers[header]; 93 | } 94 | } 95 | 96 | const redirectUrl = url.resolve(this._currentUrl, location); 97 | Object.assign(this._options, url.parse(redirectUrl)); 98 | this._isRedirect = true; 99 | this._performRequest(); 100 | } else { 101 | this.emit('response', Object.assign(response, { responseUrl: this._currentUrl })); 102 | delete this._options; 103 | delete this._bufferedWrites; 104 | } 105 | return null; 106 | }; 107 | 108 | RedirectableRequest.prototype.abort = function d(): void { 109 | this._currentRequest.abort(); 110 | }; 111 | 112 | RedirectableRequest.prototype.flushHeaders = function e(): void { 113 | this._currentRequest.flushHeaders(); 114 | }; 115 | 116 | RedirectableRequest.prototype.setNoDelay = function f(noDelay: boolean): void { 117 | this._currentRequest.setNoDelay(noDelay); 118 | }; 119 | 120 | RedirectableRequest.prototype.setSocketKeepAlive = 121 | function g(enable: boolean, initialDelay: number): void { 122 | this._currentRequest.setSocketKeepAlive(enable, initialDelay); 123 | }; 124 | 125 | RedirectableRequest.prototype.setTimeout = 126 | function h(timeout: number, cb: () => void): void { 127 | this._currentRequest.setTimeout(timeout, cb); 128 | }; 129 | 130 | RedirectableRequest.prototype._write = 131 | function i(data: Object, encoding: string, cb: () => void): void { 132 | this._currentRequest.write(data, encoding, cb); 133 | this._bufferedWrites.push({ data, encoding }); 134 | }; 135 | 136 | RedirectableRequest.prototype.end = 137 | function j(data: Object, encoding: string, cb: () => void): void { 138 | this._currentRequest.end(data, encoding, cb); 139 | if (data) this._bufferedWrites.push({ data, encoding }); 140 | }; 141 | 142 | Object.keys(nativeProtocols).forEach((protocol: string): void => { 143 | const scheme = schemes[protocol] = protocol.substr(0, protocol.length - 1); 144 | const nativeProtocol = nativeProtocols[protocol]; 145 | const wrappedProtocol = module.exports[scheme] = Object.create(nativeProtocol); 146 | 147 | wrappedProtocol.request = function k(options: Object | string, cb: () => void): Object { 148 | let newOptions; 149 | if (typeof options === 'string') { 150 | newOptions = Object.assign( 151 | {}, 152 | url.parse(options), 153 | { maxRedirects: 21 } 154 | ); 155 | } else { 156 | newOptions = Object.assign({ 157 | maxRedirects: 21, 158 | protocol, 159 | }, options); 160 | } 161 | assert.equal(newOptions.protocol, protocol, 'protocol mismatch'); 162 | return new RedirectableRequest(newOptions, cb); 163 | }; 164 | 165 | wrappedProtocol.get = function l(options: Object, cb: () => void): Object { 166 | const request = wrappedProtocol.request(options, cb); 167 | request.end(); 168 | return request; 169 | }; 170 | }); 171 | -------------------------------------------------------------------------------- /lib/redirects.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _keys = require('babel-runtime/core-js/object/keys'); 4 | 5 | var _keys2 = _interopRequireDefault(_keys); 6 | 7 | var _assign = require('babel-runtime/core-js/object/assign'); 8 | 9 | var _assign2 = _interopRequireDefault(_assign); 10 | 11 | var _create = require('babel-runtime/core-js/object/create'); 12 | 13 | var _create2 = _interopRequireDefault(_create); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | var url = require('url'); 18 | var assert = require('assert'); 19 | var http = require('http'); 20 | var https = require('https'); 21 | var Writable = require('stream').Writable; 22 | 23 | var nativeProtocols = { 24 | 'http:': http, 25 | 'https:': https 26 | }; 27 | var schemes = {}; 28 | var safeMethods = { 29 | GET: true, 30 | HEAD: true, 31 | OPTIONS: true, 32 | TRACE: true 33 | }; 34 | 35 | var eventHandlers = (0, _create2.default)(null); 36 | 37 | ['abort', 'aborted', 'error', 'socket'].forEach(function (event) { 38 | eventHandlers[event] = function a(arg) { 39 | this._redirectable.emit(event, arg); 40 | }; 41 | }); 42 | 43 | function RedirectableRequest(options, responseCallback) { 44 | var _this = this; 45 | 46 | Writable.call(this); 47 | this._options = options; 48 | this._redirectCount = 0; 49 | this._bufferedWrites = []; 50 | if (responseCallback) this.on('response', responseCallback); 51 | this._onNativeResponse = function (response) { 52 | return _this._processResponse(response); 53 | }; 54 | this._performRequest(); 55 | } 56 | 57 | RedirectableRequest.prototype = (0, _create2.default)(Writable.prototype); 58 | 59 | RedirectableRequest.prototype._performRequest = function b() { 60 | var _this2 = this; 61 | 62 | var protocol = this._options.protocol; 63 | if (this._options.agents) this._options.agent = this._options.agents[schemes[protocol]]; 64 | 65 | var nativeProtocol = nativeProtocols[protocol]; 66 | var request = this._currentRequest = nativeProtocol.request(this._options, this._onNativeResponse); 67 | this._currentUrl = url.format(this._options); 68 | 69 | request._redirectable = this; 70 | for (var event in eventHandlers) { 71 | if (event) request.on(event, eventHandlers[event]); 72 | } 73 | 74 | if (this._isRedirect) { 75 | (function () { 76 | var bufferedWrites = _this2._bufferedWrites; 77 | if (bufferedWrites.length === 0) { 78 | request.end(); 79 | } else { 80 | (function () { 81 | var i = 0; 82 | var writeNext = function writeNext() { 83 | if (i < bufferedWrites.length) { 84 | var bufferedWrite = bufferedWrites[i++]; 85 | request.write(bufferedWrite.data, bufferedWrite.encoding, writeNext); 86 | } else { 87 | request.end(); 88 | } 89 | }; 90 | writeNext(); 91 | })(); 92 | } 93 | })(); 94 | } 95 | }; 96 | 97 | RedirectableRequest.prototype._processResponse = function c(response) { 98 | var location = response.headers.location; 99 | if (location && this._options.followRedirects !== false && response.statusCode >= 300 && response.statusCode < 400) { 100 | if (++this._redirectCount > this._options.maxRedirects) { 101 | return this.emit('error', new Error('Max redirects exceeded.')); 102 | } 103 | 104 | var headers = this._options.headers; 105 | if (response.statusCode !== 307 && !(this._options.method in safeMethods)) { 106 | this._options.method = 'GET'; 107 | this._bufferedWrites = []; 108 | for (var header in headers) { 109 | if (/^content-/i.test(header)) delete headers[header]; 110 | } 111 | } 112 | 113 | if (!this._isRedirect) { 114 | for (var _header in headers) { 115 | if (/^host$/i.test(_header)) delete headers[_header]; 116 | } 117 | } 118 | 119 | var redirectUrl = url.resolve(this._currentUrl, location); 120 | (0, _assign2.default)(this._options, url.parse(redirectUrl)); 121 | this._isRedirect = true; 122 | this._performRequest(); 123 | } else { 124 | this.emit('response', (0, _assign2.default)(response, { responseUrl: this._currentUrl })); 125 | delete this._options; 126 | delete this._bufferedWrites; 127 | } 128 | return null; 129 | }; 130 | 131 | RedirectableRequest.prototype.abort = function d() { 132 | this._currentRequest.abort(); 133 | }; 134 | 135 | RedirectableRequest.prototype.flushHeaders = function e() { 136 | this._currentRequest.flushHeaders(); 137 | }; 138 | 139 | RedirectableRequest.prototype.setNoDelay = function f(noDelay) { 140 | this._currentRequest.setNoDelay(noDelay); 141 | }; 142 | 143 | RedirectableRequest.prototype.setSocketKeepAlive = function g(enable, initialDelay) { 144 | this._currentRequest.setSocketKeepAlive(enable, initialDelay); 145 | }; 146 | 147 | RedirectableRequest.prototype.setTimeout = function h(timeout, cb) { 148 | this._currentRequest.setTimeout(timeout, cb); 149 | }; 150 | 151 | RedirectableRequest.prototype._write = function i(data, encoding, cb) { 152 | this._currentRequest.write(data, encoding, cb); 153 | this._bufferedWrites.push({ data: data, encoding: encoding }); 154 | }; 155 | 156 | RedirectableRequest.prototype.end = function j(data, encoding, cb) { 157 | this._currentRequest.end(data, encoding, cb); 158 | if (data) this._bufferedWrites.push({ data: data, encoding: encoding }); 159 | }; 160 | 161 | (0, _keys2.default)(nativeProtocols).forEach(function (protocol) { 162 | var scheme = schemes[protocol] = protocol.substr(0, protocol.length - 1); 163 | var nativeProtocol = nativeProtocols[protocol]; 164 | var wrappedProtocol = module.exports[scheme] = (0, _create2.default)(nativeProtocol); 165 | 166 | wrappedProtocol.request = function k(options, cb) { 167 | var newOptions = void 0; 168 | if (typeof options === 'string') { 169 | newOptions = (0, _assign2.default)({}, url.parse(options), { maxRedirects: 21 }); 170 | } else { 171 | newOptions = (0, _assign2.default)({ 172 | maxRedirects: 21, 173 | protocol: protocol 174 | }, options); 175 | } 176 | assert.equal(newOptions.protocol, protocol, 'protocol mismatch'); 177 | return new RedirectableRequest(newOptions, cb); 178 | }; 179 | 180 | wrappedProtocol.get = function l(options, cb) { 181 | var request = wrappedProtocol.request(options, cb); 182 | request.end(); 183 | return request; 184 | }; 185 | }); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Cannabis Reports 2 | A Cannabis Reports API wrapper for Node.js 3 | 4 | [![Build Status](https://travis-ci.org/AJFunk/cannabis-reports.svg?branch=master)](https://travis-ci.org/AJFunk/cannabis-reports) 5 | 6 | This project uses modern ES2016+ syntax, which means you can use promises (as shown in the documentation) or async/await. 7 | 8 | ### Installation 9 | 10 | ```sh 11 | npm install --save cannabis-reports 12 | ``` 13 | 14 | ### Usage 15 | 16 | ```javascript 17 | import { Strain, Flower, Extract, Edible, Product, Producer, SeedCompany, Dispensary } from 'cannabis-reports'; 18 | ``` 19 | Only import the modules you need. For example, if you only need the `Strain` and `Extract` modules: 20 | ```javascript 21 | import { Strain, Extract } from 'cannabis-reports'; 22 | ``` 23 | To set your API Key, set the environment variable `CANNABIS_REPORTS_API_KEY`. Alternatively, you can set the configuration manually 24 | ```javascript 25 | import { setCannabisReportsKey } from 'cannabis-reports'; 26 | setCannabisReportsKey('') 27 | ``` 28 | 29 | ## Strains 30 | * [Strain.all()](#strain-all) 31 | * [Strain.search()](#strain-search) 32 | * [Strain.strain()](#strain-strain) 33 | * [Strain.user()](#strain-user) 34 | * [Strain.reviews()](#strain-reviews) 35 | * [Strain.effectsFlavors()](#strain-effectsFlavors) 36 | * [Strain.seedCompany()](#strain-seedCompany) 37 | * [Strain.genetics()](#strain-genetics) 38 | * [Strain.children()](#strain-children) 39 | * [Strain.availability()](#strain-availability) 40 | 41 | ## Flowers 42 | * [Flower.all()](#flower-all) 43 | * [Flower.type()](#flower-type) 44 | * [Flower.flower()](#flower-flower) 45 | * [Flower.user()](#flower-user) 46 | * [Flower.reviews()](#flower-reviews) 47 | * [Flower.effectsFlavors()](#flower-effectsFlavors) 48 | * [Flower.producer()](#flower-producer) 49 | * [Flower.strain()](#flower-strain) 50 | * [Flower.availability()](#flower-availability) 51 | 52 | ## Extracts 53 | * [Extract.all()](#extract-all) 54 | * [Extract.type()](#extract-type) 55 | * [Extract.extract()](#extract-extract) 56 | * [Extract.user()](#extract-user) 57 | * [Extract.reviews()](#extract-reviews) 58 | * [Extract.effectsFlavors()](#extract-effectsFlavors) 59 | * [Extract.producer()](#extract-producer) 60 | * [Extract.strain()](#extract-strain) 61 | * [Extract.availability()](#extract-availability) 62 | 63 | ## Edibles 64 | * [Edible.all()](#edible-all) 65 | * [Edible.type()](#edible-type) 66 | * [Edible.edible()](#edible-edible) 67 | * [Edible.user()](#edible-user) 68 | * [Edible.reviews()](#edible-reviews) 69 | * [Edible.effectsFlavors()](#edible-effectsFlavors) 70 | * [Edible.producer()](#edible-producer) 71 | * [Edible.strain()](#edible-strain) 72 | * [Edible.availability()](#edible-availability) 73 | 74 | ## Products 75 | * [Product.all()](#product-all) 76 | * [Product.type()](#product-type) 77 | * [Product.product()](#product-product) 78 | * [Product.user()](#product-user) 79 | * [Product.reviews()](#product-reviews) 80 | * [Product.effectsFlavors()](#product-effectsFlavors) 81 | * [Product.producer()](#product-producer) 82 | * [Product.strain()](#product-strain) 83 | * [Product.availability()](#product-availability) 84 | 85 | ## Producers 86 | * [Producer.all()](#producer-all) 87 | * [Producer.producer()](#producer-producer) 88 | * [Producer.user()](#producer-user) 89 | * [Producer.extracts()](#producer-extracts) 90 | * [Producer.edibles()](#producer-edibles) 91 | * [Producer.products()](#producer-products) 92 | * [Producer.availability()](#producer-availability) 93 | 94 | ## Dispensaries 95 | * [Dispensary.all()](#dispensary-all) 96 | * [Dispensary.dispensary()](#dispensary-dispensary) 97 | * [Dispensary.strains()](#dispensary-strains) 98 | * [Dispensary.extracts()](#dispensary-extracts) 99 | * [Dispensary.edibles()](#dispensary-edibles) 100 | * [Dispensary.products()](#dispensary-products) 101 | 102 | ## Seed Companies 103 | * [SeedCompany.seedCompany()](#seedCompany-seedCompany) 104 | * [SeedCompany.strains()](#seedCompany-strains) 105 | * [SeedCompany.reviews()](#seedCompany-reviews) 106 | 107 | - - - 108 |

Strain.all(options)

109 | returns an Array of strain objects. 110 | 111 | ##### `options` (optional) - [Object] 112 | * `sort` - [String] Possible values: 113 | * `createdAt` - Oldest records 114 | * `-createdAt` - Newest records 115 | * `updatedAt` - Oldest updated records 116 | * `-updatedAt` - Newest updated records 117 | * `name` - Alphabetically stating with numeric strains. 0-9, A-Z. 118 | * `-name` - Alphabetically starting with Z and working back through numeric strains. Z-A, 9-0. 119 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 120 | 121 | ```javascript 122 | Strain 123 | .all(options) 124 | .then(data => console.log(data)) 125 | .catch(err => console.log(err)) 126 | ``` 127 | 128 | 129 | returns an Array of strain objects matching the search query. 130 | 131 | ##### `query` (required) - [String] 132 | ##### `options` (optional) - [Object] 133 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 134 | 135 | ```javascript 136 | Strain 137 | .search('orange') 138 | .then(data => console.log(data)) 139 | .catch(err => console.log(err)) 140 | ``` 141 | 142 |

Strain.strain(ucpc)

143 | returns a single strain object with the specified UCPC 144 | 145 | ##### `ucpc` (required) - [String] 146 | 147 | ```javascript 148 | Strain 149 | .strain('VUJCJ4TYMG000000000000000') 150 | .then(data => console.log(data)) 151 | .catch(err => console.log(err)) 152 | ``` 153 | 154 |

Strain.user(ucpc)

155 | returns a single user object of the user who added the strain to the database. 156 | 157 | ##### `ucpc` (required) - [String] 158 | 159 | ```javascript 160 | Strain 161 | .strain('VUJCJ4TYMG000000000000000') 162 | .then(data => console.log(data)) 163 | .catch(err => console.log(err)) 164 | ``` 165 | 166 |

Strain.reviews(ucpc, options)

167 | returns an array of reviews for a cannabis strain. 168 | 169 | ##### `ucpc` (required) - [String] 170 | ##### `options` (optional) - [Object] 171 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 172 | 173 | ```javascript 174 | Strain 175 | .reviews('VUJCJ4TYMG000000000000000', options) 176 | .then(data => console.log(data)) 177 | .catch(err => console.log(err)) 178 | ``` 179 | 180 |

Strain.effectsFlavors(ucpc)

181 | returns a object containing the average effects and flavors from reviews for this strain. 182 | 183 | ##### `ucpc` (required) - [String] 184 | 185 | ```javascript 186 | Strain 187 | .effectsFlavors('VUJCJ4TYMG000000000000000') 188 | .then(data => console.log(data)) 189 | .catch(err => console.log(err)) 190 | ``` 191 | 192 |

Strain.seedCompany(ucpc)

193 | returns a object for the seed company that was responsible for a cannabis strain. 194 | 195 | ##### `ucpc` (required) - [String] 196 | 197 | ```javascript 198 | Strain 199 | .seedCompany('VUJCJ4TYMG000000000000000') 200 | .then(data => console.log(data)) 201 | .catch(err => console.log(err)) 202 | ``` 203 | 204 |

Strain.genetics(ucpc)

205 | returns an array of strains that were the parent material for the strain with the given UCPC. 206 | 207 | ##### `ucpc` (required) - [String] 208 | 209 | ```javascript 210 | Strain 211 | .genetics('VUJCJ4TYMG000000000000000') 212 | .then(data => console.log(data)) 213 | .catch(err => console.log(err)) 214 | ``` 215 | 216 |

Strain.children(ucpc, options)

217 | returns an array of the child strains that this strain has been bred into. 218 | 219 | ##### `ucpc` (required) - [String] 220 | ##### `options` (optional) - [Object] 221 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 222 | 223 | ```javascript 224 | Strain 225 | .children('VUJCJ4TYMG000000000000000', options) 226 | .then(data => console.log(data)) 227 | .catch(err => console.log(err)) 228 | ``` 229 | 230 |

Strain.availability(ucpc, lat, lng, options)

231 | returns an Array of information about the availability of a strain using latitude and longitude. 232 | 233 | ##### `ucpc` (required) - [String] 234 | ##### `lat` (required) - [String] or [Number] 235 | ##### `lng` (required) - [String] or [Number] 236 | ##### `options` (optional) - [Object] 237 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 238 | * `radius` - [Number] Radius to search for in miles, max 25. 239 | 240 | ```javascript 241 | Strain 242 | .availability('VUJCJ4TYMG000000000000000', 37.7749295, -122.4194155, options) 243 | .then(data => console.log(data)) 244 | .catch(err => console.log(err)) 245 | ``` 246 | 247 |

Flower.all(options)

248 | returns an Array of flower objects. 249 | 250 | ##### `options` (optional) - [Object] 251 | * `sort` - [String] Possible values: 252 | * `createdAt` - Oldest records 253 | * `-createdAt` - Newest records 254 | * `updatedAt` - Oldest updated records 255 | * `-updatedAt` - Newest updated records 256 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 257 | 258 | ```javascript 259 | Flower 260 | .all(options) 261 | .then(data => console.log(data)) 262 | .catch(err => console.log(err)) 263 | ``` 264 | 265 |

Flower.type(flowerType, options)

266 | returns an Array of products for a given type. 267 | 268 | ##### `flowerType` (required) - [String] (case-insensitive) Possible values: 269 | * `flowers` 270 | * `seeds` 271 | * `clones` 272 | * `shake` 273 | ##### `options` (optional) - [Object] 274 | * `sort` - [String] Possible values: 275 | * `createdAt` - Oldest records 276 | * `-createdAt` - Newest records 277 | * `updatedAt` - Oldest updated records 278 | * `-updatedAt` - Newest updated records 279 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 280 | 281 | ```javascript 282 | Flower 283 | .type(flowerType, options) 284 | .then(data => console.log(data)) 285 | .catch(err => console.log(err)) 286 | ``` 287 | 288 |

Flower.flower(ucpc)

289 | returns a single flower object with the specified UCPC. 290 | 291 | ##### `ucpc` (required) - [String] 292 | 293 | ```javascript 294 | Flower 295 | .flower('AHZ7H4N6467FVUDY3DAY00000') 296 | .then(data => console.log(data)) 297 | .catch(err => console.log(err)) 298 | ``` 299 | 300 |

Flower.user(ucpc)

301 | returns a single user object of the user who added the flower to the database. 302 | 303 | ##### `ucpc` (required) - [String] 304 | 305 | ```javascript 306 | Flower 307 | .user('AHZ7H4N6467FVUDY3DAY00000') 308 | .then(data => console.log(data)) 309 | .catch(err => console.log(err)) 310 | ``` 311 | 312 |

Flower.reviews(ucpc, options)

313 | returns an array of reviews for a cannabis flower. 314 | 315 | ##### `ucpc` (required) - [String] 316 | ##### `options` (optional) - [Object] 317 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 318 | 319 | ```javascript 320 | Flower 321 | .reviews('AHZ7H4N6467FVUDY3DAY00000', options) 322 | .then(data => console.log(data)) 323 | .catch(err => console.log(err)) 324 | ``` 325 | 326 |

Flower.effectsFlavors(ucpc)

327 | returns a object containing the average effects and flavors from reviews for this flower. 328 | 329 | ##### `ucpc` (required) - [String] 330 | 331 | ```javascript 332 | Flower 333 | .effectsFlavors('AHZ7H4N6467FVUDY3DAY00000') 334 | .then(data => console.log(data)) 335 | .catch(err => console.log(err)) 336 | ``` 337 | 338 |

Flower.producer(ucpc)

339 | returns a object for the producer of a flower. 340 | 341 | ##### `ucpc` (required) - [String] 342 | 343 | ```javascript 344 | Flower 345 | .producer('AHZ7H4N6467FVUDY3DAY00000') 346 | .then(data => console.log(data)) 347 | .catch(err => console.log(err)) 348 | ``` 349 |

Flower.strain(ucpc)

350 | returns a object for the strain of a flower. 351 | 352 | ##### `ucpc` (required) - [String] 353 | 354 | ```javascript 355 | Flower 356 | .strain('AHZ7H4N6467FVUDY3DAY00000') 357 | .then(data => console.log(data)) 358 | .catch(err => console.log(err)) 359 | ``` 360 | 361 |

Flower.availability(ucpc, lat, lng, options)

362 | returns an Array of information about the availability of a flower using latitude and longitude. 363 | 364 | ##### `ucpc` (required) - [String] 365 | ##### `lat` (required) - [String] or [Number] 366 | ##### `lng` (required) - [String] or [Number] 367 | ##### `options` (optional) - [Object] 368 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 369 | * `radius` - [Number] Radius to search for in miles, max 25. 370 | 371 | ```javascript 372 | Flower 373 | .availability('AHZ7H4N6467FVUDY3DAY00000', 37.7749295, -122.4194155, options) 374 | .then(data => console.log(data)) 375 | .catch(err => console.log(err)) 376 | ``` 377 | 378 |

Extract.all(options)

379 | returns an Array of extract objects. 380 | 381 | ##### `options` (optional) - [Object] 382 | * `sort` - [String] Possible values: 383 | * `createdAt` - Oldest records 384 | * `-createdAt` - Newest records 385 | * `updatedAt` - Oldest updated records 386 | * `-updatedAt` - Newest updated records 387 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 388 | 389 | ```javascript 390 | Extract 391 | .all(options) 392 | .then(data => console.log(data)) 393 | .catch(err => console.log(err)) 394 | ``` 395 | 396 |

Extract.type(extractType, options)

397 | returns an Array of products for a given type. 398 | 399 | ##### `extractType` (required) - [String] (case-insensitive) Possible values: 400 | * `kief` 401 | * `hash` 402 | * `water-hash` 403 | * `oil` 404 | * `wax` 405 | * `crumble` 406 | * `honeycomb` 407 | * `shatter` 408 | * `vaporizer-disposable` 409 | * `vaporizer-cartridge` 410 | ##### `options` (optional) - [Object] 411 | * `sort` - [String] Possible values: 412 | * `createdAt` - Oldest records 413 | * `-createdAt` - Newest records 414 | * `updatedAt` - Oldest updated records 415 | * `-updatedAt` - Newest updated records 416 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 417 | 418 | ```javascript 419 | Extract 420 | .type(extractType, options) 421 | .then(data => console.log(data)) 422 | .catch(err => console.log(err)) 423 | ``` 424 | 425 |

Extract.extract(ucpc)

426 | returns a single extract object with the specified UCPC. 427 | 428 | ##### `ucpc` (required) - [String] 429 | 430 | ```javascript 431 | Extract 432 | .extract('3CV7E33XLHTJT2XZ4GMD00000') 433 | .then(data => console.log(data)) 434 | .catch(err => console.log(err)) 435 | ``` 436 | 437 |

Extract.user(ucpc)

438 | returns a single user object of the user who added the extract to the database. 439 | 440 | ##### `ucpc` (required) - [String] 441 | 442 | ```javascript 443 | Extract 444 | .user('3CV7E33XLHTJT2XZ4GMD00000') 445 | .then(data => console.log(data)) 446 | .catch(err => console.log(err)) 447 | ``` 448 | 449 |

Extract.reviews(ucpc, options)

450 | returns an array of reviews for a cannabis extract. 451 | 452 | ##### `ucpc` (required) - [String] 453 | ##### `options` (optional) - [Object] 454 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 455 | 456 | ```javascript 457 | Extract 458 | .reviews('3CV7E33XLHTJT2XZ4GMD00000', options) 459 | .then(data => console.log(data)) 460 | .catch(err => console.log(err)) 461 | ``` 462 | 463 |

Extract.effectsFlavors(ucpc)

464 | returns a object containing the average effects and flavors from reviews for this extract. 465 | 466 | ##### `ucpc` (required) - [String] 467 | 468 | ```javascript 469 | Extract 470 | .effectsFlavors('3CV7E33XLHTJT2XZ4GMD00000') 471 | .then(data => console.log(data)) 472 | .catch(err => console.log(err)) 473 | ``` 474 | 475 |

Extract.producer(ucpc)

476 | returns a object for the producer of a extract. 477 | 478 | ##### `ucpc` (required) - [String] 479 | 480 | ```javascript 481 | Extract 482 | .producer('3CV7E33XLHTJT2XZ4GMD00000') 483 | .then(data => console.log(data)) 484 | .catch(err => console.log(err)) 485 | ``` 486 |

Extract.strain(ucpc)

487 | returns a object for the strain of a extract. 488 | 489 | ##### `ucpc` (required) - [String] 490 | 491 | ```javascript 492 | Extract 493 | .strain('3CV7E33XLHTJT2XZ4GMD00000') 494 | .then(data => console.log(data)) 495 | .catch(err => console.log(err)) 496 | ``` 497 | 498 |

Extract.availability(ucpc, lat, lng, options)

499 | returns an Array of information about the availability of a extract using latitude and longitude. 500 | 501 | ##### `ucpc` (required) - [String] 502 | ##### `lat` (required) - [String] or [Number] 503 | ##### `lng` (required) - [String] or [Number] 504 | ##### `options` (optional) - [Object] 505 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 506 | * `radius` - [Number] Radius to search for in miles, max 25. 507 | 508 | ```javascript 509 | Extract 510 | .availability('3CV7E33XLHTJT2XZ4GMD00000', 37.7749295, -122.4194155, options) 511 | .then(data => console.log(data)) 512 | .catch(err => console.log(err)) 513 | ``` 514 | 515 |

Edible.all(options)

516 | returns an Array of edible objects. 517 | 518 | ##### `options` (optional) - [Object] 519 | * `sort` - [String] Possible values: 520 | * `createdAt` - Oldest records 521 | * `-createdAt` - Newest records 522 | * `updatedAt` - Oldest updated records 523 | * `-updatedAt` - Newest updated records 524 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 525 | 526 | ```javascript 527 | Edible 528 | .all(options) 529 | .then(data => console.log(data)) 530 | .catch(err => console.log(err)) 531 | ``` 532 | 533 |

Edible.type(edibleType, options)

534 | returns an Array of products for a given type. 535 | 536 | ##### `edibleType` (required) - [String] (case-insensitive) Possible values: 537 | * `baked goods` 538 | * `candy` 539 | * `treat` 540 | * `chocolate` 541 | * `snack` 542 | * `beverage` 543 | * `pill` 544 | * `tincture` 545 | * `butter` 546 | * `honey` 547 | * `breath strips` 548 | * `tea` 549 | * `ice cream` 550 | ##### `options` (optional) - [Object] 551 | * `sort` - [String] Possible values: 552 | * `createdAt` - Oldest records 553 | * `-createdAt` - Newest records 554 | * `updatedAt` - Oldest updated records 555 | * `-updatedAt` - Newest updated records 556 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 557 | 558 | ```javascript 559 | Edible 560 | .type(edibleType, options) 561 | .then(data => console.log(data)) 562 | .catch(err => console.log(err)) 563 | ``` 564 | 565 |

Edible.edible(ucpc)

566 | returns a single edible object with the specified UCPC. 567 | 568 | ##### `ucpc` (required) - [String] 569 | 570 | ```javascript 571 | Edible 572 | .edible('3CV7E33XLHTJT2XZ4GMD00000') 573 | .then(data => console.log(data)) 574 | .catch(err => console.log(err)) 575 | ``` 576 | 577 |

Edible.user(ucpc)

578 | returns a single user object of the user who added the edible to the database. 579 | 580 | ##### `ucpc` (required) - [String] 581 | 582 | ```javascript 583 | Edible 584 | .user('3CV7E33XLHTJT2XZ4GMD00000') 585 | .then(data => console.log(data)) 586 | .catch(err => console.log(err)) 587 | ``` 588 | 589 |

Edible.reviews(ucpc, options)

590 | returns an array of reviews for a cannabis edible. 591 | 592 | ##### `ucpc` (required) - [String] 593 | ##### `options` (optional) - [Object] 594 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 595 | 596 | ```javascript 597 | Edible 598 | .reviews('3CV7E33XLHTJT2XZ4GMD00000', options) 599 | .then(data => console.log(data)) 600 | .catch(err => console.log(err)) 601 | ``` 602 | 603 |

Edible.effectsFlavors(ucpc)

604 | returns a object containing the average effects and flavors from reviews for this edible. 605 | 606 | ##### `ucpc` (required) - [String] 607 | 608 | ```javascript 609 | Edible 610 | .effectsFlavors('3CV7E33XLHTJT2XZ4GMD00000') 611 | .then(data => console.log(data)) 612 | .catch(err => console.log(err)) 613 | ``` 614 | 615 |

Edible.producer(ucpc)

616 | returns a object for the producer of a edible. 617 | 618 | ##### `ucpc` (required) - [String] 619 | 620 | ```javascript 621 | Edible 622 | .producer('3CV7E33XLHTJT2XZ4GMD00000') 623 | .then(data => console.log(data)) 624 | .catch(err => console.log(err)) 625 | ``` 626 |

Edible.strain(ucpc)

627 | returns a object for the strain of a edible. 628 | 629 | ##### `ucpc` (required) - [String] 630 | 631 | ```javascript 632 | Edible 633 | .strain('3CV7E33XLHTJT2XZ4GMD00000') 634 | .then(data => console.log(data)) 635 | .catch(err => console.log(err)) 636 | ``` 637 | 638 |

Edible.availability(ucpc, lat, lng, options)

639 | returns an Array of information about the availability of a edible using latitude and longitude. 640 | 641 | ##### `ucpc` (required) - [String] 642 | ##### `lat` (required) - [String] or [Number] 643 | ##### `lng` (required) - [String] or [Number] 644 | ##### `options` (optional) - [Object] 645 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 646 | * `radius` - [Number] Radius to search for in miles, max 25. 647 | 648 | ```javascript 649 | Edible 650 | .availability('3CV7E33XLHTJT2XZ4GMD00000', 37.7749295, -122.4194155, options) 651 | .then(data => console.log(data)) 652 | .catch(err => console.log(err)) 653 | ``` 654 | 655 |

Product.all(options)

656 | returns an Array of product objects. 657 | 658 | ##### `options` (optional) - [Object] 659 | * `sort` - [String] Possible values: 660 | * `createdAt` - Oldest records 661 | * `-createdAt` - Newest records 662 | * `updatedAt` - Oldest updated records 663 | * `-updatedAt` - Newest updated records 664 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 665 | 666 | ```javascript 667 | Product 668 | .all(options) 669 | .then(data => console.log(data)) 670 | .catch(err => console.log(err)) 671 | ``` 672 | 673 |

Product.type(productType, options)

674 | returns an Array of products for a given type. 675 | 676 | ##### `productType` (required) - [String] (case-insensitive) Possible values: 677 | * `bath` 678 | * `topical` 679 | * `skin care` 680 | * `pre-roll` 681 | * `lip balm` 682 | * `massage oil` 683 | * `personal lubricant` 684 | ##### `options` (optional) - [Object] 685 | * `sort` - [String] Possible values: 686 | * `createdAt` - Oldest records 687 | * `-createdAt` - Newest records 688 | * `updatedAt` - Oldest updated records 689 | * `-updatedAt` - Newest updated records 690 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 691 | 692 | ```javascript 693 | Product 694 | .type(productType, options) 695 | .then(data => console.log(data)) 696 | .catch(err => console.log(err)) 697 | ``` 698 | 699 |

Product.product(ucpc)

700 | returns a single product object with the specified UCPC. 701 | 702 | ##### `ucpc` (required) - [String] 703 | 704 | ```javascript 705 | Product 706 | .product('3CV7E33XLHTJT2XZ4GMD00000') 707 | .then(data => console.log(data)) 708 | .catch(err => console.log(err)) 709 | ``` 710 | 711 |

Product.user(ucpc)

712 | returns a single user object of the user who added the product to the database. 713 | 714 | ##### `ucpc` (required) - [String] 715 | 716 | ```javascript 717 | Product 718 | .user('3CV7E33XLHTJT2XZ4GMD00000') 719 | .then(data => console.log(data)) 720 | .catch(err => console.log(err)) 721 | ``` 722 | 723 |

Product.reviews(ucpc, options)

724 | returns an array of reviews for a cannabis product. 725 | 726 | ##### `ucpc` (required) - [String] 727 | ##### `options` (optional) - [Object] 728 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 729 | 730 | ```javascript 731 | Product 732 | .reviews('3CV7E33XLHTJT2XZ4GMD00000', options) 733 | .then(data => console.log(data)) 734 | .catch(err => console.log(err)) 735 | ``` 736 | 737 |

Product.effectsFlavors(ucpc)

738 | returns a object containing the average effects and flavors from reviews for this product. 739 | 740 | ##### `ucpc` (required) - [String] 741 | 742 | ```javascript 743 | Product 744 | .effectsFlavors('3CV7E33XLHTJT2XZ4GMD00000') 745 | .then(data => console.log(data)) 746 | .catch(err => console.log(err)) 747 | ``` 748 | 749 |

Product.producer(ucpc)

750 | returns a object for the producer of a product. 751 | 752 | ##### `ucpc` (required) - [String] 753 | 754 | ```javascript 755 | Product 756 | .producer('3CV7E33XLHTJT2XZ4GMD00000') 757 | .then(data => console.log(data)) 758 | .catch(err => console.log(err)) 759 | ``` 760 |

Product.strain(ucpc)

761 | returns a object for the strain of a product. 762 | 763 | ##### `ucpc` (required) - [String] 764 | 765 | ```javascript 766 | Product 767 | .strain('3CV7E33XLHTJT2XZ4GMD00000') 768 | .then(data => console.log(data)) 769 | .catch(err => console.log(err)) 770 | ``` 771 | 772 |

Product.availability(ucpc, lat, lng, options)

773 | returns an Array of information about the availability of a product using latitude and longitude. 774 | 775 | ##### `ucpc` (required) - [String] 776 | ##### `lat` (required) - [String] or [Number] 777 | ##### `lng` (required) - [String] or [Number] 778 | ##### `options` (optional) - [Object] 779 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 780 | * `radius` - [Number] Radius to search for in miles, max 25. 781 | 782 | ```javascript 783 | Product 784 | .availability('3CV7E33XLHTJT2XZ4GMD00000', 37.7749295, -122.4194155, options) 785 | .then(data => console.log(data)) 786 | .catch(err => console.log(err)) 787 | ``` 788 | 789 |

Producer.all(options)

790 | returns an Array of producer objects. 791 | 792 | ##### `options` (optional) - [Object] 793 | * `sort` - [String] Possible values: 794 | * `createdAt` - Oldest records 795 | * `-createdAt` - Newest records 796 | * `updatedAt` - Oldest updated records 797 | * `-updatedAt` - Newest updated records 798 | * `name` - Alphabetically stating with numeric producers. 0-9, A-Z. 799 | * `-name` - Alphabetically starting with Z and working back through numeric producers. Z-A, 9-0. 800 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 801 | 802 | ```javascript 803 | Producer 804 | .all(options) 805 | .then(data => console.log(data)) 806 | .catch(err => console.log(err)) 807 | ``` 808 | 809 |

Producer.producer(ucpc)

810 | returns a single producer object with the specified UCPC. 811 | 812 | ##### `ucpc` (required) - [String] 813 | 814 | ```javascript 815 | Producer 816 | .producer('0000000000L6M7E0000000000') 817 | .then(data => console.log(data)) 818 | .catch(err => console.log(err)) 819 | ``` 820 | 821 |

Producer.extracts(ucpc, options)

822 | returns an array of extracts for a cannabis producer. 823 | 824 | ##### `ucpc` (required) - [String] 825 | ##### `options` (optional) - [Object] 826 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 827 | * `sort` - [String] Possible values: 828 | * `createdAt` - Oldest records 829 | * `-createdAt` - Newest records 830 | * `updatedAt` - Oldest updated records 831 | * `-updatedAt` - Newest updated records 832 | 833 | ```javascript 834 | Producer 835 | .extracts('0000000000L6M7E0000000000', options) 836 | .then(data => console.log(data)) 837 | .catch(err => console.log(err)) 838 | ``` 839 | 840 |

Producer.edibles(ucpc, options)

841 | returns an array of edibles for a cannabis producer. 842 | 843 | ##### `ucpc` (required) - [String] 844 | ##### `options` (optional) - [Object] 845 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 846 | * `sort` - [String] Possible values: 847 | * `createdAt` - Oldest records 848 | * `-createdAt` - Newest records 849 | * `updatedAt` - Oldest updated records 850 | * `-updatedAt` - Newest updated records 851 | 852 | ```javascript 853 | Producer 854 | .edibles('0000000000L6M7E0000000000', options) 855 | .then(data => console.log(data)) 856 | .catch(err => console.log(err)) 857 | ``` 858 | 859 |

Producer.products(ucpc, options)

860 | returns an array of products for a cannabis producer. 861 | 862 | ##### `ucpc` (required) - [String] 863 | ##### `options` (optional) - [Object] 864 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 865 | * `sort` - [String] Possible values: 866 | * `createdAt` - Oldest records 867 | * `-createdAt` - Newest records 868 | * `updatedAt` - Oldest updated records 869 | * `-updatedAt` - Newest updated records 870 | 871 | ```javascript 872 | Producer 873 | .products('0000000000L6M7E0000000000', options) 874 | .then(data => console.log(data)) 875 | .catch(err => console.log(err)) 876 | ``` 877 | 878 |

Producer.availability(ucpc, lat, lng, options)

879 | returns an Array of information about the availability of a producer using latitude and longitude. 880 | 881 | ##### `ucpc` (required) - [String] 882 | ##### `lat` (required) - [String] or [Number] 883 | ##### `lng` (required) - [String] or [Number] 884 | ##### `options` (optional) - [Object] 885 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 886 | * `radius` - [Number] Radius to search for in miles, max 25. 887 | 888 | ```javascript 889 | Producer 890 | .availability('0000000000L6M7E0000000000', 37.7749295, -122.4194155, options) 891 | .then(data => console.log(data)) 892 | .catch(err => console.log(err)) 893 | ``` 894 | 895 |

SeedCompany.seedCompany(ucpc)

896 | returns an individual seed company object with the specified UCPC. 897 | 898 | ##### `ucpc` (required) - [String] 899 | 900 | ```javascript 901 | Product 902 | .seedCompany('VUJCJ00000000000000000000') 903 | .then(data => console.log(data)) 904 | .catch(err => console.log(err)) 905 | ``` 906 | 907 |

SeedCompany.strains(ucpc, options)

908 | returns an Array of strains offered by the specified seed company. 909 | 910 | ##### `options` (optional) - [Object] 911 | * `sort` - [String] Possible values: 912 | * `createdAt` - Oldest records 913 | * `-createdAt` - Newest records 914 | * `updatedAt` - Oldest updated records 915 | * `-updatedAt` - Newest updated records 916 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 917 | 918 | ```javascript 919 | SeedCompany 920 | .seedCompany('VUJCJ00000000000000000000', options) 921 | .then(data => console.log(data)) 922 | .catch(err => console.log(err)) 923 | ``` 924 | 925 |

SeedCompany.reviews(ucpc, options)

926 | returns an Array of reviews for the strains available from the seed company. 927 | 928 | ##### `options` (optional) - [Object] 929 | * `sort` - [String] Possible values: 930 | * `createdAt` - Oldest records 931 | * `-createdAt` - Newest records 932 | * `updatedAt` - Oldest updated records 933 | * `-updatedAt` - Newest updated records 934 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 935 | 936 | ```javascript 937 | SeedCompany 938 | .reviews('VUJCJ00000000000000000000', options) 939 | .then(data => console.log(data)) 940 | .catch(err => console.log(err)) 941 | ``` 942 | 943 |

Dispensary.all(options)

944 | returns an Array of dispensary objects. 945 | 946 | ##### `options` (optional) - [Object] 947 | * `sort` - [String] Possible values: 948 | * `createdAt` - Oldest records 949 | * `-createdAt` - Newest records 950 | * `updatedAt` - Oldest updated records 951 | * `-updatedAt` - Newest updated records 952 | * `name` - Alphabetically stating with numeric strains. 0-9, A-Z. 953 | * `-name` - Alphabetically starting with Z and working back through numeric strains. Z-A, 9-0. 954 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 955 | 956 | ```javascript 957 | Dispensary 958 | .all(options) 959 | .then(data => console.log(data)) 960 | .catch(err => console.log(err)) 961 | ``` 962 | 963 |

Dispensary.dispensary(state, city, slug)

964 | returns a individual dispensary object based on the state, city, and slug. 965 | 966 | ##### `state` (required) - [String] Two character state for the dispensary. 967 | ##### `city` (required) - [String] City the dispensary is in (kebab-case). 968 | ##### `slug` (required) - [String] Slug for the name of the dispensary. 969 | 970 | 971 | ```javascript 972 | Dispensary 973 | .dispensary('ca', 'san-francisco', 'grass-roots') 974 | .then(data => console.log(data)) 975 | .catch(err => console.log(err)) 976 | ``` 977 | 978 |

Dispensary.strains(state, city, slug)

979 | returns an Array of strains for a given dispensary 980 | 981 | ##### `state` (required) - [String] Two character state for the dispensary. 982 | ##### `city` (required) - [String] City the dispensary is in (kebab-case). 983 | ##### `slug` (required) - [String] Slug for the name of the dispensary. 984 | ##### `options` (optional) - [Object] 985 | * `sort` - [String] Possible values: 986 | * `createdAt` - Oldest records 987 | * `-createdAt` - Newest records 988 | * `updatedAt` - Oldest updated records 989 | * `-updatedAt` - Newest updated records 990 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 991 | 992 | 993 | ```javascript 994 | Dispensary 995 | .strains('ca', 'san-francisco', 'grass-roots', options) 996 | .then(data => console.log(data)) 997 | .catch(err => console.log(err)) 998 | ``` 999 | 1000 |

Dispensary.extracts(state, city, slug)

1001 | returns an Array of extracts for a given dispensary 1002 | 1003 | ##### `state` (required) - [String] Two character state for the dispensary. 1004 | ##### `city` (required) - [String] City the dispensary is in (kebab-case). 1005 | ##### `slug` (required) - [String] Slug for the name of the dispensary. 1006 | ##### `options` (optional) - [Object] 1007 | * `sort` - [String] Possible values: 1008 | * `createdAt` - Oldest records 1009 | * `-createdAt` - Newest records 1010 | * `updatedAt` - Oldest updated records 1011 | * `-updatedAt` - Newest updated records 1012 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 1013 | 1014 | 1015 | ```javascript 1016 | Dispensary 1017 | .extracts('ca', 'san-francisco', 'grass-roots', options) 1018 | .then(data => console.log(data)) 1019 | .catch(err => console.log(err)) 1020 | ``` 1021 | 1022 |

Dispensary.edibles(state, city, slug)

1023 | returns an Array of edibles for a given dispensary 1024 | 1025 | ##### `state` (required) - [String] Two character state for the dispensary. 1026 | ##### `city` (required) - [String] City the dispensary is in (kebab-case). 1027 | ##### `slug` (required) - [String] Slug for the name of the dispensary. 1028 | ##### `options` (optional) - [Object] 1029 | * `sort` - [String] Possible values: 1030 | * `createdAt` - Oldest records 1031 | * `-createdAt` - Newest records 1032 | * `updatedAt` - Oldest updated records 1033 | * `-updatedAt` - Newest updated records 1034 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 1035 | 1036 | 1037 | ```javascript 1038 | Dispensary 1039 | .edibles('ca', 'san-francisco', 'grass-roots', options) 1040 | .then(data => console.log(data)) 1041 | .catch(err => console.log(err)) 1042 | ``` 1043 | 1044 |

Dispensary.products(state, city, slug)

1045 | returns an Array of products for a given dispensary 1046 | 1047 | ##### `state` (required) - [String] Two character state for the dispensary. 1048 | ##### `city` (required) - [String] City the dispensary is in (kebab-case). 1049 | ##### `slug` (required) - [String] Slug for the name of the dispensary. 1050 | ##### `options` (optional) - [Object] 1051 | * `sort` - [String] Possible values: 1052 | * `createdAt` - Oldest records 1053 | * `-createdAt` - Newest records 1054 | * `updatedAt` - Oldest updated records 1055 | * `-updatedAt` - Newest updated records 1056 | * `page` - [Number] By default, Cannabis Reports will return 10 records at a time for this API call. You can use the `page` argument to fetch the page of results you want. Check out the [pagination](https://developers.cannabisreports.com/docs/pagination) section of the documentation for further information. 1057 | 1058 | 1059 | ```javascript 1060 | Dispensary 1061 | .products('ca', 'san-francisco', 'grass-roots', options) 1062 | .then(data => console.log(data)) 1063 | .catch(err => console.log(err)) 1064 | ``` 1065 | --------------------------------------------------------------------------------