├── .npmrc ├── .eslintignore ├── templates ├── reset-form.ejs └── verify.ejs ├── test ├── mocha.opts ├── fixtures │ ├── simple-app │ │ ├── boot │ │ │ ├── bad.txt │ │ │ └── foo.js │ │ ├── common │ │ │ └── models │ │ │ │ ├── bar.json │ │ │ │ ├── foo.json │ │ │ │ └── bar.js │ │ └── server │ │ │ ├── datasources.json │ │ │ ├── config.json │ │ │ └── model-config.json │ ├── simple-integration-app │ │ ├── common │ │ │ └── models │ │ │ │ ├── access-token.json │ │ │ │ ├── profile.json │ │ │ │ ├── user.json │ │ │ │ ├── customer-forceid.json │ │ │ │ ├── email.json │ │ │ │ ├── widget.json │ │ │ │ ├── physician.json │ │ │ │ ├── store.json │ │ │ │ ├── customer.json │ │ │ │ ├── patient.json │ │ │ │ ├── store-replacing.json │ │ │ │ ├── store-updating.json │ │ │ │ └── appointment.json │ │ └── server │ │ │ ├── datasources.json │ │ │ ├── config.json │ │ │ ├── server.js │ │ │ └── model-config.json │ ├── shared-methods │ │ ├── both-configs-set │ │ │ ├── server │ │ │ │ ├── datasources.json │ │ │ │ ├── server.js │ │ │ │ ├── config.json │ │ │ │ └── model-config.json │ │ │ └── common │ │ │ │ └── models │ │ │ │ ├── todo.js │ │ │ │ └── todo.json │ │ ├── config-default-true │ │ │ ├── server │ │ │ │ ├── datasources.json │ │ │ │ ├── server.js │ │ │ │ ├── config.json │ │ │ │ └── model-config.json │ │ │ └── common │ │ │ │ └── models │ │ │ │ ├── todo.js │ │ │ │ └── todo.json │ │ ├── config-defined-true │ │ │ ├── server │ │ │ │ ├── datasources.json │ │ │ │ ├── server.js │ │ │ │ ├── config.json │ │ │ │ └── model-config.json │ │ │ └── common │ │ │ │ └── models │ │ │ │ ├── todo.js │ │ │ │ └── todo.json │ │ ├── config-default-false │ │ │ ├── server │ │ │ │ ├── datasources.json │ │ │ │ ├── server.js │ │ │ │ ├── config.json │ │ │ │ └── model-config.json │ │ │ └── common │ │ │ │ └── models │ │ │ │ ├── todo.js │ │ │ │ └── todo.json │ │ ├── config-defined-false │ │ │ ├── server │ │ │ │ ├── datasources.json │ │ │ │ ├── server.js │ │ │ │ ├── config.json │ │ │ │ └── model-config.json │ │ │ └── common │ │ │ │ └── models │ │ │ │ ├── todo.js │ │ │ │ └── todo.json │ │ ├── model-config-default-false │ │ │ ├── server │ │ │ │ ├── datasources.json │ │ │ │ ├── server.js │ │ │ │ ├── config.json │ │ │ │ └── model-config.json │ │ │ └── common │ │ │ │ └── models │ │ │ │ ├── todo.js │ │ │ │ └── todo.json │ │ ├── model-config-default-true │ │ │ ├── server │ │ │ │ ├── datasources.json │ │ │ │ ├── server.js │ │ │ │ ├── config.json │ │ │ │ └── model-config.json │ │ │ └── common │ │ │ │ └── models │ │ │ │ ├── todo.js │ │ │ │ └── todo.json │ │ ├── model-config-defined-false │ │ │ ├── server │ │ │ │ ├── datasources.json │ │ │ │ ├── server.js │ │ │ │ ├── config.json │ │ │ │ └── model-config.json │ │ │ └── common │ │ │ │ └── models │ │ │ │ ├── todo.js │ │ │ │ └── todo.json │ │ └── model-config-defined-true │ │ │ ├── server │ │ │ ├── datasources.json │ │ │ ├── server.js │ │ │ ├── config.json │ │ │ └── model-config.json │ │ │ └── common │ │ │ └── models │ │ │ ├── todo.js │ │ │ └── todo.json │ ├── access-control │ │ ├── server │ │ │ ├── datasources.json │ │ │ ├── config.json │ │ │ ├── server.js │ │ │ └── model-config.json │ │ └── common │ │ │ └── models │ │ │ ├── email.json │ │ │ ├── alert.json │ │ │ ├── transaction.json │ │ │ ├── user.json │ │ │ ├── access-token.json │ │ │ ├── bank.json │ │ │ ├── account.json │ │ │ └── accountWithReplaceOnPUTfalse.json │ ├── user-integration-app │ │ ├── server │ │ │ ├── datasources.json │ │ │ ├── config.json │ │ │ ├── server.js │ │ │ └── model-config.json │ │ └── common │ │ │ └── models │ │ │ ├── blog.json │ │ │ ├── my-user.json │ │ │ └── post.json │ └── e2e │ │ └── server │ │ ├── models.js │ │ └── server.js ├── helpers │ ├── expect.js │ ├── use-english.js │ ├── wait-for-event.js │ └── error-loggers.js ├── util │ ├── it.js │ └── describe.js ├── error-handler.test.js ├── e2e │ ├── remote-connector.e2e.js │ └── replication.e2e.js ├── memory.test.js ├── remoting-coercion.test.js ├── hidden-properties.test.js ├── geo-point.test.js ├── registries.test.js ├── email.test.js ├── integration.test.js ├── remote-connector.test.js ├── checkpoint.test.js ├── role-mapping.test.js ├── utils.test.js ├── authorization-scopes.test.js ├── karma.conf.js ├── change-stream.test.js └── data-source.test.js ├── favicon.ico ├── common └── models │ ├── key-value-model.json │ ├── checkpoint.json │ ├── email.json │ ├── scope.json │ ├── acl.json │ ├── change.json │ ├── role.json │ ├── role-mapping.json │ ├── access-token.json │ ├── scope.js │ ├── email.js │ ├── checkpoint.js │ ├── user.json │ ├── application.json │ ├── role-mapping.js │ └── README.md ├── docs ├── assets │ ├── lb-modules.png │ ├── explorer-api.png │ ├── loopback_ov.png │ ├── explorer-endpoint.png │ ├── explorer-listing.png │ ├── explorer-req-res.png │ ├── loopback-concepts.png │ └── loopback-architecture.png └── api-explorer-details.md ├── .nycrc ├── .gitignore ├── .eslintrc ├── .travis.yml ├── CODEOWNERS ├── lib ├── globalize.js ├── runtime.js ├── browser-express.js ├── connectors │ ├── memory.js │ ├── base-connector.js │ └── mail.js ├── current-context.js ├── configure-shared-methods.js ├── builtin-models.js └── utils.js ├── server └── middleware │ ├── error-handler.js │ ├── context.js │ ├── favicon.js │ ├── static.js │ ├── url-not-found.js │ ├── status.js │ └── rest.js ├── .github ├── ISSUE_TEMPLATE │ ├── Question.md │ ├── config.yml │ ├── Feature_request.md │ └── Bug_report.md ├── PULL_REQUEST_TEMPLATE.md └── stale.yml ├── example ├── colors │ └── app.js ├── simple-data-source │ └── app.js ├── client-server │ ├── client.js │ ├── server.js │ └── models.js ├── mobile-models │ └── app.js └── replication │ └── app.js ├── index.js ├── docs.json ├── LICENSE ├── package.json └── intl ├── zh-Hans └── messages.json └── zh-Hant └── messages.json /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | coverage 3 | -------------------------------------------------------------------------------- /templates/reset-form.ejs: -------------------------------------------------------------------------------- 1 |
4 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --require ./test/helpers/use-english 2 | -------------------------------------------------------------------------------- /test/fixtures/simple-app/boot/bad.txt: -------------------------------------------------------------------------------- 1 | this is not a js file! 2 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strongloop/loopback/HEAD/favicon.ico -------------------------------------------------------------------------------- /test/fixtures/simple-app/common/models/bar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "properties": {} 4 | } -------------------------------------------------------------------------------- /test/fixtures/simple-app/common/models/foo.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "properties": {} 4 | } -------------------------------------------------------------------------------- /common/models/key-value-model.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "KeyValueModel", 3 | "base": "Model" 4 | } 5 | -------------------------------------------------------------------------------- /docs/assets/lb-modules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strongloop/loopback/HEAD/docs/assets/lb-modules.png -------------------------------------------------------------------------------- /docs/assets/explorer-api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strongloop/loopback/HEAD/docs/assets/explorer-api.png -------------------------------------------------------------------------------- /docs/assets/loopback_ov.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strongloop/loopback/HEAD/docs/assets/loopback_ov.png -------------------------------------------------------------------------------- /test/fixtures/simple-app/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "connector": "memory" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": [ 3 | "Gruntfile.js", 4 | "test/**/*.js" 5 | ], 6 | "cache": true 7 | } 8 | -------------------------------------------------------------------------------- /docs/assets/explorer-endpoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strongloop/loopback/HEAD/docs/assets/explorer-endpoint.png -------------------------------------------------------------------------------- /docs/assets/explorer-listing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strongloop/loopback/HEAD/docs/assets/explorer-listing.png -------------------------------------------------------------------------------- /docs/assets/explorer-req-res.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strongloop/loopback/HEAD/docs/assets/explorer-req-res.png -------------------------------------------------------------------------------- /docs/assets/loopback-concepts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strongloop/loopback/HEAD/docs/assets/loopback-concepts.png -------------------------------------------------------------------------------- /docs/assets/loopback-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strongloop/loopback/HEAD/docs/assets/loopback-architecture.png -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/common/models/access-token.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "accessToken", 3 | "base": "AccessToken" 4 | } -------------------------------------------------------------------------------- /test/fixtures/shared-methods/both-configs-set/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-default-true/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-defined-true/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-default-false/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-defined-false/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/access-control/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "connector": "memory" 4 | }, 5 | "mail": { 6 | "connector": "mail" 7 | } 8 | } -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-default-false/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-default-true/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-defined-false/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-defined-true/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "connector": "memory" 4 | }, 5 | "mail": { 6 | "connector": "mail" 7 | } 8 | } -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/common/models/profile.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "profile", 3 | "base": "PersistedModel", 4 | "properties": { 5 | "points": { 6 | "type": "number" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /templates/verify.ejs: -------------------------------------------------------------------------------- 1 |4 | Thanks for registering. Please follow the link below to complete your registration. 5 |
6 | 7 |8 | <%= verifyHref %> 9 |
-------------------------------------------------------------------------------- /test/fixtures/access-control/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 3000, 3 | "host": "0.0.0.0", 4 | "remoting": { 5 | "errorHandler": { 6 | "debug": true, 7 | "log": false 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/fixtures/simple-app/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 3000, 3 | "host": "127.0.0.1", 4 | "remoting": { 5 | "errorHandler": { 6 | "debug": true, 7 | "log": false 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .project 3 | .DS_Store 4 | .vscode/ 5 | *.sublime* 6 | *.seed 7 | *.log 8 | *.csv 9 | *.dat 10 | *.out 11 | *.pid 12 | *.swp 13 | *.swo 14 | node_modules 15 | dist 16 | *xunit.xml 17 | .nyc_output/ 18 | -------------------------------------------------------------------------------- /test/fixtures/user-integration-app/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "connector": "memory" 4 | }, 5 | "mail": { 6 | "connector": "mail", 7 | "transports": [ 8 | {"type": "STUB"} 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "loopback", 3 | "rules": { 4 | "max-len": ["error", 100, 4, { 5 | "ignoreComments": true, 6 | "ignoreUrls": true, 7 | "ignorePattern": "^\\s*var\\s.+=\\s*(require\\s*\\()|(/)" 8 | }] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /common/models/checkpoint.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Checkpoint", 3 | "properties": { 4 | "seq": { 5 | "type": "number" 6 | }, 7 | "time": { 8 | "type": "date" 9 | }, 10 | "sourceId": { 11 | "type": "string" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/common/models/user.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "user", 3 | "base": "User", 4 | "relations": { 5 | "accessTokens": { 6 | "model": "accessToken", 7 | "type": "hasMany", 8 | "foreignKey": "userId" 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "8" 5 | - "10" 6 | - "12" 7 | - "14" 8 | 9 | addons: 10 | chrome: stable 11 | 12 | after_success: npm run coverage 13 | 14 | before_install: 15 | - npm config set registry http://ci.strongloop.com:4873/ 16 | -------------------------------------------------------------------------------- /test/fixtures/access-control/common/models/email.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "email", 3 | "base": "Email", 4 | "acls": [ 5 | { 6 | "accessType": "*", 7 | "permission": "DENY", 8 | "principalType": "ROLE", 9 | "principalId": "$everyone" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/common/models/customer-forceid.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "customerforceidfalse", 3 | "base": "PersistedModel", 4 | "forceId": false, 5 | "properties": { 6 | "name": { 7 | "type": "string", 8 | "required": true 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /test/fixtures/access-control/common/models/alert.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alert", 3 | "acls": [ 4 | { 5 | "accessType": "WRITE", 6 | "permission": "DENY", 7 | "principalType": "ROLE", 8 | "principalId": "$everyone" 9 | } 10 | ], 11 | "properties": {} 12 | } -------------------------------------------------------------------------------- /test/fixtures/simple-app/boot/foo.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2013,2018. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | process.loadedFooJS = true; 8 | -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/common/models/email.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "email", 3 | "base": "Email", 4 | "acls": [ 5 | { 6 | "accessType": "*", 7 | "permission": "DENY", 8 | "principalType": "ROLE", 9 | "principalId": "$everyone" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /test/fixtures/access-control/common/models/transaction.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "transaction", 3 | "acls": [ 4 | { 5 | "accessType": "*", 6 | "permission": "DENY", 7 | "principalType": "ROLE", 8 | "principalId": "$everyone" 9 | } 10 | ], 11 | "properties": {} 12 | } -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners, 3 | # the last matching pattern has the most precendence. 4 | 5 | # Current maintainers 6 | 7 | * @bajtos @fabien @clarkorz @ebarault @zbarbuto @nitro404 8 | 9 | # Alumni 10 | 11 | _ @lehni 12 | -------------------------------------------------------------------------------- /common/models/email.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Email", 3 | "base": "Model", 4 | "properties": { 5 | "to": {"type": "String", "required": true}, 6 | "from": {"type": "String", "required": true}, 7 | "subject": {"type": "String", "required": true}, 8 | "text": {"type": "String"}, 9 | "html": {"type": "String"} 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/common/models/widget.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "widget", 3 | "properties": { 4 | "name": { 5 | "type": "string", 6 | "default": "DefaultWidgetName" 7 | } 8 | }, 9 | "relations": { 10 | "store": { 11 | "model": "store", 12 | "type": "belongsTo" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/both-configs-set/common/models/todo.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2018. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | module.exports = function(Todo) { 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-default-false/common/models/todo.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2018. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | module.exports = function(Todo) { 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-default-true/common/models/todo.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2018. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | module.exports = function(Todo) { 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-defined-false/common/models/todo.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2018. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | module.exports = function(Todo) { 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-defined-true/common/models/todo.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2018. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | module.exports = function(Todo) { 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-default-true/common/models/todo.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2018. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | module.exports = function(Todo) { 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-defined-true/common/models/todo.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2018. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | module.exports = function(Todo) { 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/fixtures/simple-app/common/models/bar.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2018. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | module.exports = function(Bar) { 8 | process.loadedBarJS = true; 9 | }; 10 | -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/common/models/physician.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "physician", 3 | "properties": { 4 | "name": "string" 5 | }, 6 | "relations": { 7 | "patients": { 8 | "model": "patient", 9 | "type": "hasMany", 10 | "through": "appointment", 11 | "foreignKey": "patientId" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-default-false/common/models/todo.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2018. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | module.exports = function(Todo) { 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-defined-false/common/models/todo.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2018. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | module.exports = function(Todo) { 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/common/models/store.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "store", 3 | "properties": {}, 4 | "scopes": { 5 | "superStores": { 6 | "where": { 7 | "size": "super" 8 | } 9 | } 10 | }, 11 | "relations": { 12 | "widgets": { 13 | "model": "widget", 14 | "type": "hasMany" 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/common/models/customer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "customer", 3 | "base": "PersistedModel", 4 | "properties": { 5 | "name": { 6 | "type": "string", 7 | "required": true 8 | } 9 | }, 10 | "relations": { 11 | "profile": { 12 | "type": "hasOne", 13 | "model": "profile" 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /common/models/scope.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Scope", 3 | "description": [ 4 | "Schema for Scope which represents the permissions that are granted", 5 | "to client applications by the resource owner" 6 | ], 7 | "properties": { 8 | "name": { 9 | "type": "string", 10 | "required": true 11 | }, 12 | "description": "string" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/user-integration-app/common/models/blog.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blog", 3 | "base": "PersistedModel", 4 | "properties": { 5 | "title": { 6 | "type": "string" 7 | }, 8 | "content": { 9 | "type": "string" 10 | } 11 | }, 12 | "relations": { 13 | "user": { 14 | "type": "belongsTo", 15 | "model": "myUser" 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/common/models/patient.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "patient", 3 | "properties": { 4 | "name": "string" 5 | }, 6 | "options": { 7 | "relations": { 8 | "physicians": { 9 | "model": "physician", 10 | "type": "hasMany", 11 | "through": "appointment", 12 | "foreignKey": "physicianId" 13 | } 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /test/helpers/expect.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | 8 | const chai = require('chai'); 9 | chai.use(require('dirty-chai')); 10 | chai.use(require('sinon-chai')); 11 | 12 | module.exports = chai.expect; 13 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/both-configs-set/common/models/todo.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Todo", 3 | "base": "PersistedModel", 4 | "idInjection": true, 5 | "options": { 6 | "validateUpsert": true 7 | }, 8 | "properties": { 9 | "content": { 10 | "type": "string", 11 | "required": true 12 | } 13 | }, 14 | "validations": [], 15 | "relations": {}, 16 | "acls": [], 17 | "methods": {} 18 | } 19 | -------------------------------------------------------------------------------- /lib/globalize.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const path = require('path'); 8 | const SG = require('strong-globalize'); 9 | 10 | SG.SetRootDir(path.join(__dirname, '..'), {autonomousMsgLoading: 'all'}); 11 | module.exports = SG(); 12 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-default-false/common/models/todo.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Todo", 3 | "base": "PersistedModel", 4 | "idInjection": true, 5 | "options": { 6 | "validateUpsert": true 7 | }, 8 | "properties": { 9 | "content": { 10 | "type": "string", 11 | "required": true 12 | } 13 | }, 14 | "validations": [], 15 | "relations": {}, 16 | "acls": [], 17 | "methods": {} 18 | } 19 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-default-true/common/models/todo.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Todo", 3 | "base": "PersistedModel", 4 | "idInjection": true, 5 | "options": { 6 | "validateUpsert": true 7 | }, 8 | "properties": { 9 | "content": { 10 | "type": "string", 11 | "required": true 12 | } 13 | }, 14 | "validations": [], 15 | "relations": {}, 16 | "acls": [], 17 | "methods": {} 18 | } 19 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-defined-false/common/models/todo.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Todo", 3 | "base": "PersistedModel", 4 | "idInjection": true, 5 | "options": { 6 | "validateUpsert": true 7 | }, 8 | "properties": { 9 | "content": { 10 | "type": "string", 11 | "required": true 12 | } 13 | }, 14 | "validations": [], 15 | "relations": {}, 16 | "acls": [], 17 | "methods": {} 18 | } 19 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-defined-true/common/models/todo.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Todo", 3 | "base": "PersistedModel", 4 | "idInjection": true, 5 | "options": { 6 | "validateUpsert": true 7 | }, 8 | "properties": { 9 | "content": { 10 | "type": "string", 11 | "required": true 12 | } 13 | }, 14 | "validations": [], 15 | "relations": {}, 16 | "acls": [], 17 | "methods": {} 18 | } 19 | -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 3000, 3 | "host": "0.0.0.0", 4 | "cookieSecret": "2d13a01d-44fb-455c-80cb-db9cb3cd3cd0", 5 | "remoting": { 6 | "json": { 7 | "limit": "1kb", 8 | "strict": false 9 | }, 10 | "urlencoded": { 11 | "limit": "8kb" 12 | }, 13 | "errorHandler": { 14 | "debug": true, 15 | "log": false 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/fixtures/user-integration-app/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 3000, 3 | "host": "0.0.0.0", 4 | "cookieSecret": "2d13a01d-44fb-455c-80cb-db9cb3cd3cd0", 5 | "remoting": { 6 | "json": { 7 | "limit": "1kb", 8 | "strict": false 9 | }, 10 | "urlencoded": { 11 | "limit": "8kb" 12 | }, 13 | "errorHandler": { 14 | "debug": true, 15 | "log": false 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-default-false/common/models/todo.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Todo", 3 | "base": "PersistedModel", 4 | "idInjection": true, 5 | "options": { 6 | "validateUpsert": true 7 | }, 8 | "properties": { 9 | "content": { 10 | "type": "string", 11 | "required": true 12 | } 13 | }, 14 | "validations": [], 15 | "relations": {}, 16 | "acls": [], 17 | "methods": {} 18 | } 19 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-default-true/common/models/todo.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Todo", 3 | "base": "PersistedModel", 4 | "idInjection": true, 5 | "options": { 6 | "validateUpsert": true 7 | }, 8 | "properties": { 9 | "content": { 10 | "type": "string", 11 | "required": true 12 | } 13 | }, 14 | "validations": [], 15 | "relations": {}, 16 | "acls": [], 17 | "methods": {} 18 | } 19 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-defined-false/common/models/todo.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Todo", 3 | "base": "PersistedModel", 4 | "idInjection": true, 5 | "options": { 6 | "validateUpsert": true 7 | }, 8 | "properties": { 9 | "content": { 10 | "type": "string", 11 | "required": true 12 | } 13 | }, 14 | "validations": [], 15 | "relations": {}, 16 | "acls": [], 17 | "methods": {} 18 | } 19 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-defined-true/common/models/todo.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Todo", 3 | "base": "PersistedModel", 4 | "idInjection": true, 5 | "options": { 6 | "validateUpsert": true 7 | }, 8 | "properties": { 9 | "content": { 10 | "type": "string", 11 | "required": true 12 | } 13 | }, 14 | "validations": [], 15 | "relations": {}, 16 | "acls": [], 17 | "methods": {} 18 | } 19 | -------------------------------------------------------------------------------- /server/middleware/error-handler.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2018. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | module.exports = function(options) { 8 | throw new Error('loopback.errorHandler is no longer available.' + 9 | ' Please use the module "strong-error-handler" instead.'); 10 | }; 11 | -------------------------------------------------------------------------------- /test/fixtures/user-integration-app/common/models/my-user.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myUser", 3 | "base": "User", 4 | "relations": { 5 | "blogs": { 6 | "model": "blog", 7 | "type": "hasMany", 8 | "foreignKey": "userId" 9 | } 10 | }, 11 | "acls": [ 12 | { 13 | "permission": "ALLOW", 14 | "principalType": "ROLE", 15 | "principalId": "$owner" 16 | } 17 | ], 18 | "saltWorkFactor": 4 19 | } 20 | -------------------------------------------------------------------------------- /test/fixtures/user-integration-app/common/models/post.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Post", 3 | "base": "PersistedModel", 4 | "properties": { 5 | "title": { 6 | "type": "string" 7 | }, 8 | "content": { 9 | "type": "string" 10 | }, 11 | "notes": { 12 | "type": "string" 13 | } 14 | }, 15 | "relations": { 16 | "user": { 17 | "type": "belongsTo", 18 | "model": "User" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/common/models/store-replacing.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "storeWithReplaceOnPUTtrue", 3 | "plural": "stores-replacing", 4 | "properties": {}, 5 | "scopes": { 6 | "superStores": { 7 | "where": { 8 | "size": "super" 9 | } 10 | } 11 | }, 12 | "relations": { 13 | "widgets": { 14 | "model": "widget", 15 | "type": "hasMany" 16 | } 17 | }, 18 | "replaceOnPUT": true 19 | } -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/common/models/store-updating.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "storeWithReplaceOnPUTfalse", 3 | "plural": "stores-updating", 4 | "properties": {}, 5 | "scopes": { 6 | "superStores": { 7 | "where": { 8 | "size": "super" 9 | } 10 | } 11 | }, 12 | "relations": { 13 | "widgets": { 14 | "model": "widget", 15 | "type": "hasMany" 16 | } 17 | }, 18 | "replaceOnPUT": false 19 | } -------------------------------------------------------------------------------- /common/models/acl.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ACL", 3 | "properties": { 4 | "model": { 5 | "type": "string", 6 | "description": "The name of the model" 7 | }, 8 | "property": { 9 | "type": "string", 10 | "description": "The name of the property, method, scope, or relation" 11 | }, 12 | "accessType": "string", 13 | "permission": "string", 14 | "principalType": "string", 15 | "principalId": "string" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/fixtures/e2e/server/models.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const loopback = require('../../../../index'); 8 | const PersistedModel = loopback.PersistedModel; 9 | 10 | exports.TestModel = PersistedModel.extend('TestModel', {}, { 11 | trackChanges: true, 12 | }); 13 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/both-configs-set/server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const boot = require('loopback-boot'); 8 | const loopback = require('../../../../../index'); 9 | 10 | const app = module.exports = loopback(); 11 | boot(app, __dirname); 12 | app.use(loopback.rest()); 13 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-default-true/server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const boot = require('loopback-boot'); 8 | const loopback = require('../../../../../index'); 9 | 10 | const app = module.exports = loopback(); 11 | boot(app, __dirname); 12 | app.use(loopback.rest()); 13 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-defined-true/server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const boot = require('loopback-boot'); 8 | const loopback = require('../../../../../index'); 9 | 10 | const app = module.exports = loopback(); 11 | boot(app, __dirname); 12 | app.use(loopback.rest()); 13 | -------------------------------------------------------------------------------- /test/helpers/use-english.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2017,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | 8 | const env = process.env; 9 | 10 | // delete any user-provided language settings 11 | delete env.LC_ALL; 12 | delete env.LC_MESSAGES; 13 | delete env.LANG; 14 | delete env.LANGUAGE; 15 | delete env.STRONGLOOP_GLOBALIZE_APP_LANGUAGE; 16 | -------------------------------------------------------------------------------- /common/models/change.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Change", 3 | "trackChanges": false, 4 | "properties": { 5 | "id": { 6 | "type": "string", 7 | "id": true 8 | }, 9 | "rev": { 10 | "type": "string" 11 | }, 12 | "prev": { 13 | "type": "string" 14 | }, 15 | "checkpoint": { 16 | "type": "number" 17 | }, 18 | "modelName": { 19 | "type": "string" 20 | }, 21 | "modelId": { 22 | "type": "string" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-default-false/server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const boot = require('loopback-boot'); 8 | const loopback = require('../../../../../index'); 9 | 10 | const app = module.exports = loopback(); 11 | boot(app, __dirname); 12 | app.use(loopback.rest()); 13 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-defined-false/server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const boot = require('loopback-boot'); 8 | const loopback = require('../../../../../index'); 9 | 10 | const app = module.exports = loopback(); 11 | boot(app, __dirname); 12 | app.use(loopback.rest()); 13 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-default-false/server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const boot = require('loopback-boot'); 8 | const loopback = require('../../../../../index'); 9 | 10 | const app = module.exports = loopback(); 11 | boot(app, __dirname); 12 | app.use(loopback.rest()); 13 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-default-true/server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const boot = require('loopback-boot'); 8 | const loopback = require('../../../../../index'); 9 | 10 | const app = module.exports = loopback(); 11 | boot(app, __dirname); 12 | app.use(loopback.rest()); 13 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-defined-false/server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const boot = require('loopback-boot'); 8 | const loopback = require('../../../../../index'); 9 | 10 | const app = module.exports = loopback(); 11 | boot(app, __dirname); 12 | app.use(loopback.rest()); 13 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-defined-true/server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const boot = require('loopback-boot'); 8 | const loopback = require('../../../../../index'); 9 | 10 | const app = module.exports = loopback(); 11 | boot(app, __dirname); 12 | app.use(loopback.rest()); 13 | -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/common/models/appointment.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "appointment", 3 | "properties": { 4 | "date": "date" 5 | }, 6 | "options": { 7 | "relations": { 8 | "physician": { 9 | "model": "physician", 10 | "type": "belongsTo", 11 | "foreignKey": "physicianId" 12 | }, 13 | "patient": { 14 | "model": "patient", 15 | "type": "belongsTo", 16 | "foreignKey": "patientId" 17 | } 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /test/helpers/wait-for-event.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2017,2018. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | 8 | const Promise = require('bluebird'); 9 | 10 | function waitForEvent(emitter, event) { 11 | return new Promise((resolve, reject) => { 12 | emitter.on(event, resolve); 13 | }); 14 | } 15 | 16 | module.exports = waitForEvent; 17 | 18 | -------------------------------------------------------------------------------- /server/middleware/context.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const g = require('../../lib/globalize'); 8 | 9 | module.exports = function() { 10 | throw new Error(g.f( 11 | '%s middleware was removed in version 3.0. See %s for more details.', 12 | 'loopback#context', 13 | 'http://loopback.io/doc/en/lb2/Using-current-context.html', 14 | )); 15 | }; 16 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-default-false/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "rest": { 7 | "normalizeHttpPath": false, 8 | "xml": false 9 | }, 10 | "json": { 11 | "strict": false, 12 | "limit": "100kb" 13 | }, 14 | "urlencoded": { 15 | "extended": true, 16 | "limit": "100kb" 17 | }, 18 | "cors": false, 19 | "errorHandler": { 20 | "debug": true, 21 | "log": false 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-default-true/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "rest": { 7 | "normalizeHttpPath": false, 8 | "xml": false 9 | }, 10 | "json": { 11 | "strict": false, 12 | "limit": "100kb" 13 | }, 14 | "urlencoded": { 15 | "extended": true, 16 | "limit": "100kb" 17 | }, 18 | "cors": false, 19 | "errorHandler": { 20 | "debug": true, 21 | "log": false 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-defined-false/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "rest": { 7 | "normalizeHttpPath": false, 8 | "xml": false 9 | }, 10 | "json": { 11 | "strict": false, 12 | "limit": "100kb" 13 | }, 14 | "urlencoded": { 15 | "extended": true, 16 | "limit": "100kb" 17 | }, 18 | "cors": false, 19 | "errorHandler": { 20 | "debug": true, 21 | "log": false 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-defined-true/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "rest": { 7 | "normalizeHttpPath": false, 8 | "xml": false 9 | }, 10 | "json": { 11 | "strict": false, 12 | "limit": "100kb" 13 | }, 14 | "urlencoded": { 15 | "extended": true, 16 | "limit": "100kb" 17 | }, 18 | "cors": false, 19 | "errorHandler": { 20 | "debug": true, 21 | "log": false 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /server/middleware/favicon.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const favicon = require('serve-favicon'); 8 | const path = require('path'); 9 | 10 | /** 11 | * Serve the LoopBack favicon. 12 | * @header loopback.favicon() 13 | */ 14 | module.exports = function(icon, options) { 15 | icon = icon || path.join(__dirname, '../../favicon.ico'); 16 | return favicon(icon, options); 17 | }; 18 | -------------------------------------------------------------------------------- /test/fixtures/access-control/common/models/user.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "user", 3 | "base": "User", 4 | "relations": { 5 | "accessTokens": { 6 | "model": "accessToken", 7 | "type": "hasMany", 8 | "foreignKey": "userId" 9 | }, 10 | "transactions": { 11 | "model": "transaction", 12 | "type": "hasMany" 13 | } 14 | }, 15 | "acls": [ 16 | { 17 | "accessType": "*", 18 | "permission": "DENY", 19 | "principalType": "ROLE", 20 | "principalId": "$everyone" 21 | } 22 | ], 23 | "replaceOnPUT": false 24 | } 25 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-default-true/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "rest": { 7 | "normalizeHttpPath": false, 8 | "xml": false 9 | }, 10 | "json": { 11 | "strict": false, 12 | "limit": "100kb" 13 | }, 14 | "urlencoded": { 15 | "extended": true, 16 | "limit": "100kb" 17 | }, 18 | "cors": false, 19 | "errorHandler": { 20 | "debug": true, 21 | "log": false 22 | }, 23 | "sharedMethods": { 24 | "*": true 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-default-false/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "rest": { 7 | "normalizeHttpPath": false, 8 | "xml": false 9 | }, 10 | "json": { 11 | "strict": false, 12 | "limit": "100kb" 13 | }, 14 | "urlencoded": { 15 | "extended": true, 16 | "limit": "100kb" 17 | }, 18 | "cors": false, 19 | "errorHandler": { 20 | "debug": true, 21 | "log": false 22 | }, 23 | "sharedMethods": { 24 | "*": false 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-defined-false/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "rest": { 7 | "normalizeHttpPath": false, 8 | "xml": false 9 | }, 10 | "json": { 11 | "strict": false, 12 | "limit": "100kb" 13 | }, 14 | "urlencoded": { 15 | "extended": true, 16 | "limit": "100kb" 17 | }, 18 | "cors": false, 19 | "errorHandler": { 20 | "debug": true, 21 | "log": false 22 | }, 23 | "sharedMethods": { 24 | "find": false 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-defined-true/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "rest": { 7 | "normalizeHttpPath": false, 8 | "xml": false 9 | }, 10 | "json": { 11 | "strict": false, 12 | "limit": "100kb" 13 | }, 14 | "urlencoded": { 15 | "extended": true, 16 | "limit": "100kb" 17 | }, 18 | "cors": false, 19 | "errorHandler": { 20 | "debug": true, 21 | "log": false 22 | }, 23 | "sharedMethods": { 24 | "find": true 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/both-configs-set/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "rest": { 7 | "normalizeHttpPath": false, 8 | "xml": false 9 | }, 10 | "json": { 11 | "strict": false, 12 | "limit": "100kb" 13 | }, 14 | "urlencoded": { 15 | "extended": true, 16 | "limit": "100kb" 17 | }, 18 | "cors": false, 19 | "errorHandler": { 20 | "debug": true, 21 | "log": false 22 | }, 23 | "sharedMethods": { 24 | "*": false, 25 | "destroyAll": true 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /common/models/role.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Role", 3 | "properties": { 4 | 5 | "id": { 6 | "type": "string", 7 | "id": true, 8 | "generated": true 9 | }, 10 | "name": { 11 | "type": "string", 12 | "required": true 13 | }, 14 | "description": "string", 15 | "created": { 16 | "type":"date", 17 | "defaultFn": "now" 18 | }, 19 | "modified": { 20 | "type":"date", 21 | "defaultFn": "now" 22 | } 23 | }, 24 | "relations": { 25 | "principals": { 26 | "type": "hasMany", 27 | "model": "RoleMapping", 28 | "foreignKey": "roleId" 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/fixtures/access-control/common/models/access-token.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "accessToken", 3 | "base": "AccessToken", 4 | "baseUrl": "access-tokens", 5 | "acls": [ 6 | { 7 | "accessType": "*", 8 | "permission": "DENY", 9 | "principalType": "ROLE", 10 | "principalId": "$everyone" 11 | }, 12 | { 13 | "permission": "ALLOW", 14 | "principalType": "ROLE", 15 | "principalId": "$everyone", 16 | "property": "create" 17 | } 18 | ], 19 | "relations": { 20 | "user": { 21 | "type": "belongsTo", 22 | "model": "user", 23 | "foreignKey": "userId" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/util/it.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const loopback = require('../../'); 8 | 9 | module.exports = it; 10 | 11 | it.onServer = function itOnServer(name, fn) { 12 | if (loopback.isServer) { 13 | it(name, fn); 14 | } else { 15 | it.skip(name, fn); 16 | } 17 | }; 18 | 19 | it.inBrowser = function itInBrowser(name, fn) { 20 | if (loopback.isBrowser) { 21 | it(name, fn); 22 | } else { 23 | it.skip(name, fn); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const loopback = require('../../../../index'); 8 | const boot = require('loopback-boot'); 9 | const app = module.exports = loopback({localRegistry: true}); 10 | const errorHandler = require('strong-error-handler'); 11 | 12 | boot(app, __dirname); 13 | const apiPath = '/api'; 14 | app.use(apiPath, loopback.rest()); 15 | app.use(loopback.urlNotFound()); 16 | app.use(errorHandler()); 17 | -------------------------------------------------------------------------------- /test/fixtures/simple-app/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "../common/models", 5 | "./models", 6 | "../../../../common/models" 7 | ] 8 | }, 9 | "User": { 10 | "dataSource": "db", 11 | "public": false 12 | }, 13 | "AccessToken": { 14 | "dataSource": "db", 15 | "public": false 16 | }, 17 | "ACL": { 18 | "dataSource": "db", 19 | "public": false 20 | }, 21 | "RoleMapping": { 22 | "dataSource": "db", 23 | "public": false 24 | }, 25 | "Role": { 26 | "dataSource": "db", 27 | "public": false 28 | }, 29 | "foo": { 30 | "dataSource": "db" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /common/models/role-mapping.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RoleMapping", 3 | "description": "Map principals to roles", 4 | "properties": { 5 | "id": { 6 | "type": "string", 7 | "id": true, 8 | "generated": true 9 | }, 10 | "principalType": { 11 | "type": "string", 12 | "description": "The principal type, such as USER, APPLICATION, ROLE, or user model name in case of multiple user models" 13 | }, 14 | "principalId": { 15 | "type": "string", 16 | "index": true 17 | } 18 | }, 19 | "relations": { 20 | "role": { 21 | "type": "belongsTo", 22 | "model": "Role", 23 | "foreignKey": "roleId" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/error-handler.test.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const loopback = require('../'); 8 | let app; 9 | const assert = require('assert'); 10 | const request = require('supertest'); 11 | const expect = require('./helpers/expect'); 12 | 13 | describe('loopback.errorHandler(options)', function() { 14 | it('should throw a descriptive error', function() { 15 | expect(function() { loopback.errorHandler(); }) 16 | .to.throw(/no longer available.*strong-error-handler/); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /server/middleware/static.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2018. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | /** 7 | * Serve static assets of a LoopBack application. 8 | * 9 | * @param {string} root The root directory from which the static assets are to 10 | * be served. 11 | * @param {object} options Refer to 12 | * [express documentation](http://expressjs.com/4x/api.html#express.static) 13 | * for the full list of available options. 14 | * @header loopback.static(root, [options]) 15 | */ 16 | 'use strict'; 17 | module.exports = require('express').static; 18 | -------------------------------------------------------------------------------- /test/util/describe.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const loopback = require('../../'); 8 | 9 | module.exports = describe; 10 | 11 | describe.onServer = function describeOnServer(name, fn) { 12 | if (loopback.isServer) { 13 | describe(name, fn); 14 | } else { 15 | describe.skip(name, fn); 16 | } 17 | }; 18 | 19 | describe.inBrowser = function describeInBrowser(name, fn) { 20 | if (loopback.isBrowser) { 21 | describe(name, fn); 22 | } else { 23 | describe.skip(name, fn); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: The issue tracker is not for questions. Please use Stack Overflow or other resources for help. 4 | labels: question 5 | 6 | --- 7 | 8 | 28 | -------------------------------------------------------------------------------- /test/helpers/error-loggers.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2017,2018. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | 8 | exports.logAllServerErrors = function(app) { 9 | exports.logServerErrorsOtherThan(-1, app); 10 | }; 11 | 12 | exports.logServerErrorsOtherThan = function(statusCode, app) { 13 | app.use((err, req, res, next) => { 14 | if ((err.statusCode || 500) !== statusCode) { 15 | console.log('Unhandled error for request %s %s: %s', 16 | req.method, req.url, err.stack || err); 17 | } 18 | res.statusCode = err.statusCode || 500; 19 | res.json(err); 20 | }); 21 | }; 22 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | ## Checklist 12 | 13 | 👉 [Read and sign the CLA (Contributor License Agreement)](https://cla.strongloop.com/agreements/strongloop/loopback) 👈 14 | 15 | - [ ] `npm test` passes on your machine 16 | - [ ] New tests added or existing tests modified to cover all changes 17 | - [ ] Code conforms with the [style guide](https://loopback.io/doc/en/contrib/style-guide-es6.html) 18 | - [ ] Commit messages are following our [guidelines](https://loopback.io/doc/en/contrib/git-commit-messages.html) 19 | -------------------------------------------------------------------------------- /test/fixtures/access-control/server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const loopback = require('../../../..'); 8 | const boot = require('loopback-boot'); 9 | const app = module.exports = loopback({ 10 | localRegistry: true, 11 | loadBuiltinModels: true, 12 | }); 13 | const errorHandler = require('strong-error-handler'); 14 | 15 | boot(app, __dirname); 16 | 17 | const apiPath = '/api'; 18 | app.use(loopback.token({model: app.models.accessToken})); 19 | app.use(apiPath, loopback.rest()); 20 | 21 | app.use(loopback.urlNotFound()); 22 | app.use(errorHandler()); 23 | app.enableAuth(); 24 | -------------------------------------------------------------------------------- /test/fixtures/user-integration-app/server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const loopback = require('../../../../index'); 8 | const boot = require('loopback-boot'); 9 | const app = module.exports = loopback({ 10 | localRegistry: true, 11 | loadBuiltinModels: true, 12 | }); 13 | const errorHandler = require('strong-error-handler'); 14 | 15 | app.enableAuth(); 16 | boot(app, __dirname); 17 | app.use(loopback.token({model: app.models.AccessToken})); 18 | const apiPath = '/api'; 19 | app.use(apiPath, loopback.rest()); 20 | app.use(loopback.urlNotFound()); 21 | app.use(errorHandler()); 22 | -------------------------------------------------------------------------------- /test/fixtures/e2e/server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const loopback = require('../../../../index'); 8 | const app = module.exports = loopback({localRegistry: true}); 9 | const models = require('./models'); 10 | const TestModel = models.TestModel; 11 | 12 | const apiPath = '/api'; 13 | app.use(apiPath, loopback.rest()); 14 | 15 | TestModel.attachTo(loopback.memory()); 16 | app.model(TestModel); 17 | app.model(TestModel.getChangeModel()); 18 | 19 | // app.use(loopback.static(path.join(__dirname, 'public'))); 20 | app.use(loopback.urlNotFound()); 21 | app.use(loopback.errorHandler()); 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Report a security vulnerability 4 | url: https://loopback.io/doc/en/contrib/Reporting-issues.html#security-issues 5 | about: > 6 | LoopBack 3 has reached End-of-Life. No new security fixes will be provided 7 | or accepted. 8 | 9 | Do not report security vulnerabilities using GitHub issues. Please send an 10 | email to `reachsl@us.ibm.com` instead. 11 | - name: Get help on StackOverflow 12 | url: https://stackoverflow.com/tags/loopbackjs 13 | about: Please ask and answer questions on StackOverflow. 14 | - name: Join our mailing list 15 | url: https://groups.google.com/forum/#!forum/loopbackjs 16 | about: You can also post your question to our mailing list. 17 | -------------------------------------------------------------------------------- /lib/runtime.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | /* 7 | * This is an internal file that should not be used outside of loopback. 8 | * All exported entities can be accessed via the `loopback` object. 9 | * @private 10 | */ 11 | 12 | 'use strict'; 13 | const runtime = exports; 14 | 15 | /** 16 | * True if running in a browser environment; false otherwise. 17 | * @header loopback.isBrowser 18 | */ 19 | 20 | runtime.isBrowser = typeof window !== 'undefined'; 21 | 22 | /** 23 | * True if running in a server environment; false otherwise. 24 | * @header loopback.isServer 25 | */ 26 | 27 | runtime.isServer = !runtime.isBrowser; 28 | -------------------------------------------------------------------------------- /test/fixtures/access-control/common/models/bank.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bank", 3 | "relations": { 4 | "users": { 5 | "model": "user", 6 | "type": "hasMany" 7 | }, 8 | "accounts": { 9 | "model": "account", 10 | "type": "hasMany" 11 | } 12 | }, 13 | "acls": [ 14 | { 15 | "accessType": "*", 16 | "permission": "DENY", 17 | "principalType": "ROLE", 18 | "principalId": "$everyone" 19 | }, 20 | { 21 | "accessType": "READ", 22 | "permission": "ALLOW", 23 | "principalType": "ROLE", 24 | "principalId": "$everyone" 25 | }, 26 | { 27 | "accessType": "WRITE", 28 | "permission": "ALLOW", 29 | "principalType": "ROLE", 30 | "principalId": "$dynamic-role" 31 | } 32 | ], 33 | "properties": {} 34 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | labels: feature 5 | 6 | --- 7 | 8 | 16 | 17 | ## Suggestion 18 | 19 | 20 | 21 | ## Use Cases 22 | 23 | 27 | 28 | ## Examples 29 | 30 | 31 | 32 | ## Acceptance criteria 33 | 34 | TBD - will be filled by the team. 35 | -------------------------------------------------------------------------------- /example/colors/app.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2013,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const g = require('../../lib/globalize'); 8 | const loopback = require('../../'); 9 | const app = loopback(); 10 | 11 | app.use(loopback.rest()); 12 | 13 | const schema = { 14 | name: String, 15 | }; 16 | 17 | app.dataSource('db', {connector: 'memory'}); 18 | const Color = app.registry.createModel('color', schema); 19 | app.model(Color, {dataSource: 'db'}); 20 | 21 | Color.create({name: 'red'}); 22 | Color.create({name: 'green'}); 23 | Color.create({name: 'blue'}); 24 | 25 | app.listen(3000); 26 | 27 | g.log('a list of colors is available at {{http://localhost:3000/colors}}'); 28 | -------------------------------------------------------------------------------- /example/simple-data-source/app.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2013,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const g = require('../../lib/globalize'); 8 | const loopback = require('../../'); 9 | const app = loopback(); 10 | 11 | app.use(loopback.rest()); 12 | 13 | const dataSource = app.dataSource('db', {adapter: 'memory'}); 14 | 15 | const Color = dataSource.define('color', { 16 | 'name': String, 17 | }); 18 | 19 | Color.create({name: 'red'}); 20 | Color.create({name: 'green'}); 21 | Color.create({name: 'blue'}); 22 | 23 | Color.all(function() { 24 | console.log(arguments); 25 | }); 26 | 27 | app.listen(3000); 28 | 29 | g.log('a list of colors is available at {{http://localhost:3000/colors}}'); 30 | -------------------------------------------------------------------------------- /example/client-server/client.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const g = require('../../lib/globalize'); 8 | const loopback = require('../../'); 9 | const client = loopback(); 10 | const CartItem = require('./models').CartItem; 11 | const remote = loopback.createDataSource({ 12 | connector: loopback.Remote, 13 | url: 'http://localhost:3000', 14 | }); 15 | 16 | client.model(CartItem); 17 | CartItem.attachTo(remote); 18 | 19 | // call the remote method 20 | CartItem.sum(1, function(err, total) { 21 | g.log('result:%s', err || total); 22 | }); 23 | 24 | // call a built in remote method 25 | CartItem.find(function(err, items) { 26 | console.log(items); 27 | }); 28 | -------------------------------------------------------------------------------- /server/middleware/url-not-found.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | /*! 7 | * Export the middleware. 8 | * See discussion in Connect pull request #954 for more details 9 | * https://github.com/senchalabs/connect/pull/954. 10 | */ 11 | 'use strict'; 12 | module.exports = urlNotFound; 13 | 14 | /** 15 | * Convert any request not handled so far to a 404 error 16 | * to be handled by error-handling middleware. 17 | * @header loopback.urlNotFound() 18 | */ 19 | function urlNotFound() { 20 | return function raiseUrlNotFoundError(req, res, next) { 21 | const error = new Error('Cannot ' + req.method + ' ' + req.url); 22 | error.status = 404; 23 | next(error); 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-default-false/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "loopback/common/models", 5 | "loopback/server/models", 6 | "../common/models", 7 | "./models" 8 | ], 9 | "mixins": [ 10 | "loopback/common/mixins", 11 | "loopback/server/mixins", 12 | "../common/mixins", 13 | "./mixins" 14 | ] 15 | }, 16 | "User": { 17 | "dataSource": "db" 18 | }, 19 | "AccessToken": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "ACL": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "RoleMapping": { 28 | "dataSource": "db", 29 | "public": false 30 | }, 31 | "Role": { 32 | "dataSource": "db", 33 | "public": false 34 | }, 35 | "Todo": { 36 | "dataSource": "db", 37 | "public": true 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-default-true/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "loopback/common/models", 5 | "loopback/server/models", 6 | "../common/models", 7 | "./models" 8 | ], 9 | "mixins": [ 10 | "loopback/common/mixins", 11 | "loopback/server/mixins", 12 | "../common/mixins", 13 | "./mixins" 14 | ] 15 | }, 16 | "User": { 17 | "dataSource": "db" 18 | }, 19 | "AccessToken": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "ACL": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "RoleMapping": { 28 | "dataSource": "db", 29 | "public": false 30 | }, 31 | "Role": { 32 | "dataSource": "db", 33 | "public": false 34 | }, 35 | "Todo": { 36 | "dataSource": "db", 37 | "public": true 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-defined-false/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "loopback/common/models", 5 | "loopback/server/models", 6 | "../common/models", 7 | "./models" 8 | ], 9 | "mixins": [ 10 | "loopback/common/mixins", 11 | "loopback/server/mixins", 12 | "../common/mixins", 13 | "./mixins" 14 | ] 15 | }, 16 | "User": { 17 | "dataSource": "db" 18 | }, 19 | "AccessToken": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "ACL": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "RoleMapping": { 28 | "dataSource": "db", 29 | "public": false 30 | }, 31 | "Role": { 32 | "dataSource": "db", 33 | "public": false 34 | }, 35 | "Todo": { 36 | "dataSource": "db", 37 | "public": true 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/config-defined-true/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "loopback/common/models", 5 | "loopback/server/models", 6 | "../common/models", 7 | "./models" 8 | ], 9 | "mixins": [ 10 | "loopback/common/mixins", 11 | "loopback/server/mixins", 12 | "../common/mixins", 13 | "./mixins" 14 | ] 15 | }, 16 | "User": { 17 | "dataSource": "db" 18 | }, 19 | "AccessToken": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "ACL": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "RoleMapping": { 28 | "dataSource": "db", 29 | "public": false 30 | }, 31 | "Role": { 32 | "dataSource": "db", 33 | "public": false 34 | }, 35 | "Todo": { 36 | "dataSource": "db", 37 | "public": true 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /common/models/access-token.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AccessToken", 3 | "properties": { 4 | "id": { 5 | "type": "string", 6 | "id": true 7 | }, 8 | "ttl": { 9 | "type": "number", 10 | "ttl": true, 11 | "default": 1209600, 12 | "description": "time to live in seconds (2 weeks by default)" 13 | }, 14 | "scopes": { 15 | "type": ["string"], 16 | "description": "Array of scopes granted to this access token." 17 | }, 18 | "created": { 19 | "type": "Date", 20 | "defaultFn": "now" 21 | } 22 | }, 23 | "relations": { 24 | "user": { 25 | "type": "belongsTo", 26 | "model": "User", 27 | "foreignKey": "userId" 28 | } 29 | }, 30 | "acls": [ 31 | { 32 | "principalType": "ROLE", 33 | "principalId": "$everyone", 34 | "permission": "DENY" 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /example/client-server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const loopback = require('../../'); 8 | const server = module.exports = loopback(); 9 | const CartItem = require('./models').CartItem; 10 | const memory = loopback.createDataSource({ 11 | connector: loopback.Memory, 12 | }); 13 | 14 | server.use(loopback.rest()); 15 | server.model(CartItem); 16 | 17 | CartItem.attachTo(memory); 18 | 19 | // test data 20 | CartItem.create([ 21 | {item: 'red hat', qty: 6, price: 19.99, cartId: 1}, 22 | {item: 'green shirt', qty: 1, price: 14.99, cartId: 1}, 23 | {item: 'orange pants', qty: 58, price: 9.99, cartId: 1}, 24 | ]); 25 | 26 | CartItem.sum(1, function(err, total) { 27 | console.log(total); 28 | }); 29 | 30 | server.listen(3000); 31 | -------------------------------------------------------------------------------- /server/middleware/status.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | /*! 7 | * Export the middleware. 8 | */ 9 | 10 | 'use strict'; 11 | module.exports = status; 12 | 13 | /** 14 | * Return [HTTP response](http://expressjs.com/4x/api.html#res.send) with basic application status information: 15 | * date the application was started and uptime, in JSON format. 16 | * For example: 17 | * ```js 18 | * { 19 | * "started": "2014-06-05T00:26:49.750Z", 20 | * "uptime": 9.394 21 | * } 22 | * ``` 23 | * 24 | * @header loopback.status() 25 | */ 26 | function status() { 27 | const started = new Date(); 28 | 29 | return function(req, res) { 30 | res.send({ 31 | started: started, 32 | uptime: (Date.now() - Number(started)) / 1000, 33 | }); 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /lib/browser-express.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const EventEmitter = require('events').EventEmitter; 8 | const util = require('util'); 9 | 10 | module.exports = browserExpress; 11 | 12 | function browserExpress() { 13 | return new BrowserExpress(); 14 | } 15 | 16 | browserExpress.errorHandler = {}; 17 | 18 | function BrowserExpress() { 19 | this.settings = {}; 20 | } 21 | 22 | util.inherits(BrowserExpress, EventEmitter); 23 | 24 | BrowserExpress.prototype.set = function(key, value) { 25 | if (arguments.length == 1) { 26 | return this.get(key); 27 | } 28 | 29 | this.settings[key] = value; 30 | 31 | return this; // fluent API 32 | }; 33 | 34 | BrowserExpress.prototype.get = function(key) { 35 | return this.settings[key]; 36 | }; 37 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2013,2018. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | /** 8 | * loopback ~ public api 9 | */ 10 | 11 | const loopback = module.exports = require('./lib/loopback'); 12 | const datasourceJuggler = require('loopback-datasource-juggler'); 13 | 14 | /** 15 | * Connectors 16 | */ 17 | 18 | loopback.Connector = require('./lib/connectors/base-connector'); 19 | loopback.Memory = require('./lib/connectors/memory'); 20 | loopback.Mail = require('./lib/connectors/mail'); 21 | loopback.Remote = require('loopback-connector-remote'); 22 | 23 | /** 24 | * Types 25 | */ 26 | 27 | loopback.GeoPoint = require('loopback-datasource-juggler/lib/geo').GeoPoint; 28 | loopback.DateString = require('loopback-datasource-juggler/lib/date-string'); 29 | loopback.ValidationError = loopback.Model.ValidationError; 30 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/both-configs-set/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "loopback/common/models", 5 | "loopback/server/models", 6 | "../common/models", 7 | "./models" 8 | ], 9 | "mixins": [ 10 | "loopback/common/mixins", 11 | "loopback/server/mixins", 12 | "../common/mixins", 13 | "./mixins" 14 | ] 15 | }, 16 | "User": { 17 | "dataSource": "db" 18 | }, 19 | "AccessToken": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "ACL": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "RoleMapping": { 28 | "dataSource": "db", 29 | "public": false 30 | }, 31 | "Role": { 32 | "dataSource": "db", 33 | "public": false 34 | }, 35 | "Todo": { 36 | "dataSource": "db", 37 | "public": true, 38 | "options": { 39 | "remoting": { 40 | "sharedMethods": { 41 | "destroyAll": false 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-default-true/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "loopback/common/models", 5 | "loopback/server/models", 6 | "../common/models", 7 | "./models" 8 | ], 9 | "mixins": [ 10 | "loopback/common/mixins", 11 | "loopback/server/mixins", 12 | "../common/mixins", 13 | "./mixins" 14 | ] 15 | }, 16 | "User": { 17 | "dataSource": "db" 18 | }, 19 | "AccessToken": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "ACL": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "RoleMapping": { 28 | "dataSource": "db", 29 | "public": false 30 | }, 31 | "Role": { 32 | "dataSource": "db", 33 | "public": false 34 | }, 35 | "Todo": { 36 | "dataSource": "db", 37 | "public": true, 38 | "options": { 39 | "remoting": { 40 | "sharedMethods": { 41 | "*": true 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-default-false/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "loopback/common/models", 5 | "loopback/server/models", 6 | "../common/models", 7 | "./models" 8 | ], 9 | "mixins": [ 10 | "loopback/common/mixins", 11 | "loopback/server/mixins", 12 | "../common/mixins", 13 | "./mixins" 14 | ] 15 | }, 16 | "User": { 17 | "dataSource": "db" 18 | }, 19 | "AccessToken": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "ACL": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "RoleMapping": { 28 | "dataSource": "db", 29 | "public": false 30 | }, 31 | "Role": { 32 | "dataSource": "db", 33 | "public": false 34 | }, 35 | "Todo": { 36 | "dataSource": "db", 37 | "public": true, 38 | "options": { 39 | "remoting": { 40 | "sharedMethods": { 41 | "*": false 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-defined-false/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "loopback/common/models", 5 | "loopback/server/models", 6 | "../common/models", 7 | "./models" 8 | ], 9 | "mixins": [ 10 | "loopback/common/mixins", 11 | "loopback/server/mixins", 12 | "../common/mixins", 13 | "./mixins" 14 | ] 15 | }, 16 | "User": { 17 | "dataSource": "db" 18 | }, 19 | "AccessToken": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "ACL": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "RoleMapping": { 28 | "dataSource": "db", 29 | "public": false 30 | }, 31 | "Role": { 32 | "dataSource": "db", 33 | "public": false 34 | }, 35 | "Todo": { 36 | "dataSource": "db", 37 | "public": true, 38 | "options": { 39 | "remoting": { 40 | "sharedMethods": { 41 | "find": false 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/fixtures/shared-methods/model-config-defined-true/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "loopback/common/models", 5 | "loopback/server/models", 6 | "../common/models", 7 | "./models" 8 | ], 9 | "mixins": [ 10 | "loopback/common/mixins", 11 | "loopback/server/mixins", 12 | "../common/mixins", 13 | "./mixins" 14 | ] 15 | }, 16 | "User": { 17 | "dataSource": "db" 18 | }, 19 | "AccessToken": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "ACL": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "RoleMapping": { 28 | "dataSource": "db", 29 | "public": false 30 | }, 31 | "Role": { 32 | "dataSource": "db", 33 | "public": false 34 | }, 35 | "Todo": { 36 | "dataSource": "db", 37 | "public": true, 38 | "options": { 39 | "remoting": { 40 | "sharedMethods": { 41 | "find": true 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /docs.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "LoopBack Documentation", 3 | "content": [ 4 | "lib/application.js", 5 | "lib/server-app.js", 6 | "lib/loopback.js", 7 | "lib/registry.js", 8 | "lib/access-context.js", 9 | { "title": "Base models", "depth": 2 }, 10 | "lib/model.js", 11 | "lib/persisted-model.js", 12 | { "title": "Middleware", "depth": 2 }, 13 | "server/middleware/favicon.js", 14 | "server/middleware/rest.js", 15 | "server/middleware/static.js", 16 | "server/middleware/status.js", 17 | "server/middleware/token.js", 18 | "server/middleware/url-not-found.js", 19 | { "title": "Built-in models", "depth": 2 }, 20 | "common/models/access-token.js", 21 | "common/models/acl.js", 22 | "common/models/application.js", 23 | "common/models/change.js", 24 | "common/models/email.js", 25 | "common/models/key-value-model.js", 26 | "common/models/role.js", 27 | "common/models/role-mapping.js", 28 | "common/models/scope.js", 29 | "common/models/user.js" 30 | ], 31 | "assets": "/docs/assets" 32 | } 33 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 14 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | - critical 10 | # Label to use when marking an issue as stale 11 | staleLabel: stale 12 | # Comment to post when marking an issue as stale. Set to `false` to disable 13 | markComment: > 14 | This issue has been automatically marked as stale because it has not had 15 | recent activity. It will be closed if no further activity occurs. Thank you 16 | for your contributions. 17 | # Comment to post when closing a stale issue. Set to `false` to disable 18 | closeComment: > 19 | This issue has been closed due to continued inactivity. Thank you for your understanding. 20 | If you believe this to be in error, please contact one of the code owners, 21 | listed in the [`CODEOWNERS`](https://github.com/strongloop/loopback/blob/master/CODEOWNERS) file at the top-level of this repository. 22 | -------------------------------------------------------------------------------- /lib/connectors/memory.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2013,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | /** 7 | * Expose `Memory`. 8 | */ 9 | 10 | 'use strict'; 11 | module.exports = Memory; 12 | 13 | /** 14 | * Module dependencies. 15 | */ 16 | 17 | const Connector = require('./base-connector'); 18 | const debug = require('debug')('memory'); 19 | const util = require('util'); 20 | const inherits = util.inherits; 21 | const assert = require('assert'); 22 | const JdbMemory = require('loopback-datasource-juggler/lib/connectors/memory'); 23 | 24 | /** 25 | * Create a new `Memory` connector with the given `options`. 26 | * 27 | * @param {Object} options 28 | * @return {Memory} 29 | */ 30 | 31 | function Memory() { 32 | // TODO implement entire memory connector 33 | } 34 | 35 | /** 36 | * Inherit from `DBConnector`. 37 | */ 38 | 39 | inherits(Memory, Connector); 40 | 41 | /** 42 | * JugglingDB Compatibility 43 | */ 44 | 45 | Memory.initialize = JdbMemory.initialize; 46 | -------------------------------------------------------------------------------- /test/fixtures/access-control/common/models/account.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "accountWithReplaceOnPUTtrue", 3 | "plural": "accounts-replacing", 4 | "relations": { 5 | "transactions": { 6 | "model": "transaction", 7 | "type": "hasMany" 8 | }, 9 | "user": { 10 | "model": "user", 11 | "type": "belongsTo", 12 | "foreignKey": "userId" 13 | } 14 | }, 15 | "acls": [ 16 | { 17 | "accessType": "*", 18 | "permission": "DENY", 19 | "principalType": "ROLE", 20 | "principalId": "$everyone" 21 | }, 22 | { 23 | "accessType": "*", 24 | "permission": "ALLOW", 25 | "principalType": "ROLE", 26 | "principalId": "$owner" 27 | }, 28 | { 29 | "permission": "DENY", 30 | "principalType": "ROLE", 31 | "principalId": "$owner", 32 | "property": "deleteById" 33 | }, 34 | { 35 | "accessType": "*", 36 | "permission": "DENY", 37 | "property": "find", 38 | "principalType": "ROLE", 39 | "principalId": "$dummy" 40 | } 41 | ], 42 | "properties": {}, 43 | "replaceOnPUT": true 44 | } -------------------------------------------------------------------------------- /test/fixtures/access-control/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "../common/models", 5 | "./models", 6 | "../../../../common/models" 7 | ] 8 | }, 9 | "ACL": { 10 | "dataSource": "db", 11 | "public": false 12 | }, 13 | "RoleMapping": { 14 | "dataSource": "db", 15 | "public": false 16 | }, 17 | "Role": { 18 | "dataSource": "db", 19 | "public": false 20 | }, 21 | "email": { 22 | "dataSource": "mail", 23 | "public": false 24 | }, 25 | "user": { 26 | "dataSource": "db", 27 | "public": true 28 | }, 29 | "accessToken": { 30 | "dataSource": "db", 31 | "public": true 32 | }, 33 | "bank": { 34 | "public": true, 35 | "dataSource": "db" 36 | }, 37 | "accountWithReplaceOnPUTtrue": { 38 | "public": true, 39 | "dataSource": "db" 40 | }, 41 | "accountWithReplaceOnPUTfalse": { 42 | "public": true, 43 | "dataSource": "db" 44 | }, 45 | "transaction": { 46 | "public": true, 47 | "dataSource": "db" 48 | }, 49 | "alert": { 50 | "public": true, 51 | "dataSource": "db" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test/fixtures/access-control/common/models/accountWithReplaceOnPUTfalse.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "accountWithReplaceOnPUTfalse", 3 | "plural": "accounts-updating", 4 | "relations": { 5 | "transactions": { 6 | "model": "transaction", 7 | "type": "hasMany" 8 | }, 9 | "user": { 10 | "model": "user", 11 | "type": "belongsTo", 12 | "foreignKey": "userId" 13 | } 14 | }, 15 | "acls": [ 16 | { 17 | "accessType": "*", 18 | "permission": "DENY", 19 | "principalType": "ROLE", 20 | "principalId": "$everyone" 21 | }, 22 | { 23 | "accessType": "*", 24 | "permission": "ALLOW", 25 | "principalType": "ROLE", 26 | "principalId": "$owner" 27 | }, 28 | { 29 | "permission": "DENY", 30 | "principalType": "ROLE", 31 | "principalId": "$owner", 32 | "property": "deleteById" 33 | }, 34 | { 35 | "accessType": "*", 36 | "permission": "DENY", 37 | "property": "find", 38 | "principalType": "ROLE", 39 | "principalId": "$dummy" 40 | } 41 | ], 42 | "properties": {}, 43 | "replaceOnPUT": false 44 | } -------------------------------------------------------------------------------- /example/client-server/models.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const loopback = require('../../'); 8 | 9 | const CartItem = exports.CartItem = loopback.PersistedModel.extend('CartItem', { 10 | tax: {type: Number, default: 0.1}, 11 | price: Number, 12 | item: String, 13 | qty: {type: Number, default: 0}, 14 | cartId: Number, 15 | }); 16 | 17 | CartItem.sum = function(cartId, callback) { 18 | this.find({where: {cartId: cartId}}, function(err, items) { 19 | if (err) return callback(err); 20 | const total = items 21 | .map(function(item) { 22 | return item.total(); 23 | }) 24 | .reduce(function(cur, prev) { 25 | return prev + cur; 26 | }, 0); 27 | 28 | callback(null, total); 29 | }); 30 | }; 31 | 32 | CartItem.remoteMethod('sum', 33 | { 34 | accepts: {arg: 'cartId', type: 'number'}, 35 | returns: {arg: 'total', type: 'number'}, 36 | }); 37 | 38 | CartItem.prototype.total = function() { 39 | return this.price * this.qty * (1 + this.tax); 40 | }; 41 | -------------------------------------------------------------------------------- /test/fixtures/user-integration-app/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "../common/models", 5 | "./models", 6 | "../../../../common/models" 7 | ] 8 | }, 9 | "Email": { 10 | "dataSource": "mail", 11 | "public": false 12 | }, 13 | "User": { 14 | "dataSource": "db", 15 | "public": true, 16 | "relations": { 17 | "posts": { 18 | "model": "Post", 19 | "type": "hasMany", 20 | "foreignKey": "userId" 21 | } 22 | }, 23 | "acls": [ 24 | { 25 | "permission": "ALLOW", 26 | "principalType": "ROLE", 27 | "principalId": "$owner" 28 | } 29 | ] 30 | }, 31 | "AccessToken": { 32 | "dataSource": "db", 33 | "public": false 34 | }, 35 | "ACL": { 36 | "dataSource": "db", 37 | "public": false 38 | }, 39 | "RoleMapping": { 40 | "dataSource": "db", 41 | "public": false 42 | }, 43 | "Role": { 44 | "dataSource": "db", 45 | "public": false 46 | }, 47 | "myUser": { 48 | "dataSource": "db", 49 | "public": true 50 | }, 51 | "blog": { 52 | "dataSource": "db", 53 | "public": true 54 | }, 55 | "Post": { 56 | "dataSource": "db", 57 | "public": true 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) IBM Corp. 2013,2018. All Rights Reserved. 2 | Node module: loopback 3 | This project is licensed under the MIT License, full text below. 4 | 5 | -------- 6 | 7 | MIT license 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /test/e2e/remote-connector.e2e.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const path = require('path'); 8 | const loopback = require('../../'); 9 | const models = require('../fixtures/e2e/models'); 10 | const TestModel = models.TestModel; 11 | const assert = require('assert'); 12 | 13 | describe('RemoteConnector', function() { 14 | before(function() { 15 | // setup the remote connector 16 | const ds = loopback.createDataSource({ 17 | url: 'http://127.0.0.1:3000/api', 18 | connector: loopback.Remote, 19 | }); 20 | TestModel.attachTo(ds); 21 | }); 22 | 23 | it('should be able to call create', function(done) { 24 | TestModel.create({ 25 | foo: 'bar', 26 | }, function(err, inst) { 27 | if (err) return done(err); 28 | 29 | assert(inst.id); 30 | 31 | done(); 32 | }); 33 | }); 34 | 35 | it('should be able to call save', function(done) { 36 | const m = new TestModel({ 37 | foo: 'bar', 38 | }); 39 | m.save(function(err, data) { 40 | if (err) return done(err); 41 | 42 | assert(data.foo === 'bar'); 43 | 44 | done(); 45 | }); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /test/memory.test.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2013,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const assert = require('assert'); 8 | const loopback = require('../'); 9 | 10 | describe('Memory Connector', function() { 11 | it('Create a model using the memory connector', function(done) { 12 | // use the built in memory function 13 | // to create a memory data source 14 | let memory = loopback.memory(); 15 | 16 | // or create it using the standard 17 | // data source creation api 18 | memory = loopback.createDataSource({ 19 | connector: loopback.Memory, 20 | }); 21 | 22 | // create a model using the 23 | // memory data source 24 | const properties = { 25 | name: String, 26 | price: Number, 27 | }; 28 | 29 | const Product = memory.createModel('product', properties); 30 | 31 | Product.create([ 32 | {name: 'apple', price: 0.79}, 33 | {name: 'pear', price: 1.29}, 34 | {name: 'orange', price: 0.59}, 35 | ], count); 36 | 37 | function count() { 38 | Product.count(function(err, count) { 39 | assert.equal(count, 3); 40 | 41 | done(); 42 | }); 43 | } 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /lib/current-context.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const g = require('./globalize'); 8 | const juggler = require('loopback-datasource-juggler'); 9 | const remoting = require('strong-remoting'); 10 | 11 | module.exports = function(loopback) { 12 | juggler.getCurrentContext = 13 | remoting.getCurrentContext = 14 | loopback.getCurrentContext = function() { 15 | throw new Error(g.f( 16 | '%s was removed in version 3.0. See %s for more details.', 17 | 'loopback.getCurrentContext()', 18 | 'http://loopback.io/doc/en/lb2/Using-current-context.html', 19 | )); 20 | }; 21 | 22 | loopback.runInContext = function(fn) { 23 | throw new Error(g.f( 24 | '%s was removed in version 3.0. See %s for more details.', 25 | 'loopback.runInContext()', 26 | 'http://loopback.io/doc/en/lb2/Using-current-context.html', 27 | )); 28 | }; 29 | 30 | loopback.createContext = function(scopeName) { 31 | throw new Error(g.f( 32 | '%s was removed in version 3.0. See %s for more details.', 33 | 'loopback.createContext()', 34 | 'http://loopback.io/doc/en/lb2/Using-current-context.html', 35 | )); 36 | }; 37 | }; 38 | -------------------------------------------------------------------------------- /test/remoting-coercion.test.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const assert = require('assert'); 8 | const loopback = require('../'); 9 | const request = require('supertest'); 10 | 11 | describe('remoting coercion', function() { 12 | it('should coerce arguments based on the type', function(done) { 13 | let called = false; 14 | const app = loopback(); 15 | app.use(loopback.rest()); 16 | 17 | const TestModel = app.registry.createModel('TestModel', 18 | {}, 19 | {base: 'Model'}); 20 | app.model(TestModel, {public: true}); 21 | 22 | TestModel.test = function(inst, cb) { 23 | called = true; 24 | assert(inst instanceof TestModel); 25 | assert(inst.foo === 'bar'); 26 | cb(); 27 | }; 28 | TestModel.remoteMethod('test', { 29 | accepts: {arg: 'inst', type: 'TestModel', http: {source: 'body'}}, 30 | http: {path: '/test', verb: 'post'}, 31 | }); 32 | 33 | request(app) 34 | .post('/TestModels/test') 35 | .set('Content-Type', 'application/json') 36 | .send({ 37 | foo: 'bar', 38 | }) 39 | .end(function(err) { 40 | if (err) return done(err); 41 | 42 | assert(called); 43 | 44 | done(); 45 | }); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /test/e2e/replication.e2e.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const path = require('path'); 8 | const loopback = require('../../'); 9 | const models = require('../fixtures/e2e/models'); 10 | const TestModel = models.TestModel; 11 | const LocalTestModel = TestModel.extend('LocalTestModel', {}, { 12 | trackChanges: true, 13 | }); 14 | const assert = require('assert'); 15 | 16 | describe('Replication', function() { 17 | before(function() { 18 | // setup the remote connector 19 | const ds = loopback.createDataSource({ 20 | url: 'http://127.0.0.1:3000/api', 21 | connector: loopback.Remote, 22 | }); 23 | TestModel.attachTo(ds); 24 | const memory = loopback.memory(); 25 | LocalTestModel.attachTo(memory); 26 | }); 27 | 28 | it('should replicate local data to the remote', function(done) { 29 | const RANDOM = Math.random(); 30 | 31 | LocalTestModel.create({ 32 | n: RANDOM, 33 | }, function(err, created) { 34 | LocalTestModel.replicate(0, TestModel, function() { 35 | if (err) return done(err); 36 | 37 | TestModel.findOne({n: RANDOM}, function(err, found) { 38 | assert.equal(created.id, found.id); 39 | 40 | done(); 41 | }); 42 | }); 43 | }); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /lib/connectors/base-connector.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2013,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | /** 7 | * Expose `Connector`. 8 | */ 9 | 10 | 'use strict'; 11 | module.exports = Connector; 12 | 13 | /** 14 | * Module dependencies. 15 | */ 16 | 17 | const EventEmitter = require('events').EventEmitter; 18 | const debug = require('debug')('connector'); 19 | const util = require('util'); 20 | const inherits = util.inherits; 21 | const assert = require('assert'); 22 | 23 | /** 24 | * Create a new `Connector` with the given `options`. 25 | * 26 | * @param {Object} options 27 | * @return {Connector} 28 | */ 29 | 30 | function Connector(options) { 31 | EventEmitter.apply(this, arguments); 32 | this.options = options; 33 | 34 | debug('created with options', options); 35 | } 36 | 37 | /** 38 | * Inherit from `EventEmitter`. 39 | */ 40 | 41 | inherits(Connector, EventEmitter); 42 | 43 | /*! 44 | * Create an connector instance from a JugglingDB adapter. 45 | */ 46 | 47 | Connector._createJDBAdapter = function(jdbModule) { 48 | const fauxSchema = {}; 49 | jdbModule.initialize(fauxSchema, function() { 50 | // connected 51 | }); 52 | }; 53 | 54 | /*! 55 | * Add default crud operations from a JugglingDB adapter. 56 | */ 57 | 58 | Connector.prototype._addCrudOperationsFromJDBAdapter = function(connector) { 59 | 60 | }; 61 | -------------------------------------------------------------------------------- /test/fixtures/simple-integration-app/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "../common/models", 5 | "./models", 6 | "../../../../common/models" 7 | ] 8 | }, 9 | "ACL": { 10 | "dataSource": "db", 11 | "public": false 12 | }, 13 | "RoleMapping": { 14 | "dataSource": "db", 15 | "public": false 16 | }, 17 | "Role": { 18 | "dataSource": "db", 19 | "public": false 20 | }, 21 | "email": { 22 | "dataSource": "mail", 23 | "public": false 24 | }, 25 | "user": { 26 | "dataSource": "db", 27 | "public": true 28 | }, 29 | "accessToken": { 30 | "dataSource": "db", 31 | "public": true 32 | }, 33 | "widget": { 34 | "public": true, 35 | "dataSource": "db" 36 | }, 37 | "store": { 38 | "public": true, 39 | "dataSource": "db" 40 | }, 41 | "storeWithReplaceOnPUTfalse": { 42 | "public": true, 43 | "dataSource": "db" 44 | }, 45 | "storeWithReplaceOnPUTtrue": { 46 | "public": true, 47 | "dataSource": "db" 48 | }, 49 | "physician": { 50 | "dataSource": "db", 51 | "public": true 52 | }, 53 | "patient": { 54 | "dataSource": "db", 55 | "public": true 56 | }, 57 | "appointment": { 58 | "dataSource": "db", 59 | "public": true 60 | }, 61 | "customer": { 62 | "dataSource": "db", 63 | "public": true 64 | }, 65 | "profile": { 66 | "dataSource": "db", 67 | "public": true 68 | }, 69 | "customerforceidfalse": { 70 | "dataSource": "db", 71 | "public": true 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /example/mobile-models/app.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2013,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const g = require('../../lib/globalize'); 8 | const models = require('../../lib/models'); 9 | const loopback = require('../../'); 10 | const app = loopback(); 11 | 12 | app.use(loopback.rest()); 13 | 14 | const dataSource = loopback.createDataSource('db', {connector: loopback.Memory}); 15 | 16 | const Application = models.Application(dataSource); 17 | 18 | app.model(Application); 19 | 20 | const data = { 21 | pushSettings: [{ 22 | 'platform': 'apns', 23 | 'apns': { 24 | 'pushOptions': { 25 | 'gateway': 'gateway.sandbox.push.apple.com', 26 | 'cert': 'credentials/apns_cert_dev.pem', 27 | 'key': 'credentials/apns_key_dev.pem', 28 | }, 29 | 30 | 'feedbackOptions': { 31 | 'gateway': 'feedback.sandbox.push.apple.com', 32 | 'cert': 'credentials/apns_cert_dev.pem', 33 | 'key': 'credentials/apns_key_dev.pem', 34 | 'batchFeedback': true, 35 | 'interval': 300, 36 | }, 37 | }, 38 | }], 39 | }; 40 | 41 | Application.create(data, function(err, data) { 42 | g.log('Created: %s', data.toObject()); 43 | }); 44 | 45 | Application.register('rfeng', 'MyApp', {description: g.f('My first mobile application')}, 46 | function(err, result) { 47 | console.log(result.toObject()); 48 | 49 | result.resetKeys(function(err, result) { 50 | console.log(result.toObject()); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | labels: bug 5 | 6 | --- 7 | 8 | 21 | 22 | ## Steps to reproduce 23 | 24 | 25 | 26 | ## Current Behavior 27 | 28 | 29 | 30 | ## Expected Behavior 31 | 32 | 33 | 34 | ## Link to reproduction sandbox 35 | 36 | 40 | 41 | ## Additional information 42 | 43 | 48 | 49 | ## Related Issues 50 | 51 | 52 | 53 | _See [Reporting Issues](http://loopback.io/doc/en/contrib/Reporting-issues.html) for more tips on writing good issues_ 54 | -------------------------------------------------------------------------------- /common/models/scope.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const assert = require('assert'); 8 | const loopback = require('../../lib/loopback'); 9 | 10 | /** 11 | * Resource owner grants/delegates permissions to client applications 12 | * 13 | * For a protected resource, does the client application have the authorization 14 | * from the resource owner (user or system)? 15 | * 16 | * Scope has many resource access entries 17 | * 18 | * @class Scope 19 | */ 20 | 21 | module.exports = function(Scope) { 22 | Scope.resolveRelatedModels = function() { 23 | if (!this.aclModel) { 24 | const reg = this.registry; 25 | this.aclModel = reg.getModelByType(loopback.ACL); 26 | } 27 | }; 28 | 29 | /** 30 | * Check if the given scope is allowed to access the model/property 31 | * @param {String} scope The scope name 32 | * @param {String} model The model name 33 | * @param {String} property The property/method/relation name 34 | * @param {String} accessType The access type 35 | * @callback {Function} callback 36 | * @param {String|Error} err The error object 37 | * @param {AccessRequest} result The access permission 38 | */ 39 | Scope.checkPermission = function(scope, model, property, accessType, callback) { 40 | this.resolveRelatedModels(); 41 | const aclModel = this.aclModel; 42 | assert(aclModel, 43 | 'ACL model must be defined before Scope.checkPermission is called'); 44 | 45 | this.findOne({where: {name: scope}}, function(err, scope) { 46 | if (err) { 47 | if (callback) callback(err); 48 | } else { 49 | aclModel.checkPermission( 50 | aclModel.SCOPE, scope.id, model, property, accessType, callback, 51 | ); 52 | } 53 | }); 54 | }; 55 | }; 56 | -------------------------------------------------------------------------------- /common/models/email.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2014,2019. All Rights Reserved. 2 | // Node module: loopback 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | 'use strict'; 7 | const g = require('../../lib/globalize'); 8 | 9 | /** 10 | * Email model. Extends LoopBack base [Model](#model-new-model). 11 | * @property {String} to Email addressee. Required. 12 | * @property {String} from Email sender address. Required. 13 | * @property {String} subject Email subject string. Required. 14 | * @property {String} text Text body of email. 15 | * @property {String} html HTML body of email. 16 | * 17 | * @class Email 18 | * @inherits {Model} 19 | */ 20 | 21 | module.exports = function(Email) { 22 | /** 23 | * Send an email with the given `options`. 24 | * 25 | * Example Options: 26 | * 27 | * ```js 28 | * { 29 | * from: "Fred Foo