```
##### When exposing view locals to client-side JavaScript...
Use the `exposeLocalsToBrowser` partial to safely expose some or all of your view locals to client-side JavaScript:
```html
<%- exposeLocalsToBrowser(); %>
'
// }
// ],
// _csrf: 'oon95Uac-wKfWQKC5pHx1rP3HsiN9tjqGMyE'
// }
```
> Note that when you use this strategy, the strings in your view locals are no longer HTML unescaped after being exposed to client-side JavaScript.
> That's because you'll want to escape them _again_ when you stick them in the DOM. If you always escape at the point of injection, this stuff is a
> lot easier to keep track of. This way, you know you can safely escape _any_ string you inject into the DOM from your client-side JavaScript.
> (More on that below.)
#### On the client
A lot of XSS prevention is about what you do in your client-side code. Here are a few examples:
##### When injecting data into a client-side JST template...
Use `<%- %>` to HTML-encode data:
```html
Hello <%- me.username %>!
```
##### When modifying the DOM with client-side JavaScript...
Use something like `$(...).text()` to HTML-encode data:
```js
var $welcomeMsg = $('#signup').find('[is="welcome-msg"]');
welcomeMsg.text('Hello, '+window.SAILS_LOCALS.me.username+'!');
// Avoid using `$(...).html()` to inject untrusted data.
// Even if you know an XSS is not possible under particular circumstances,
// accidental escaping issues can cause really, really annoying client-side bugs.
```
> As you've probably figured out, the example above assumes you are using jQuery, but the same concepts apply regardless of what front-end library you are using.
### Additional Resources
+ [XSS (OWasp)](https://www.owasp.org/index.php/XSS)
+ [XSS Prevention Cheatsheet](https://www.owasp.org/index.php/XSS_Prevention_Cheat_Sheet)
### Notes
> + The examples above assume you are using the default view engine (EJS) and client-side JST/Lodash templates from the default asset pipeline.
================================================
FILE: docs/concepts/Services/Services.md
================================================
# Services
> _**Note**_: Although Services are still fully supported in Sails 1.0, it is recommended that you use [helpers](https://sailsjs.com/documentation/concepts/helpers) instead.
**Services** are stateless libraries of functions that you can use from anywhere in your Sails app. For example, you might have an `EmailService` which tidily wraps up one or more utility functions so you can use them in more than one place within your application.
Another benefit of using services in Sails is that they are *globalized*, which means that you don't have to use `require()` to access them, although you can if you prefer (you can also disable the automatic exposure of global variables in your app's configuration). By default, you can access a service and call its functions (e.g. `EmailService.sendHtmlEmail()` or `EmailService.sendPasswordRecoveryEmail()`) from anywhere: within controller actions, from inside other services, in custom model methods, or even from command-line scripts.
Hypothetically, one could create a service for:
- Sending an email
- Blasting tweets to celebrities
- Retrieving data from a third party API
But [helpers](https://sailsjs.com/documentation/concepts/helpers) are a better bet.
================================================
FILE: docs/concepts/Sessions/sessions.md
================================================
# How sessions work in Sails (advanced)
For our purposes, **sessions** are defined to be a few components that together allow you to store information about a user agent between requests.
> A **user agent** is the software (browser or native application) that represents you on a device (e.g. a browser tab on your computer, a smartphone application, or your refrigerator). It is associated one-to-one with a cookie or access token.
Sessions can be very useful because the request/response cycle is **stateless**. The request/response cycle is considered stateless because neither the client nor the server inherently stores any information between different requests about a particular request. Therefore, the lifecycle of a request/response ends when a response is made to the requesting user agent (e.g. `res.send()`).
Note: we’re going to discuss sessions in the context of a browser user agent. While you can use sessions in Sails for whatever you like, it is generally a best practice to use them purely for storing the state of user agent authentication. Authentication is a process that allows a user agent to prove that they have a certain identity. For example, in order to access some protected functionality, I might need to prove that my browser tab actually corresponds with a particular user record in a database. If I provide you with a unique name and a password, you can look up the name and compare my password with a stored (hopefully [encrypted](http://node-machine.org/machinepack-passwords/encrypt-password)) password. If there's a match, I'm authenticated. But how do you store that "authenticated-ness" between requests? That's where sessions come in.
### What sessions are made of
There are three main components to the implementation of sessions in Sails:
1. the **session store** where information is retained
2. the middleware that manages the session
3. a cookie that is sent along with every request and stores a session id (by default, `sails.sid`)
The **session store** can either be in memory (this is the default Sails session store) or in a database (Sails has built-in support for using Redis for this purpose). Sails builds on top of Connect middleware to manage the session, which includes using a **cookie** to store a session id (`sid`) on the user agent.
### A day in the life of a request, a response, and a session
When a request is sent to Sails, the request header is parsed by the session middleware.
##### Scenario 1: The request header has no cookie
If the header does not contain a cookie, a `sid` is created in the session and a default session dictionary is added to `req` (e.g. `req.session`). At this point you can make changes to the session property (usually in a controller/action). For example, let's look at the following login action:
```javascript
module.exports = {
login: function(req, res) {
// Authentication code here
// If successfully authenticated
req.session.userId = foundUser.id; // returned from a database
return res.json(foundUser);
}
}
```
Here we added a `userId` property to `req.session`.
> **Note:** the property will not be stored in the session store, nor will it be available to other requests until the response is sent.
Once the response is sent, any new requests will have access to `req.session.userId`. Since we didn't have a cookie in the request header, a cookie will be established for us.
##### Scenario 2: The request header has a cookie with a `Sails.sid`
Now when the user agent makes the next request, the `Sails.sid` stored on the cookie is checked for authenticity. If it matches an existing `sid` in the session store, the contents of the session store are added as a property on the `req` dictionary (`req.session`). We can access properties on `req.session` (e.g. `req.session.userId`) or set properties on it (e.g. `req.session.userId == someValue`). The values in the session store might change, but the `Sails.sid` and `sid` generally do not.
### When does the `Sails.sid` change?
During development, the Sails session store is in memory. Therefore, when you close the Sails server, the current session store disappears. When Sails is restarted, although a user agent request contains a `Sails.sid` in the cookie, the `sid` is no longer in the session store. Therefore, a new `sid` will be generated and replaced in the cookie. The `Sails.sid` will also change if the user agent cookie expires or is removed.
>The lifespan of a Sails cookie can be changed from its default setting (never expires) to a new setting by accessing the `cookie.maxAge` property in `projectName/config/session.js`.
### Using Redis as the session store
Redis is a key-value database package that can be used as a session store that is separate from the Sails instance. This configuration for sessions has two benefits. The first is that the session store will remain viable between Sails restarts. The second is that if you have multiple Sails instances behind a load balancer, all of the instances can point to a single consolidated session store.
#### Enabling Redis session store in development
To enable Redis as your session store in development, first make sure you have a local Redis instance running on your machine (`redis-server`). Then, lift your app with `sails lift --redis`.
This is just a shortcut for `sails lift --session.adapter=@sailshq/connect-redis --sockets.adapter=@sailshq/socket.io-redis`. These packages are included as dependencies of new Sails apps by default, but if you're working with an upgraded app you'll need to `npm install @sailshq/connect-redis` and `npm install @sailshq/socket.io-redis`.
> Note that this built-in configuration uses your local Redis instance. For advanced session configuration options, see [Reference > Configuration > sails.config.session](https://sailsjs.com/documentation/reference/configuration/sails-config-session).
#### Nerdy details of how the session cookie is created
The value for the cookie is created by first hashing the `sid` with a configurable *secret* which is just a long string.
> You can change the session `secret` property in `projectName/config/session.js`.
The Sails `sid` (e.g. `Sails.sid`) then becomes a combination of the plain `sid` followed by a hash of the `sid` plus the `secret`. To take this out of the world of abstraction, let's use an example. Sails creates a `sid` of `234lj232hg234jluy32UUYUHH` and a `session secret` of `9238cca11a83d473e10981c49c4f`. These values are simply two strings that Sails combines and hashes to create a `signature` of `AuSosBAbL9t3Ev44EofZtIpiMuV7fB2oi`. So the `Sails.sid` becomes `234lj232hg234jluy32UUYUHH.AuSosBAbL9t3Ev44EofZtIpiMuV7fB2oi` and is stored in the user agent cookie by sending a `set-cookie` property in the response header.
**What does this prevent?** This prevents a user from guessing the `sid`. It also prevents a evildoer from spoofing a user into making an authetication request with a `sid` that the evildoer knows. This could allow the evildoer to use the `sid` to do bad things while the user is authenticated via the session.
### Disabling sessions
Even if your Sails app is designed to be accessed by non-browser clients, such as toasters, you are strongly encouraged to use sessions for authentication. While it can sometimes be complex to understand, the built-in session mechanism in Sails (session store + HTTP-only cookies) is a tried and true solution that is generally [less brittle, easier to use, and lower-risk than rolling out something yourself](http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/).
That said, sessions may not always be an option (for example, if you must [integrate with a different authentication scheme](https://github.com/sails101/jwt-login) like JWT). In these cases, you can disable sessions on an app-wide or per-request basis.
##### Disabling sessions for your entire app
To entirely turn off session support for your app, add the following to your `.sailsrc` file:
```javascript
"hooks": {
"session": false
}
```
This disables the core Sails session hook. You can also accomplish this by setting the `sails_hooks__session` environment variable to `false`.
##### Disabling sessions for certain requests
To turn off session support on a per-route (or per-request) basis, use the [`sails.config.session.isSessionDisabled` setting](https://sailsjs.com/documentation/reference/configuration/sails-config-session#?properties). By default, Sails enables session support for all requests except those that [look like](https://sailsjs.com/documentation/reference/application/advanced-usage/sails-looks-like-asset-rx) they're pointed at static assets like images, stylesheets, etc.
================================================
FILE: docs/concepts/Testing/Testing.md
================================================
# Testing your code
This section of the documentation runs through how you might go about testing your Sails application. There are countless test frameworks and assertion libraries for Sails and Node.js; pick one that fits your needs.
> There is no official strategy for testing in the Sails framework, and this page is a collaborative, community-driven guide that has not been thoroughly vetted by Sails core team members. If you run across something that seems confusing or incorrect, feel free to submit a pull request.
### Preparation
For our example test suite, we'll use [mocha](http://mochajs.org/).
```bash
npm install mocha --save-dev
```
Before you start building your test cases, organize your `test/` directory structure. Once again, when it comes to automated testing, there are several different organizational approaches you might choose. For this example, we'll go about it as follows:
```bash
./myApp
├── api/
├── assets/
├── ...
├── test/
│ ├── integration/
│ │ ├── controllers/
│ │ │ └── UserController.test.js
│ │ ├── models/
│ │ │ └── User.test.js
│ │ └── helpers/
| | └── ...
│ ├── fixtures/
| │ └── ...
│ ├── lifecycle.test.js
│ └── mocha.opts
├── ...
└── views/
```
##### lifecycle.test.js
This file is useful when you want to execute some code before and after running your tests (e.g. lifting and lowering your Sails application). Since your models are converted to Waterline collections on lift, it is necessary to lift your Sails app before trying to test them (this applies controllers and other parts of your app, too, so be sure to call this file first).
```javascript
var sails = require('sails');
// Before running any tests...
before(function(done) {
// Increase the Mocha timeout so that Sails has enough time to lift, even if you have a bunch of assets.
this.timeout(5000);
sails.lift({
// Your Sails app's configuration files will be loaded automatically,
// but you can also specify any other special overrides here for testing purposes.
// For example, we might want to skip the Grunt hook,
// and disable all logs except errors and warnings:
hooks: { grunt: false },
log: { level: 'warn' },
}, function(err) {
if (err) { return done(err); }
// here you can load fixtures, etc.
// (for example, you might want to create some records in the database)
return done();
});
});
// After all tests have finished...
after(function(done) {
// here you can clear fixtures, etc.
// (e.g. you might want to destroy the records you created above)
sails.lower(done);
});
```
##### mocha.opts
This file is optional. You can use it as an alternative to command-line options for specifying [custom Mocha configuration](https://mochajs.org/#mochaopts).
One notable customization option is timeout. The default timeout in Mocha is 2 seconds, which is sufficient for most test cases but may be too short depending on how often your tests are lifting and lowering Sails. To ensure that Sails lifts in time to finish your first test, you may need to increase the timeout value in mocha.opts:
```bash
--timeout 10000
```
> **Note**: If you are writing your tests in a transpiled language such as CoffeeScript (`.coffee` files instead of `.js` files), you'll need to take an extra step to configure Mocha accordingly. For example, you might add these lines to your `mocha.opts`:
>
> ```bash
> --require coffee-script/register
> --compilers coffee:coffee-script/register
> ```
>
> _If you prefer Typescript, the approach is basically the same, except you'll want to use `--require ts-node/register`.
### Writing tests
Once you have prepared your directory, you can start writing your integration tests:
```js
// ./test/integration/models/User.test.js
var util = require('util');
describe('User (model)', function() {
describe('#findBestStudents()', function() {
it('should return 5 users', function (done) {
User.findBestStudents()
.then(function(bestStudents) {
if (bestStudents.length !== 5) {
return done(new Error(
'Should return exactly 5 students -- the students '+
'from our test fixtures who are considered the "best". '+
'But instead, got: '+util.inspect(bestStudents, {depth:null})+''
));
}//-•
return done();
})
.catch(done);
});
});
});
```
### Testing actions & controllers
The most fundamental tests for your backend code involve sending an HTTP request and checking the response. There are numerous ways to go about this, whether it's a full-fledged testing tool, like Supertest, or a pure utility like [`request`](https://npmjs.com/package/request) or [`mp-http`](https://npmjs.com/package/machinepack-http), combined with [`assert`](https://nodejs.org/dist/latest/docs/api/assert.html).
##### Using Supertest
Let's take [Supertest](https://github.com/visionmedia/supertest) for a spin:
```bash
npm install supertest --save-dev
```
The idea behind Supertest is to provide a high-level tool that helps build a specific type of test—specifically, the type of test that send an HTTP request to your Sails app and checks the response.
```js
// test/integration/controllers/UserController.test.js
var supertest = require('supertest');
describe('UserController.login', function() {
describe('#login()', function() {
it('should redirect to /my/page', function (done) {
supertest(sails.hooks.http.app)
.post('/users/login')
.send({ name: 'test', password: 'test' })
.expect(302)
.expect('location','/my/page', done);
});
});
});
```
### Running tests
In order to run your test using Mocha, you'll have to use `mocha` in the command line then pass as arguments any test you want to run. Be sure to call lifecycle.test.js before the rest of your tests, like this: `mocha test/lifecycle.test.js test/integration/**/*.test.js`
##### Using `npm test` to run your test
You can modify your package.json file to use `npm test` instead of Mocha, and thus avoid typing out the Mocha command described above. This is particularly useful when calling lifecycle.test.js.
On the scripts dictionary, add a `test` key and use the following as its value: `mocha test/lifecycle.test.js test/integration/**/*.test.js`. This looks like:
```json
"scripts": {
"start": "node app.js",
"debug": "node debug app.js",
"test": "node ./node_modules/mocha/bin/mocha test/lifecycle.test.js test/integration/**/*.test.js"
}
```
The `*` is a wildcard used to match any file inside the `integration/` folder that ends in `.test.js`. If it suits you, you can modify it to search for `*.spec.js` instead. In the same way, you can use wildcards for your folders by using two `*` instead of one.
> As of Sails v1, Sails apps are generated with a `test` script already in their package.json file, but you'll still want to make some modifications to it for this example. If you're upgrading an existing app, you may have to add a `test` key by hand.
### Continuous integration
If you'd like to have a system automatically run your tests every time you push to your source code repository, you're in luck! Many different continuous integration systems support Sails/Node.js, so you can have your pick. Here are a few popular choices to get you started:
+ [Circle CI](https://circleci.com/)
+ [Travis CI](http://travis-ci.com)
+ [Semaphore CI](https://semaphoreci.com/)
+ [Appveyor](http://appveyor.com) _(useful if you'll be deploying to a Windows server)_
> All of the options above charge a monthly fee for proprietary apps but are free for open source. Circle CI is free for proprietary apps as well, but throttled to two builds at a time. Semaphore is also free and and allows you 4x parallel CI/CD jobs.
### Load testing
A [number of commercial options](http://www.bing.com/search?q=load+testing) exist for load testing web applications. You can also get a reasonable idea of how your app will perform using tools like [`ab`](http://httpd.apache.org/docs/2.4/programs/ab.html) or [JMeter](http://jmeter.apache.org/). Just remember, the goal is to simulate real traffic. For more help setting up your Sails app to be production-ready and scalable, see [Scalability](https://sailsjs.com/documentation/concepts/deployment/scaling). For additional help or more specific questions, click [here](https://sailsjs.com/support).
### Optimizing performance
Usually, the scalability and overall performance of your app is more important than the performance and latency of any given individual request to a particular endpoint. So rather than focusing on one piece of code in isolation, we recommend starting with [the basics](https://sailsjs.com/documentation/concepts/deployment/scaling); for most apps, that's good enough. For some use cases (e.g. serving ads, or apps with very computationally-intensive functionality), though, individual request latency may be important from the get-go.
For testing the performance of particular chunks of code, or for benchmarking the latency of individual requests to particular endpoints, a great option is [benchmark.js](https://www.npmjs.com/package/benchmark). Not only is it a robust library that supports high-resolution timers and returns statistically significant results, it also works great with Mocha out of the box.
================================================
FILE: docs/concepts/Views/Layouts.md
================================================
# Layouts
When building an app with many different pages, it can be helpful to extrapolate markup shared by several HTML files into a layout. This [reduces the total amount of code](http://en.wikipedia.org/wiki/Don't_repeat_yourself) in your project and helps you avoid making the same changes in multiple files down the road.
In Sails and Express, layouts are implemented by the view engines themselves. For instance, `jade` has its own layout system, with its own syntax.
For convenience, Sails bundles special support for layouts **when using the default view engine, EJS**. If you'd like to use layouts with a different view engine, check out [that view engine's documentation](https://sailsjs.com/documentation/concepts/views/view-engines) to find the appropriate syntax.
### Creating layouts
Sails layouts are special `.ejs` files in your app's `views/` folder you can use to "wrap" or "sandwich" other views. Layouts usually contain the preamble (e.g. `....`) and conclusion (``). The original view file is included using `<%- body %>`. Layouts are never used without a view: that would be like serving someone a bread sandwich.
Layout support for your app can be configured or disabled in [`config/views.js`](https://sailsjs.com/documentation/anatomy/config/views.js), and it can be overridden for a particular route or action by setting a special [local](https://sailsjs.com/documentation/concepts/views/locals) called `layout`. By default, Sails will compile all views using the layout located at `views/layouts/layout.ejs`.
To specify what layout a view uses, see the example below. There is more information in the docs at [routes](https://sailsjs.com/documentation/concepts/routes).
The example route below will use the view located at `./views/users/privacy.ejs` within the layout located at `./views/users.ejs`
```javascript
'get /privacy': {
view: 'users/privacy',
locals: {
layout: 'users'
}
},
```
The example controller action below will use the view located at `./views/users/privacy.ejs` within the layout located at `./views/users.ejs`
```javascript
privacy: function (req, res) {
res.view('users/privacy', {layout: 'users'})
}
```
### Notes
> #### Why do layouts only work for EJS?
> A couple of years ago, built-in support for layouts/partials was deprecated in Express. Instead, developers were expected to rely on the view engines themselves to implement this feature. (See https://github.com/balderdashy/sails/issues/494 for more information.)
>
> Sails supports the legacy `layouts` feature for convenience, backwards compatibility with Express 2.x and Sails 0.8.x apps, and in particular, familiarity for new community members coming from other MVC frameworks. As a result, layouts have only been tested with the default view engine (ejs).
>
> If layouts aren’t your thing, or (for now) if you’re using a server-side view engine other than ejs, (e.g. Jade, handlebars, haml, dust) you’ll want to set `layout:false` in [`sails.config.views`](https://sailsjs.com/documentation/reference/configuration/sails-config-views) and rely on your view engine’s custom layout/partial support.
================================================
FILE: docs/concepts/Views/Locals.md
================================================
# Locals
The variables accessible in a particular view are called `locals`. Locals represent server-side data that is _accessible_ to your view—locals are not actually _included_ in the compiled HTML unless you explicitly reference them using special syntax provided by your view engine.
```ejs
```
### Using locals in your views
The notation for accessing locals varies between view engines. In EJS, you use special template markup (e.g. `<%= someValue %>`) to include locals in your views.
There are three kinds of template tags in EJS:
+ `<%= someValue %>`
+ HTML-escapes the `someValue` local, and then includes it as a string.
+ `<%- someRawHTML %>`
+ Includes the `someRawHTML` local verbatim, without escaping it.
+ Be careful! This tag can make you vulnerable to XSS attacks if you don't know what you're doing.
+ `<% if (!loggedIn) { %> Logout <% } %>`
+ Runs the JavaScript inside the `<% ... %>` when the view is compiled.
+ Useful for conditionals (`if`/`else`), and looping over data (`for`/`each`).
Here's an example of a view (`views/backOffice/profile.ejs`) using two locals, `user` and `corndogs`:
```ejs
<%= user.fullName %>'s first view
My corndog collection:
<% for (let corndog of corndogs) { %>
<%= _.capitalize(corndog.name) %>
<% } %>
```
> You might have noticed another local: `_`. By default, Sails passes down a few locals to your views automatically, one of which is lodash (`_`).
If the data you wanted to pass down to this view was completely static, you wouldn't necessarily need a controller. Instead, you could hard-code the view and its locals in your `config/routes.js` file, like so:
```javascript
// ...
'get /profile': {
view: 'backOffice/profile',
locals: {
user: {
fullName: 'Frank',
emailAddress: 'frank@enfurter.com'
},
corndogs: [
{ name: 'beef corndog' },
{ name: 'chicken corndog' },
{ name: 'soy corndog' }
]
}
},
// ...
```
More likely, though, this data will be dynamic. In this scenario, we'd need to use a controller action to load the data from our models, then pass it to the view using the [res.view()](https://sailsjs.com/documentation/reference/response-res/res-view) method.
Assuming we hooked up our route to one of our controller's actions (and our models were set up), we might send down our view like this:
```javascript
// in api/controllers/UserController.js...
profile: function (req, res) {
// ...
return res.view('backOffice/profile', {
user: theUser,
corndogs: theUser.corndogCollection
});
},
// ...
```
### Escaping untrusted data using `exposeLocalsToBrowser`
It is often desirable to “bootstrap” data onto a page so that it’s available via Javascript as soon as the page loads, rather than having to fetch the data in a separate AJAX or socket request. Sites like [Twitter and GitHub](https://blog.twitter.com/2012/improving-performance-on-twittercom) rely heavily on this approach in order to optimize page load times and provide an improved user experience.
Historically, this problem was commonly solved using hidden form fields or by hand-rolling code that injected server-side locals directly into a client-side script tag. While effective, these techniques can present challenges when some of the data to be bootstrapped is from an _untrusted_ source that might contain HTML tags and Javascript code meant to compromise your app with an XSS attack. To prevent situations like this, Sails provides a built-in view partial called `exposeLocalsToBrowser` that you can use to securely inject data from your view locals for access from client-side JavaScript.
To use `exposeLocalsToBrowser`, simply call it from within your view using the _non-escaping syntax_ for your template language. For example, using the default EJS view engine:
```ejs
<%- exposeLocalsToBrowser() %>
```
By default, this exposes _all_ of your view locals as the `window.SAILS_LOCALS` global variable. For example, if your action code contained:
```javascript
res.view('myView', {
someString: 'hello',
someNumber: 123,
someObject: { owl: 'hoot' },
someArray: [1, 'boot', true],
someBool: false
someXSS: ''
});
```
then using `exposeLocalsToBrowser` as shown above would cause the locals to be safely bootstrapped in such a way that `window.SAILS_LOCALS.someArray` would contain the array `[1, 'boot', true]`, and `window.SAILS_LOCALS.someXSS` would contain the _string_ `` without causing that code to actually be executed on the page.
The `exposeLocalsToBrowser` function has a single `options` parameter that can be used to configure what data is outputted, and how. The `options` parameter is a dictionary that can contain the following properties:
| | Property | Type | Default| Details |
|---|:--------------------|----------------------------------------------|:-----------------------------------|-----|
| 1 | _keys_ | ((array?)) | `undefined` | A “whitelist” of locals to expose. If left undefined, _all_ locals will be exposed. If specified, this should be an array of property names from the locals dictionary. For example, given the `res.view()` statement shown above, setting `keys: ['someString', 'someBool']` would cause `windows.SAILS_LOCALS` to be set to `{someString: 'hello', someBool: false}`.
| 2 | _namespace_ | ((string?)) | `SAILS_LOCALS` | The name of the global variable to which the bootstrapped data should be assigned.
| 3| _dontUnescapeOnClient_ | ((boolean?)) | false | **Advanced. Not recommended for most apps.** If set to `true`, any string values that were escaped to avoid XSS attacks will _still be escaped_ when accessed from client-side JS, instead of being transformed back into the original value. For example, given the `res.view()` statement from the example above, using `exposeLocalsToBrowser({dontUnescapeOnClient: true})` would cause `window.SAILS_LOCALS.someXSS` to be set to `<script>alert('hello!');`.
================================================
FILE: docs/concepts/Views/Partials.md
================================================
# Partials
When using the default view engine (`ejs`), Sails supports the use of _partials_ (i.e. "view partials"). Partials are basically just views that are designed to be used from within other views.
They are particularly useful for reusing the same markup between different views, layouts, and even other partials.
```ejs
<%- partial('./partials/navbar.ejs') %>
```
This should render the partial located at `views/partials/navbar.ejs`, which might look something like this:
```ejs
<%
/**
* views/partials/navbar.ejs
*
* > Note: This EJS comment won't show up in the ejs served to the browser.
* > So you can be as verbose as you like. Just be careful not to inadvertently
* > type a percent sign followed by a greater-than sign (it'll bust you out of
* > the EJS block).
*
*/%>
```
The target path that you pass in as the first argument to `partial()` should be relative from the view, layout, or partial where you call it. So if you are calling `partial()` from within a view file located at `views/pages/dashboard/user-profile.ejs`, and want to load `views/partials/widget.ejs` then you would use:
```ejs
<%- partial('../../partials/navbar.ejs') %>
```
### Partials and view locals
Partials automatically inherit the view locals that are available wherever they are used. For example, if you call `partial()` within a view where a variable named `currentUser` is available, then `currentUser` will also be available within the partial:
```ejs
<%
/**
* views/partials/navbar.ejs
*
* The navbar at the top of the page.
*
* @needs {Dictionary} currentUser
* @property {Boolean} isLoggedIn
* @property {String} username
*/%>
```
### Overriding locals in a partial
Automatic inheritance of view locals takes care of most use cases for partials, but sometimes you might want to pass in additional, dynamic data. For example, imagine your app has duplicate copies of the following code in a few different views:
```ejs
<%
// A list representing the currently-logged in user's inbox.
%>
<%
// Display each message, with a button to delete it.
_.each(messages, function (message) {
%>
` into a partial to avoid duplicating code. But if we do that, _we cannot rely on automatic inheritance_. Partials only inherit locals that are available to the view, partial, or layout where they're called as a whole, but this `
` relies on a variable called `message`, which comes from the call to [`_.each()`](https://lodash.com/docs/3.10.1#forEach).
Fortunately, Sails also allows you to pass in an optional dictionary (i.e. a plain JavaScript object) of overrides as the second argument to `partial()`:
```
<%- partial(relPathToPartial, optionalOverrides) %>
```
These overrides will be accessible in the partial as local variables, where they will take precedence over any automatically inherited locals with the same variable name.
Here's our example from above, refactored to take advantage of this:
```ejs
<%
// A list representing the currently-logged in user's inbox.
%>
<%
// Display each message, with a button to delete it.
_.each(messages, function (message) { %>
<%- partial ('../partials/inbox-message.ejs', { message: message }) %>
<% });
%>
```
And finally, here is our new partial representing an individual inbox message:
```ejs
/**
* views/partials/inbox-message.ejs
*
* An individual inbox message.
*
* @needs {Dictionary} message
* @property {Number} id
* @property {String} subject
*
*/%>
```
### Notes
> + Partials are rendered synchronously, so they will block Sails from serving more requests until they're done loading. It's something to keep in mind while developing your app, especially if you anticipate a large number of connections.
> + Built-in support for partials in Sails is only for the default view engine, `ejs`. If you decide to customize your Sails install and use a view engine other than `ejs`, then please be aware that support for partials (sometimes known as "blocks", "includes", etc.) may or may not be included, and that the usage will vary. Refer to the documentation for your view engine of choice for more information on its syntax and conventions.
================================================
FILE: docs/concepts/Views/ViewEngines.md
================================================
# View engines
The default view engine in Sails is [EJS](https://github.com/mde/ejs).
##### Swapping out the view engine
To use a different view engine, you should use npm to install it in your project, then in [`config/views.js`](https://sailsjs.com/documentation/anatomy/config/views.js) set `sails.config.views.extension` to your desired file extension and `sails.config.views.getRenderFn` to a function that returns your view engine's rendering function.
If your view engine is supported by [Consolidate](https://github.com/tj/consolidate.js/blob/master/Readme.md#api), you can use that in `getRenderFn` to easily access the rendering function. First, you'll need to use npm to install `consolidate` into your project, if it is not already present:
```bash
npm install consolidate --save
```
After the install has completed and you have installed your view engine package, you can then set the view configuration. For example, to use [Swig](https://github.com/paularmstrong/swig) templates you would `npm install swig --save` and then add the following into [`config/views.js`](https://sailsjs.com/documentation/anatomy/config/views.js):
```javascript
extension: 'swig',
getRenderFn: ()=>{
// Import `consolidate`.
var cons = require('consolidate');
// Return the rendering function for Swig.
return cons.swig;
}
```
The `getRenderFn` allows you to configure your view engine before plugging it into Sails:
```javascript
extension: 'swig',
getRenderFn: ()=>{
// Import `consolidate`.
var cons = require('consolidate');
// Import `swig`.
var swig = require('swig');
// Configure `swig`.
swig.setDefaults({tagControls: ['{?', '?}']});
// Set the module that Consolidate uses for Swig.
cons.requires.swig = swig;
// Return the rendering function for Swig.
return cons.swig;
}
```
================================================
FILE: docs/concepts/Views/Views.md
================================================
# Views
### Overview
In Sails, views are markup templates that are compiled _on the server_ into HTML pages. In most cases, views are used as the response to an incoming HTTP request, e.g. to serve your home page.
> Much more rarely, you can also compile a view directly into an HTML string for use in your backend code (see [`sails.renderView()`](https://github.com/balderdashy/sails/blob/master/docs/PAGE_NEEDED.md)). For instance, you might use this approach to send HTML emails, or to build big XML strings for use with a legacy API.
##### Creating a view
By default, Sails is configured to use EJS ([Embedded Javascript](http://ejs.co/)) as its view engine. The syntax for EJS is highly conventional; if you've worked with php, asp, erb, gsp, jsp, etc., you'll immediately know what you're doing.
If you prefer to use a different view engine, there are a multitude of options. Sails supports all of the view engines compatible with [Express](http://expressjs.com/en/guide/using-template-engines.html) via [Consolidate](https://github.com/visionmedia/consolidate.js).
Views are defined in your app's [`views/`](https://sailsjs.com/documentation/anatomy/views) folder by default, but like all of the default paths in Sails, they are [configurable](https://sailsjs.com/documentation/reference/configuration/sails-config-views). If you don't need to serve dynamic HTML pages at all (say, if you're building an API for a mobile app), you can remove the directory from your app.
##### Compiling a view
Anywhere you can access the `res` object (e.g. a controller action, custom response, or policy), you can use [`res.view`](https://sailsjs.com/documentation/reference/response-res/res-view) to compile one of your views, then send the resulting HTML down to the user.
You can also hook up a view directly to a route in your `routes.js` file. Just indicate the relative path to the view from your app's `views/` directory. For example:
```javascript
{
'get /': {
view: 'pages/homepage'
},
'get /signup': {
view: 'pages/signup/basic-info'
},
'get /signup/password': {
view: 'pages/signup/choose-password'
},
// and so on.
}
```
##### What about single-page apps?
If you are building a web application for the browser, part (or all) of your navigation may take place on the client; i.e. instead of the browser fetching a new HTML page each time the user navigates around, the client-side code preloads some markup templates which are then rendered in the user's browser without needing to hit the server again directly.
In this case, you have a couple of options for bootstrapping the single-page app:
+ Use a single view, e.g. `views/publicSite.ejs`. The advantage of this option is that you can use the view engine in Sails to pass data from the server directly into the HTML that will be rendered on the client. This is an easy way to get stuff like user data to your client-side JavaScript, without having to send AJAX/WebSocket requests from the client.
+ Use a single HTML page in your assets folder , e.g. `assets/index.html`. Although you can't pass server-side data directly to the client this way, the advantage of this approach is that it allows you to further decouple the client and server-side parts of your application.
Note that anything in your assets folder can be moved to a static CDN (like Cloudfront or CloudFlare), allowing you to take advantage of that provider's geographically-distributed data centers to get your content closer to your users.
================================================
FILE: docs/concepts/concepts.md
================================================
# Sails.js Documentation > Core Concepts
> The contents of this file are overridden automatically during compilation (please do not edit manually!)
================================================
FILE: docs/concepts/extending-sails/Adapters/Adapters.md
================================================
# Adapters
### What is an adapter?
In Sails and Waterline, database adapters (often simply called "adapters", for short) allow the models in your Sails app to communicate with your database(s). In other words, when your code in a controller action or helper calls a model method like `User.find()`, what happens next is determined by the [configured adapter](https://sailsjs.com/documentation/reference/configuration/sails-config-datastores).
An adapter is defined as a dictionary (aka JavaScript object, like `{}`) with methods like `find`, `create`, etc. Based on which methods it implements, and the completeness with which they are implemented, adapters are said to implement one or more **interface layers**. Each interface layer implies a contract to implement certain functionality. This allows Sails and Waterline to guarantee conventional usage patterns across multiple models, developers, apps, and even companies, making app code more maintainable, efficient, and reliable.
> In previous versions of Sails, adapters were sometimes used for other purposes, like communicating with certain kinds of RESTful web APIs, internal/proprietary web services, or even hardware. But _truly_ RESTful APIs are very rare, and so, in most cases, writing a database adapter to integrate with a _non-database API_ can be limiting. Luckily, there is now a [more straightforward way](https://sailsjs.com/documentation/concepts/helpers) to build these types of integrations.
### What kind of things can I do in an adapter?
Adapters are mainly focused on providing model-contextualized CRUD methods. CRUD stands for create, read, update, and delete. In Sails/Waterline, we call these methods `create()`, `find()`, `update()`, and `destroy()`.
For example, a `MySQLAdapter` implements a `create()` method which, internally, calls out to a MySQL database using the specified table name and connection information and runs an `INSERT ...` SQL query.
### Next steps
Read about [available adapters](https://sailsjs.com/documentation/concepts/extending-sails/adapters/available-adapters), or how to make your own [custom adapter](https://sailsjs.com/documentation/concepts/extending-sails/adapters/custom-adapters).
================================================
FILE: docs/concepts/extending-sails/Adapters/adapterList.md
================================================
# Available database adapters
This page is meant to be an up-to-date, comprehensive list of all of the core adapters available for the Sails.js framework, and a reference of a few of the most robust community adapters out there.
All supported adapters can be configured in roughly the same way: by passing in a Sails/Waterline adapter (`adapter`), as well as a connection URL (`url`). For more information on configuring datastores, see [sails.config.datastores](https://sailsjs.com/documentation/reference/configuration/sails-config-datastores).
> Having trouble connecting? Be sure to check your connection URL for typos. If that doesn't work, review the documentation for your database provider, or [get help](https://sailsjs.com/support).
### Officially-supported database adapters
The following core adapters are maintained, tested, and used by the Sails.js core team.
> Want to help out with a core adapter? Get started by reading [the Sails project contribution guide](https://sailsjs.com/contributing).
| Database technology | Adapter | Connection URL structure | For production? |
|:------------------------|:---------------------------------------------------------------|:----------------------------------------------|:--------------------|
| MySQL | [require('sails-mysql')](http://npmjs.com/package/sails-mysql) | `mysql://user:password@host:port/database` | Yes
| PostgreSQL | [require('sails-postgresql')](http://npmjs.com/package/sails-postgresql) | `postgresql://user:password@host:port/database` | Yes
| MongoDB | [require('sails-mongo')](http://npmjs.com/package/sails-mongo) | `mongodb://user:password@host:port/database` | Yes
| Local disk / memory | _(built-in, see [sails-disk](http://npmjs.com/package/sails-disk))_ | _n/a_ | **No!**
### sails-mysql
[MySQL](http://en.wikipedia.org/wiki/MySQL) is the world's most popular relational database.
[](http://npmjs.com/package/sails-mysql) [](http://npmjs.com/package/sails-mysql)
```bash
npm install sails-mysql --save
```
```javascript
adapter: 'sails-mysql',
url: 'mysql://user:password@host:port/database',
```
> + The default port for MySQL is `3306`.
> + If you plan on saving special characters—like emojis—in your data, you may need to set the [`charset`](https://dev.mysql.com/doc/refman/5.7/en/charset-charsets.html) configuration option for your datastore. To allow emojis, use `charset: 'utf8mb4'`. You may use the [`columnType` setting](https://sailsjs.com/documentation/concepts/models-and-orm/attributes#?columntype) in a model attribute to set the character set.
> + For relational database servers like MySQL and PostgreSQL, you may have to create a "database" first using a free tool like [SequelPro](https://www.sequelpro.com/) or in the MySQL REPL on the command-line (if you're an experience SQL user). It's customary to make a database specifically for your app to use.
> + The sails-mysql adapter is also 100% compatible with [Amazon Aurora](https://aws.amazon.com/rds/aurora/) databases.
##### Handshake inactivity timeout errors
If you find yourself encountering a "Handshake inactivity timeout" error when your Sails app interacts with MySQL, you can increase the timeout using the `connectTimeout` option. This is [usually only necessary](https://github.com/mysqljs/mysql/issues/1434) when queries are running side-by-side with computationally expensive operations (for example, compiling client-side typescript files or running webpack during development).
For example, you might extend the timeout to 20 seconds:
```javascript
adapter: 'sails-mysql',
url: 'mysql://user:password@host:port/database',
connectTimeout: 20000
```
### sails-postgresql
[PostgreSQL](http://en.wikipedia.org/wiki/postgresql) is a modern relational database with powerful features.
[](http://npmjs.com/package/sails-postgresql) [](http://npmjs.com/package/sails-postgresql)
```bash
npm install sails-postgresql --save
```
```javascript
adapter: 'sails-postgresql',
url: 'postgresql://user:password@host:port/database',
```
> + The default port for PostgreSQL is `5432`.
> + In addition to `adapter` and `url`, you might also need to set `ssl: true`. This depends on where your PostgreSQL database server is hosted. For example, `ssl: true` is required when connecting to Heroku's hosted PostgreSQL service.
> + Note that in `pg` version 8.0, the syntax was updated to `ssl: { rejectUnauthorized: false }`.
> + Compatible with most versions of Postgres. See [this issue](https://github.com/balderdashy/sails/issues/6957) to learn more about compatability with Postgres >12
### sails-mongo
[MongoDB](http://en.wikipedia.org/wiki/MongoDB) is the leading NoSQL database.
[](http://npmjs.com/package/sails-mongo) [](http://npmjs.com/package/sails-mongo)
```bash
npm install sails-mongo --save
```
```javascript
adapter: 'sails-mongo',
url: 'mongodb://user:password@host:port/database',
```
> + The default port for MongoDB is `27017`.
> + If your Mongo deployment keeps track of its internal credentials in a separate database, then you may need to name that database by tacking on [`?authSource=theotherdb`](https://stackoverflow.com/a/40608735/486547) to the end of the connection URL.
> + Other [Mongo configuration settings](https://github.com/balderdashy/sails-mongo/blob/master/lib/private/constants/config-whitelist.constant.js) provided via querystring in the connection URL are passed through to the underlying Mongo driver.
### sails-disk
Write to your computer's hard disk, or a mounted network drive. Not suitable for at-scale production deployments, but great for a small project, and essential for developing in environments where you may not always have a database set up. This adapter is bundled with Sails and works out of the box with zero configuration.
You can also operate `sails-disk` in _memory-only mode_. See the settings table below for details.
[](http://npmjs.com/package/sails-disk) [](http://npmjs.com/package/sails-disk)
_Available out of the box in every Sails app._
_Configured as the default database, by default._
##### Optional datastore settings for `sails-disk`
| Setting | Description | Type | Default |
|:--------|:------------|:------|:--------|
| `dir` | The directory to place database files in. The adapter creates one file per model. | ((string)) | `.tmp/localDiskDb` |
| `inMemoryOnly` | If `true`, no database files will be written to disk. Instead, all data will be stored in memory (and will be lost when the app stops running). | ((boolean)) | `false` |
> + You can configure the default `sails-disk` adapter by adding settings to the `default` datastore in `config/datastores.js`.
### Community-supported database adapters
Is your database not supported by one of the core adapters? Good news! There are many different community database adapters for Sails.js and Waterline [available on NPM](https://www.npmjs.com/search?q=sails+adapter).
Here are a few highlights:
| Database technology | Adapter | Maintainer | Interfaces implemented | Stable release |
|:--------------------------------|:-----------------------|:-----------|:-----------------------|-----------------------|
| **Redis** | [sails-redis](https://npmjs.com/package/sails-redis) | [Ryan Clough / Solnet Solutions](https://github.com/Ryanc1256) | Semantic, Queryable | [](http://npmjs.com/package/sails-redis) |
| **MS SQL Server** | [sails-MSSQLserver](https://github.com/misterGF/sails-mssqlserver) | [misterGF](https://github.com/misterGF) | Semantic, Queryable | [](http://npmjs.com/package/sails-sqlserver)
| **OrientDB** | [sails-orientDB](https://github.com/appscot/sails-orientdb) | [appscot](https://github.com/appscot) | Semantic, Queryable, Associations, Migratable | [](http://npmjs.com/package/sails-orientdb)
| **Oracle** | [sails-oracleDB](https://npmjs.com/package/sails-oracledb) | [atiertant](https://github.com/atiertant) | Semantic, Queryable | [](http://npmjs.com/package/sails-oracledb) |
| **Oracle (AnyPresence)** | [waterline-oracle-adapter](https://github.com/AnyPresence/waterline-oracle-adapter) | [AnyPresence](https://github.com/AnyPresence) | Semantic, Queryable | [](https://github.com/AnyPresence/waterline-oracle-adapter)
| **Oracle (stored procedures)** | [sails-oracle-SP](https://npmjs.com/sails-oracle-sp) | [Buto](http://github.com/buto) and [nethoncho](http://github.com/nethoncho) | Semantic, Queryable | [](http://npmjs.com/package/sails-oracle-sp)
| **SAP HANA DB** | [sails-HANA](https://npmjs.com/sails-hana) | [Enrico Battistella](https://github.com/battistaar) | Semantic, Queryable | [](http://npmjs.com/package/sails-hana)
| **SAP HANA (AnyPresence)** | [waterline-SAP-HANA-adapter](https://github.com/AnyPresence/waterline-sap-hana-adapter) | [AnyPresence](https://github.com/AnyPresence) | Semantic, Queryable | [](https://github.com/AnyPresence/waterline-sap-hana-adapter)
| **IBM DB2** | [sails-DB2](https://npmjs.com/sails-db2) | [ibuildings Italia](https://github.com/IbuildingsItaly) & [Vincenzo Ferrari](https://github.com/wilk) | Semantic, Queryable | [](http://npmjs.com/package/sails-db2)
| **ServiceNow SOAP** | [waterline-ServiceNow-SOAP](https://npmjs.com/waterline-servicenow-soap) | [Sungard Availability Services](http://www.sungardas.com/) | Semantic, Queryable | [](http://npmjs.com/package/waterline-servicenow-soap)
| **Cassandra** | [sails-cassandra](https://github.com/dtoubelis/sails-cassandra) | [dtoubelis](https://github.com/dtoubelis) | Semantic, Migratable, Iterable | [](http://npmjs.com/package/sails-cassandra)
| **Solr** | [sails-solr](https://github.com/sajov/sails-solr) | [sajov](https://github.com/sajov) | Semantic, Migratable, Queryable | [](http://npmjs.com/package/sails-solr)
| **FileMaker Database** | [sails-FileMaker](https://github.com/geistinteractive/sails-filemaker) | [Geist Interactive](https://www.geistinteractive.com/) | Semantic | [](http://npmjs.com/package/sails-filemaker)
| **Apache Derby** | [sails-derby](https://github.com/dash-/node-sails-derby) | [dash-](https://github.com/dash-) | Semantic, Queryable, Associations, SQL | [](http://npmjs.com/package/sails-derby)
| **REST API (Generic)** | [sails-REST](https://github.com/zohararad/sails-rest) | [zohararad](https://github.com/zohararad) | Semantic | [](http://npmjs.com/package/sails-rest)
##### Add your custom adapter to this list
If you see out of date information on this page, or if you want to add an adapter you made, please submit a pull request to this file updating the table of community adapters above.
Note that, to be listed on this page, an adapter must:
1. Be free and open source (_libre_ and _gratis_), preferably under the MIT license.
2. Pass all of the Waterline adapter tests for the interface layers declared in its package.json file.
3. Support configuration via a connection URL, as `url` (if applicable).
If you find that any of these conventions are not true for any of the community adapters above (i.e. for latest stable release published on NPM, not for the code on GitHub), then please reach out to the maintainer of the adapter. If you can't reach them or need further assistance, then please [get in touch](https://sailsjs.com/contact) with a member of the Sails core team.
================================================
FILE: docs/concepts/extending-sails/Adapters/customAdapters.md
================================================
# Custom adapters
Sails makes it fairly easy to write your own database adapter. Custom adapters can be built directly in your app (`api/adapters/`) or published as NPM packages. Check out [Intro to Custom Adapters](https://github.com/balderdashy/sails/blob/master/docs/contributing/intro-to-custom-adapters.md), the [Adapter Interface Reference](https://github.com/balderdashy/sails/blob/master/docs/contributing/adapter-specification.md), and [sails-adapter-boilerplate](https://github.com/balderdashy/sails-adapter-boilerplate) for more information about creating your own adapter.
### Where does my adapter go?
There are two different places you can build an adapter:
##### In your app's `api/adapters/` folder
If an adapter is only going to be used in one app (e.g. a short-term fork of an existing adapter) you can put it in `api/adapters/`. This is what you get out of the box when you run `sails generate adapter`. In this case, the name of the adapter is determined by the name of the folder inside `api/adapters/` (by convention, the entry point for your adapter should be `index.js`).
##### In a separate repo
Go with this option if you plan to share your adapter between multiple Sails apps, whether that's within your organization or as an open-source package for other members of the Sails/Node.js community at large. To use an externalized adapter like this, you'll need to do `npm install your-adapter-package-name` or `npm link your-adapter-package-name`.
> Before you start on an open-source adapter, we recommend you search GitHub for `sails-databasename` and `waterline-databasename` to check if a project already exists. If it does, it's generally a good idea to approach the author of an existing adapter and offer to contribute instead of starting a new project. Most developers will welcome your help, and the combined efforts will likely result in a better quality adapter. If one doesn't exist, we recommend you create a new project and name it following the convention: `sails-databasename`.
### What goes in a custom adapter?
In Sails, database adapters expose **interfaces**, which imply a contract to implement certain functionality. This allows us to guarantee conventional usage patterns across multiple models, developers, apps, and even companies, making app code more maintainable, efficient, and reliable. Adapters are primarily useful for integrating with databases, but they can also be used to support any open API or internal/proprietary web service that is _purely_ RESTful.
> Not everything fits perfectly into a RESTful/CRUD mold. Sometimes the service you're integrating with has an RPC-style interface with one-off methods. For example, consider an API request to send an email, or to read a remote sensor on a piece of connected hardware. For that, you'll want to write or extend a machinepack. [Learn more about machinepacks here](http://node-machine.org).
### What kind of things can I do in an adapter?
Adapters are mainly focused on providing model-contextualized CRUD methods. CRUD stands for create, read, update, and delete. In Sails/Waterline, we call these methods `create()`, `find()`, `update()`, and `destroy()`.
For example, a `MySQLAdapter` implements a `create()` method which, internally, calls out to a MySQL database using the specified table name and connection information and runs an `INSERT ...` SQL query.
In practice, your adapter can really do anything it likes—any method you write will be exposed on the raw datastore objects and any models which use them.
### Building a custom adapter
Check out the [Sails docs](https://sailsjs.com/documentation), or see [`config/datastores.js`](https://sailsjs.com/anatomy/config/datastores.js) in a new Sails project for information on setting up this adapter in a Sails app.
#### Running the tests
Configure the interfaces you plan to support (and the targeted version of Sails) in the adapter's `package.json` file:
```javascript
{
//...
"sails": {
"adapter": {
"sailsVersion": "^1.0.0",
"implements": [
"semantic",
"queryable"
]
}
}
}
```
In your adapter's directory, run:
```sh
$ npm test
```
#### Publish your adapter
> You're welcome to write proprietary adapters and use them any way you wish—
> these instructions are for releasing an open-source adapter.
1. Create a [new public repo](https://github.com/new) and add it as a remote (`git remote add origin git@github.com:yourusername/sails-youradaptername.git).
2. Make sure you attribute yourself as the author and set the license in the package.json to "MIT".
3. Run the tests one last time.
4. Do a [pull request to the docs](https://github.com/balderdashy/sails/edit/master/docs/concepts/extending-sails/Adapters/adapterList.md), adding your adapter's repo.
5. We'll update the documentation with information about your new adapter.
6. Let the people of the world adore you with lavish praise.
7. Run `npm version patch`.
8. Run `git push && git push --tags`.
9. Run `npm publish`.
### Why would I need a custom adapter?
When building a Sails app, the sending or receiving of any asynchronous communication with another piece of hardware can _technically_ be normalized into an adapter (viz. API integrations).
> **From Wikipedia:**
> *http://en.wikipedia.org/wiki/Create,_read,_update_and_delete*
> Although a relational database provides a common persistence layer in software applications, numerous other persistence layers exist. CRUD functionality can be implemented with an object database, an XML database, flat text files, custom file formats, tape, or card, for example.
In other words, Waterline is not _necessarily_ just an ORM for your database. It is a purpose-agnostic open standard and toolset for integrating with all kinds of RESTful services, datasources, and devices—whether it's LDAP, Neo4J, or [a lamp](https://www.youtube.com/watch?v=OmcQZD_LIAE).
> **But remember:** only use Waterline adapters for communicating with databases and APIs that support a "create", "read", "update", and "destroy" interface. Not everything fits into that mold, and there are [better, more generic ways](http://node-machine.org) to address those other use cases.
### Why should I build a custom adapter?
To recap, writing your API integrations as adapters is **easier**, takes **less time**, and **absorbs a considerable amount of risk**, since you get the advantage of a **standardized set of conventions**, a **documented API**, and a **built-in community** of other developers who have gone through the same process. Best of all, you (and your team) can **reuse the adapter** in other projects, **speeding up development** and **saving time and money**.
Finally, if you choose to release your adapter as open source, you provide a tremendous boon to our little framework and our budding Sails.js ecosystem. Even if it's not via Sails, I encourage you to give back to the OSS community, even if you've never forked a repo before—don't be intimidated, it's not that bad!
The more high-quality adapters the Sails community collectively releases as open source, the less repetitive work we all have to do when we integrate with various databases and services. Our vision is to make building server-side apps more fun and less repetitive for everyone, and that happens one community adapter (or machinepack/driver/generator/view engine/etc.) at a time.
### What is an adapter interface?
The functionality of database adapters is as varied as the services they connect. That said, there is a standard library of methods, and a support matrix you should be aware of. Adapters may implement some, all, or none of the interfaces below, but rest assured that **if an adapter implements one method in an interface, it should implement *all* of them**. This is not always the case due to limitations and/or incomplete implementations, but at the very least, a descriptive error message should be used to keep developers informed of what's supported and what's not.
> For more information, check out the Sails docs, and specifically the [adapter interface reference](https://github.com/balderdashy/sails/blob/master/docs/contributing/adapter-specification.md).
### Are there examples I can look at?
If you're looking for some inspiration, a good place to start is with the core adapters. Take a look at **[MySQL](https://github.com/balderdashy/sails-mysql)**, **[PostgreSQL](https://github.com/balderdashy/sails-postgresql)**, **[MongoDB](https://github.com/balderdashy/sails-mongo)**, **[Redis](https://github.com/balderdashy/sails-redis)**, or local [disk](https://github.com/balderdashy/sails-disk).
### Where do I get help?
An active community of Sails and Waterline users exists on GitHub, Stack Overflow, Google groups, IRC, Gitter, and more. See the [Support page](https://sailsjs.com/support) for a list of recommendations.
> If you have an unanswered question that isn't covered here, and that you feel would add value for the community, please feel free to send a PR adding it to this section of the docs.
================================================
FILE: docs/concepts/extending-sails/Custom Responses/AddingCustomResponse.md
================================================
# Adding a custom response
To add your own custom response method, simply add a file to `/api/responses` with the same name as the method you would like to create. The file should export a function, which can take any parameters you like.
```javascript
/**
* api/responses/myResponse.js
*
* This will be available in controllers as res.myResponse('foo');
*/
module.exports = function(message) {
var req = this.req;
var res = this.res;
var viewFilePath = 'mySpecialView';
var statusCode = 200;
var result = {
status: statusCode
};
// Optional message
if (message) {
result.message = message;
}
// If the user-agent wants a JSON response, send json
if (req.wantsJSON) {
return res.json(result, result.status);
}
// Set status code and view locals
res.status(result.status);
for (var key in result) {
res.locals[key] = result[key];
}
// And render view
res.render(viewFilePath, result, function(err) {
// If the view doesn't exist, or an error occured, send json
if (err) {
return res.json(result, result.status);
}
// Otherwise, serve the `views/mySpecialView.*` page
res.render(viewFilePath);
});
}
```
================================================
FILE: docs/concepts/extending-sails/Custom Responses/Custom Responses.md
================================================
# Custom responses
### Overview
Sails apps come bundled with several pre-configured _responses_ that can be called from [action code](https://sailsjs.com/documentation/concepts/actions-and-controllers). These default responses can handle situations like “resource not found” (the [`notFound` response](https://sailsjs.com/documentation/reference/response-res/res-not-found)) and “internal server error” (the [`serverError` response](https://sailsjs.com/documentation/reference/response-res/res-server-error)). If your app needs to modify the way that the default responses work, or create new responses altogether, you can do so by adding files to the `api/responses` folder.
> Note: `api/responses` is not generated by default in new Sails apps, so you’ll have to add it yourself if you want to add / customize responses.
### Using responses
As a quick example, consider the following action:
```javascript
getProfile: function(req, res) {
// Look up the currently logged-in user's record from the database.
User.findOne({ id: req.session.userId }).exec(function(err, user) {
if (err) {
res.status(500);
return res.view('500', {data: err});
}
return res.json(user);
});
}
```
This code handles a database error by sending a 500 error status and sending the error data to a view to be displayed. However, this code has several drawbacks, primarily:
* The response isn't *content-negotiated*: if the client is expecting a JSON response, they're out of luck
* The response *reveals too much* about the error: in production, it'd be best to just log the error to the terminal
* It isn't *normalized*: even if we dealt with the other bullet points above, the code is specific to this action, and we'd have to work hard to keep the exact same format for error handling everywhere
* It isn't *abstracted*: if we wanted to use a similar approach elsewhere, we'd have to copy / paste the code
Now, consider this replacement:
```javascript
getProfile: function(req, res) {
// Look up the currently logged-in user's record from the database.
User.findOne({ id: req.session.userId }).exec(function(err, user) {
if (err) { return res.serverError(err); }
return res.json(user);
});
}
```
This approach has many advantages:
- More concise
- Error payloads are normalized
- Production vs. development logging is taken into account
- Error codes are consistent
- Content negotiation (JSON vs HTML) is taken care of
- API tweaks can be done in one quick edit to the appropriate generic response file
### Response methods and files
Any `.js` file saved in the `api/responses/` folder can be executed by calling `res.thatFileName()`. For example, `api/responses/insufficientFunds.js` can be executed with a call to `res.insufficientFunds()`.
##### Accessing `req`, `res`, and `sails`
The request and response objects are available inside of a custom response as `this.req` and `this.res`. This allows the actual response function to take arbitrary parameters. For example:
```javascript
return res.insufficientFunds(err, { happenedDuring: 'signup' });
```
And the implementation of the custom response might look something like this:
```javascript
module.exports = function insufficientFunds(err, extraInfo){
var req = this.req;
var res = this.res;
var sails = req._sails;
var newError = new Error('Insufficient funds');
newError.raw = err;
_.extend(newError, extraInfo);
sails.log.verbose('Sent "Insufficient funds" response.');
return res.badRequest(newError);
}
```
### Built-in responses
All Sails apps have several pre-configured responses like [`res.serverError()`](https://sailsjs.com/documentation/reference/response-res/res-server-error) and [`res.notFound()`](https://sailsjs.com/documentation/reference/response-res/res-not-found) that can be used even if they don’t have corresponding files in `api/responses/`.
Any of the default responses may be overridden by adding a file with the same name to `api/responses/` in your app (e.g. `api/responses/serverError.js`).
> You can use the [Sails command-line tool](https://sailsjs.com/documentation/reference/command-line-interface/sails-generate) as a shortcut for doing this.
>
> For example:
>
>```bash
>sails generate response serverError
>```
>
================================================
FILE: docs/concepts/extending-sails/Generators/Generators.md
================================================
# Generators
A big part of Sails, like any framework, is automating repetitive tasks. **Generators** are no exception: they're what power the Sails command-line interface any time it generates new files for your Sails projects. In fact, you or someone on your team probably used a _generator_ to create your latest Sails project.
When you type
```sh
sails new my-project
```
sails uses its built-in "new" generator to prompt you for your app template of choice, then spits out the initial folder structure for a Sails app:
```javascript
my-project
├── api/
│ ├─ controllers/
│ ├─ helpers/
│ └─ models/
├── assets/
│ └─ …
├── config/
│ └─ …
├── views/
│ └─ …
├── .gitignore
…
├── package.json
└── README.md
```
This conventional folder structure is one of the big advantages of using a framework. But it's usually also one of the trade-offs (what if your team or organization has made firm commitments to a different set of conventions?).
Fortunately since Sails v0.11, generators are extensible and easy to check in to a project repository or publish on NPM for re-use.
Sails' generators allow you to completely customize what happens when you run `sails new` and `sails generate` from the command-line. By augmenting new apps and newly-generated modules, custom generators can be used to do all sorts of cool things:
- to standardize conventions and boilerplate logic for all new apps across your organization
- to swap out rules in the default .eslintrc file
- to customize how the asset pipeline works in new projects
- to use a different asset pipeline altogether (like [Gulp](http://gulpjs.com/) or [webpack](https://webpack.github.io/))
- to use a [different default view engine](https://sailsjs.com/documentation/concepts/views/view-engines)
- to automate custom deployments (e.g. white label apps with one server per customer)
- to include a different set of dependencies in the package.json file
- to generate files in a transpiled language like TypeScript or CoffeeScript
- to start off with all documentation and comments in a language other than English
- to include ASCII pictures of cats at the top of every code file (or license headers, whatever)
- to standardize around a particular version of a front-end dependency (for example, `sails generate jquery`)
- to include a particular front-end framework in your new Sails apps
- to make it easy to include new Vue / React components or Angular modules from your favorite templates (for example, `sails generate component` or `sails generate ng-module`)
> If you are interested in making custom generators, the best place to start is by checking out the [introduction to custom generators](https://sailsjs.com/documentation/concepts/extending-sails/generators/custom-generators). You also might check out [open-source generators from the community](https://sailsjs.com/documentation/concepts/extending-sails/generators/available-generators), in case something already out there will save you some time.
================================================
FILE: docs/concepts/extending-sails/Generators/customGenerators.md
================================================
# Custom generators
### Overview
Custom [generators](https://sailsjs.com/documentation/concepts/extending-sails/generators) are a type of plugin for the Sails command line. Through templates, they control which files get generated in your Sails projects when you run `sails new` or `sails generate`, and also what those files look like.
### Creating a generator
To make this easier to play with, let's first make a Sails project. If you haven't already created one, go to your terminal and type:
```sh
sails new my-project
```
Then `cd` into `my-project` and ask Sails to spit out the template for a new generator:
```sh
sails generate generator awesome
```
### Configuring a generator
To enable the generator you need to tell Sails about it via your test project's [`.sailsrc` file](https://sailsjs.com/documentation/concepts/configuration/using-sailsrc-files).
If we were using an existing generator, we could just install it from NPM, then specify the name of the package in `.sailsrc`. But since we're developing this generator locally, we'll just connect it to the folder directly:
```javascript
{
"generators": {
"modules": {
"awesome": "./my-project/awesome"
}
}
}
```
> **Note:** For now, we'll stick with "awesome", but you can mount the generator under any name you want. Whatever you choose for the name of the key in the `.sailsrc` file will be the name you'll use to run this generator from the terminal (e.g. `sails generate awesome`).
### Running a custom generator
To run your generator, just tack its name on to `sails generate`, followed by any desired arguments or command-line options. For example:
```js
sails generate awesome
```
### Publishing to NPM
If your generator is useful across different projects, you might consider publishing it as an NPM package (note that this doesn't mean that your generator must be open-source: NPM also supports [private packages](https://docs.npmjs.com/private-modules/intro).
First, pop open the `package.json` file and verify the package name (e.g. "@my-npm-name/sails-generate-awesome"), author ("My Name"), license, and other information are correct. If you're unsure, a good open source license to use is "MIT". If you're publishing a private generator and want it to remain proprietary to your organization, use "UNLICENSED".
> **Note:** If you don't already have an NPM account, go to [npmjs.com](https://www.npmjs.com/) and create one. Then use `npm login` to get set up.
When you're ready to pull the trigger and publish your generator on NPM, cd into the generator's folder in the terminal and type:
```sh
npm publish
```
### Installing a generator
To take your newly-published generator for a spin, cd back into your example Sails project (`my-project`), delete the inline generator, and run:
```js
npm install @my-npm-name/sails-generate-awesome
```
then change the `.sailsrc` in your example Sails project (`my-project/.sailsrc`):
```javascript
{
"generators": {
"modules": {
"awesome": "@my-npm-name/sails-generate-awesome"
}
}
}
```
And, last but not least:
```sh
sails generate awesome
```
================================================
FILE: docs/concepts/extending-sails/Generators/generatorList.md
================================================
# Available generators
The Sails framework's built-in [generators](https://sailsjs.com/documentation/concepts/extending-sails/generators) can be customized using command-line options and overridden by [mounting custom generators in the `.sailsrc` file](https://sailsjs.com/documentation/concepts/extending-sails/generators/custom-generators). Other generators that add completely new sub-commands to [`sails generate`](https://sailsjs.com/documentation/reference/command-line-interface/sails-generate) can be mounted in the same way.
### Core generators
Certain generators are built in to Sails by default.
| Commands that generate a new Sails app
|:-----------------------------------|
| sails new _name_
| sails new _name_ --fast
| sails new _name_ --caviar
| sails new _name_ --without=grunt
| sails new _name_ --without=lodash,async,grunt,blueprints,i18n
| sails new _name_ --no-frontend --without=sockets,lodash
| sails new _name_ --minimal
| Generators for spitting out new files in an existing Sails app
|:-----------------------------------|
| sails generate model _identity_
| sails generate action _name_
| sails generate action view-_name_
| sails generate action _some/path/_view-_name_
| sails generate page _name_
| sails generate helper _name_
| sails generate helper view-_name_
| sails generate script _name_
| sails generate script get-_name_
| sails generate controller _name_
| sails generate api _name_
| sails generate hook _name_
| sails generate response _name_
| Commands for generating plugins
|:-----------------------------------|
| sails generate generator _name_
| sails generate adapter _name_
| Commands for (re)generating client-side dependencies
|:-----------------------------------|
| sails generate sails.io.js
| sails generate parasails
| Utils for building your own 3rd party packages
|:-----------------------------------|
| sails generate etc
_Since Sails v1.0, built-in generators are now [bundled](https://npmjs.com/package/sails-generate) in Sails core, rather than in separate NPM packages. All generators can still be overridden the same way. For advice setting up overrides for core generators in your environment, [click here](https://sailsjs.com/support)._
### Community generators
There are over 100 community-supported generators [available on NPM](https://www.npmjs.com/search?q=sails+generate):
+ [sails-inverse-model](https://github.com/juliandavidmr/sails-inverse-model)
+ [sails-generate-new-gulp](https://github.com/Karnith/sails-generate-new-gulp)
+ [sails-generate-archive](https://github.com/jaumard/sails-generate-archive)
+ [sails-generate-scaffold](https://github.com/irlnathan/sails-generate-scaffold)
+ [sails-generate-directive](https://github.com/balderdashy/sails-generate-directive)
+ [sails-generate-bower](https://github.com/smies/sails-generate-bower)
+ [sails-generate-angular-gulp](https://github.com/Karnith/sails-generate-angular-gulp)
+ [sails-generate-ember-blueprints](https://github.com/mphasize/sails-generate-ember-blueprints)
+ And [many more](https://www.npmjs.com/search?q=sails+generate)...
================================================
FILE: docs/concepts/extending-sails/Hooks/Hooks.md
================================================
# Hooks
### What is a hook?
A hook is a Node module that adds functionality to the Sails core. The [hook specification](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification) defines the requirements a module must meet for Sails to be able to import its code and make the new functionality available. Because they can be saved separately from the core, hooks allow Sails code to be shared between apps and developers without having to modify the framework.
### Types of hooks
There are three types of hooks available in Sails:
1. **Core hooks** are built in and provide many of the common features essential to a Sails app, such as request handling, blueprint route creation, and database integration via [Waterline](https://sailsjs.com/documentation/concepts/models-and-orm). Core hooks are bundled with the Sails core and are thus available to every app. You will rarely need to call core hook methods in your code.
2. **App-level hooks** live in the `api/hooks/` folder of a Sails app. Project hooks let you take advantage of the features of the hook system for code that doesn’t need to be shared between apps.
3. **Installable hooks** are plugins, installed into an app’s `node_modules` folder using `npm install`. Installable hooks allow developers in the Sails community to create “plug-in”-like modules for use in Sails apps.
### Read more
* [Using hooks in your app](https://sailsjs.com/documentation/concepts/extending-sails/Hooks/using-hooks)
* [The hook specification](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification)
* [Creating a project hook](https://sailsjs.com/documentation/concepts/extending-sails/hooks/project-hooks)
* [Creating an installable hook](https://sailsjs.com/documentation/concepts/extending-sails/Hooks/installable-hooks)
================================================
FILE: docs/concepts/extending-sails/Hooks/available-hooks.md
================================================
# Available hooks
This page is meant to be an up to date, comprehensive list of all of the core hooks in the Sails.js framework, and a reference of a few of the most popular community-made hooks.
### Core hooks
The following hooks are maintained by the Sails.js core team and are included in your Sails app by default. You can override or disable them using your [sailsrc file](https://sailsjs.com/documentation/concepts/configuration/using-sailsrc-files) or [environment variables](https://sailsjs.com/documentation/concepts/configuration#?setting-sailsconfig-values-directly-using-environment-variables).
| Hook | Package | Latest stable release | Purpose |
|:---------------|---------------|-------------------------|:------------|
| `grunt` | [sails-hook-grunt](https://npmjs.com/package/sails-hook-grunt) | [](http://badge.fury.io/js/sails-hook-grunt) | Governs the built-in asset pipeline in Sails.
| `orm` | [sails-hook-orm](https://npmjs.com/package/sails-hook-orm) | [](http://badge.fury.io/js/sails-hook-orm) | Implements support for Waterline ORM in Sails.
| `sockets` | [sails-hook-sockets](https://npmjs.com/package/sails-hook-sockets) | [](http://badge.fury.io/js/sails-hook-sockets) | Implements Socket.io support in Sails.
### sails-hook-orm
Implements support for the Waterline ORM in Sails.
[](http://npmjs.com/package/sails-hook-orm) [](http://npmjs.com/package/sails-hook-orm)
> + The default configuration set by this hook can be found [here](https://www.npmjs.com/package/sails-hook-orm#implicit-defaults).
> + You can find futher details about this hook's purpose [here](https://www.npmjs.com/package/sails-hook-orm#purpose).
> + You can disable this hook by following [these instructions](https://www.npmjs.com/package/sails-hook-orm#can-i-disable-this-hook).
### sails-hook-sockets
Implements socket.io support in Sails.
[](http://npmjs.com/package/sails-hook-sockets) [](http://npmjs.com/package/sails-hook-sockets)
> + You can find futher details about this hook's purpose [here](https://www.npmjs.com/package/sails-hook-sockets#purpose).
### sails-hook-grunt
Implements support for the built-in asset pipeline and task runner in Sails.
[](http://npmjs.com/package/sails-hook-grunt) [](http://npmjs.com/package/sails-hook-grunt)
> + You can find futher details about this hook's purpose [here](https://www.npmjs.com/package/sails-hook-grunt#purpose).
> + You can disable this hook by following [these instructions](https://www.npmjs.com/package/sails-hook-grunt#can-i-disable-this-hook).
### Community-made hooks
There are more than 200 community hooks for Sails.js [available on NPM](https://www.npmjs.com/search?q=sails+hook). Here are a few highlights:
| Hook | Maintainer | Purpose | Stable release |
|-------------|-------------|:---------------|----------------|
| [sails-hook-webpack](https://www.npmjs.com/package/sails-hook-webpack) | [Michael Diarmid](https://github.com/Salakar) | Use Webpack for your Sails app's asset pipeline instead of Grunt. | [](http://npmjs.com/package/sails-hook-webpack)
| [sails-hook-postcss](https://www.npmjs.com/package/sails-hook-postcss) | [Jeff Jewiss](https://github.com/jeffjewiss)| Process your Sails application’s CSS with Postcss. | [](http://npmjs.com/package/sails-hook-postcss)
| [sails-hook-babel](https://www.npmjs.com/package/sails-hook-babel) | [Onoshko Dan](https://github.com/dangreen), [Markus Padourek](https://github.com/globegitter) & [SANE](http://sanestack.com/) | Process your Sails application’s CSS with Postcss. | [](http://npmjs.com/package/sails-hook-babel)
| [sails-hook-responsetime](https://www.npmjs.com/package/sails-hook-responsetime) | [Luis Lobo Borobia](https://github.com/luislobo)| Add X-Response-Time to both HTTP and Socket request headers. | [](http://npmjs.com/package/sails-hook-responsetime)
| [sails-hook-winston](https://www.npmjs.com/package/sails-hook-winston) | [Kikobeats](https://github.com/Kikobeats) | Integrate the Winston logging system with your Sails application. | [](http://npmjs.com/package/sails-hook-winston)
| [sails-hook-allowed-hosts](https://www.npmjs.com/package/sails-hook-allowed-hosts) | [Akshay Bist](https://github.com/elssar) | Ensure that only requests made from authorized hosts/IP addresses are allowed. | [](http://npmjs.com/package/sails-hook-allowed-hosts)
| [sails-hook-cron](https://www.npmjs.com/package/sails-hook-cron) | [Eugene Obrezkov](https://github.com/ghaiklor) | Run cron tasks for your Sails app. | [](http://npmjs.com/package/sails-hook-cron)
| [sails-hook-organics](https://www.npmjs.com/package/sails-hook-organics) | [Mike McNeil](https://github.com/mikermcneil) | Exposes a set of commonly-used functions ("organics") as built-in helpers in your Sails app. | [](http://npmjs.com/package/sails-hook-organics)
##### Add your hook to this list
If you see out of date information on this page, or if you want to add a hook you made, please submit a pull request to this file updating the table of community hooks above.
Note: to be listed on this page, an adapter must be free and open-source (_libre_ and _gratis_), preferably under the MIT license.
================================================
FILE: docs/concepts/extending-sails/Hooks/events.md
================================================
# Application Events
### Overview
Sails app instances inherit Node's [`EventEmitter` interface](https://nodejs.org/api/events.html#events_class_eventemitter), meaning that they can both emit and listen for custom events. While it is not recommended that you utilize Sails events directly in app code (since your apps should strive to be as stateless as possible to facilitate scalability), events can be very useful when extending Sails (via [hooks](https://sailsjs.com/documentation/concepts/extending-sails/hooks) or [adapters](https://sailsjs.com/documentation/concepts/extending-sails/adapters)) and in a testing environment.
### Should I use events?
Most Sails developers never have a use case for working with application events. Events emitted by the Sails app instance are designed to be used when building your own custom hooks, and while you _could_ technically use them anywhere, in most cases you _should not_. Never use events in your controllers, models, services, configuration, or anywhere else in the userland code in your Sails app (unless you are building a custom app-level hook in `api/hooks/`).
### Events emitted by Sails
The following are the most commonly used built-in events emitted by Sails instances. Like any EventEmitter in Node, you can listen for these events with `sails.on()`:
```javascript
sails.on(eventName, eventHandlerFn);
```
None of the events are emitted with extra information, so your `eventHandlerFn` should not have any arguments.
| Event name | Emitted when... |
|:-----------|:----------------|
| `ready` | The app has been loaded and the bootstrap has run, but it is not yet listening for requests |
| `lifted` | The app has been lifted and is listening for requests. |
| `lower` | The app has is lowering and will stop listening for requests. |
| `hook::loaded` | The hook with the specified identity loaded and ran its `initialize()` method successfully. |
> In addition to `.on()`, Sails also exposes a useful utility function called `sails.after()`. See the [inline documentation](https://github.com/balderdashy/sails/blob/fd2f9b6866637143eda8e908775365ca52fab27c/lib/EVENTS.md#usage) in Sails core for more information.
================================================
FILE: docs/concepts/extending-sails/Hooks/hookspec/configure.md
================================================
# `.configure`
The `configure` feature provides a way to configure a hook after the [`defaults` objects](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification/defaults) have been applied to all hooks. By the time a custom hook’s `configure()` function runs, all user-level configuration and core hook settings will have been merged into `sails.config`. However, you should *not* depend on the configuration of other custom hooks at this point, as the load order of custom hooks is not guaranteed.
`configure` should be implemented as a function with no arguments, and should not return any value. For example, the following `configure` function could be used for a hook that communicates with a remote API, to change the API endpoint based on whether the user set the hook’s `ssl` property to `true`. Note that the hook’s configuration key is available in `configure` as `this.configKey`:
```
configure: function() {
// If SSL is on, use the HTTPS endpoint
if (sails.config[this.configKey].ssl == true) {
sails.config[this.configKey].url = "https://" + sails.config[this.configKey].domain;
}
// Otherwise use HTTP
else {
sails.config[this.configKey].url = "http://" + sails.config[this.configKey].domain;
}
}
```
The main benefit of `configure` is that all hook `configure` functions are guaranteed to run before any [`initialize` functions](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification/initialize) run; therefore, a hook’s `initialize` function can examine the configuration settings of other hooks.
================================================
FILE: docs/concepts/extending-sails/Hooks/hookspec/defaults.md
================================================
# `.defaults`
The `defaults` feature can be implemented either as an object or a function which takes a single argument (see “using `defaults` as a function” below) and returns an object. The object you specify will be used to provide default configuration values for Sails. You should use this feature to specify default settings for your hook. For example, if you were creating a hook that communicates with a remote service, you may want to provide a default domain and timeout length:
```
{
myapihook: {
timeout: 5000,
domain: "www.myapi.com"
}
}
```
If a `myapihook.timeout` value is provided via a Sails configuration file, that value will be used; otherwise it will default to `5000`.
##### Namespacing your hook configuration
For [project hooks](https://sailsjs.com/documentation/concepts/extending-sails/Hooks?q=types-of-hooks), you should namespace your hook’s configuration under a key that uniquely identifies that hook (e.g. `myapihook` above). For [installable hooks](https://sailsjs.com/documentation/concepts/extending-sails/Hooks?q=types-of-hooks), you should use the special `__configKey__` key to allow end-users of your hook to [change the configuration key](https://sailsjs.com/documentation/concepts/extending-sails/hooks/using-hooks?q=changing-the-way-sails-loads-an-installable-hook) if necessary. The default key for a hook using `__configKey__` is the hook name. For example, if you create a hook called `sails-hooks-myawesomehook` which includes the following `defaults` object:
```
{
__configKey__: {
name: "Super Bob"
}
}
```
then it will, by default, provide default settings for the `sails.config.myawesomehook.name` value. If the end-user of the hook overrides the hook name to be `foo`, then the `defaults` object will provide a default value for `sails.config.foo.name`.
##### Using `defaults` as a function
If you specify a function for the `defaults` feature instead of a plain object, it takes a single argument (`config`) which receives any Sails configuration overrides. Configuration overrides can be made by passing settings to the command line when lifting Sails (e.g. `sails lift --prod`), by passing an object as the first argument when programmatically lifting or loading Sails (e.g. `Sails.lift({port: 1338}, ...)`) or by using a [`.sailsrc`](https://sailsjs.com/documentation/anatomy/.sailsrc) file. The `defaults` function should return a plain object representing configuration defaults for your hook.
================================================
FILE: docs/concepts/extending-sails/Hooks/hookspec/hookspec.md
================================================
# The hook specification
### Overview
Each Sails hook is implemeted as a Javascript function that takes a single argument—a reference to the running `sails` instance—and returns an object with one or more of the keys described later in this document. The most basic hook would look like this:
```javascript
module.exports = function myBasicHook(sails) {
return {};
}
```
It wouldn't do much, but it would work!
Each hook should be saved in its own folder with the filename `index.js`. The folder name should uniquely identify the hook, and the folder can contain any number of additional files and subfolders. Extending the previous example, if you saved the file containing `myBasicHook` in a Sails project as `index.js` in the folder `api/hooks/my-basic-hook` and then lifted your app with `sails lift --verbose`, you would see the following in the output:
`verbose: my-basic-hook hook loaded successfully.`
### Hook features
The following features are available to implement in your hook. All features are optional, and can be implemented by adding them to the object returned by your hook function.
* [.defaults](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification/defaults)
* [.configure()](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification/configure)
* [.initialize()](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification/initialize)
* [.routes](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification/routes)
* [.registerActions()](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification/register-actions)
### Custom hook data and functions
Any other keys added to the object returned from the main hook function will be provided in the `sails.hooks[]` object. This is how custom hook functionality is provided to end-users. Any data and functions that you wish to remain private to the hook can be added *outside* the returned object:
```javascript
// File api/hooks/myhook/index.js
module.exports = function (sails) {
// This var will be private
var foo = 'bar';
return {
// This var will be public
abc: 123,
// This function will be public
sayHi: function (name) {
console.log(greet(name));
}
};
// This function will be private
function greet (name) {
return 'Hi, ' + name + '!';
}
};
```
The public var and function above would be available as `sails.hooks.myhook.abc` and `sails.hooks.myhook.sayHi`, respectively.
================================================
FILE: docs/concepts/extending-sails/Hooks/hookspec/initialize.md
================================================
# `.initialize`
The `initialize` feature allows a hook to perform startup tasks that may be asynchronous or rely on other hooks. All Sails configuration is guaranteed to be completed before a hook’s `initialize` function runs. Examples of tasks that you may want to put in `initialize` include:
* logging in to a remote API
* reading from a database that will be used by hook methods
* loading support files from a user-configured directory
* waiting for another hook to load first
Like all hook features, `initialize` is optional and can be left out of your hook definition. If implemented, `initialize` should be an `async function` which must be resolved (i.e. not throw or hang forever) in order for Sails to finish loading:
```javascript
initialize: async function() {
// Do some stuff here to initialize hook
}
```
##### Hook timeout settings
By default, hooks have ten seconds to complete their `initialize` function and resolve before Sails throws an error. That timeout can be configured by setting the `_hookTimeout` key to the number of milliseconds that Sails should wait. This can be done in the hook’s [`defaults`](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification/defaults):
```
defaults: {
__configKey__: {
_hookTimeout: 20000 // wait 20 seconds before timing out
}
}
```
##### Hook events and dependencies
When a hook successfully initializes, it emits an event with the following name:
`hook::loaded`
For example:
* the core `orm` hook emits `hook:orm:loaded` after its initialization is complete
* a hook installed into `node_modules/sails-hook-foo` emits `hook:foo:loaded` by default
* the same `sails-hook-foo` hook, with `sails.config.installedHooks['sails-hook-foo'].name` set to `bar` would emit `hook:bar:loaded`
* a hook installed into `node_modules/mygreathook` would emit `hook:mygreathook:loaded`
* a hook installed into `api/hooks/mygreathook` would also emit `hook:mygreathook:loaded`
You can use the "hook loaded" events to make one hook dependent on another. To do so, simply wrap your hook’s `initialize` logic in a call to `sails.on()`. For example, to make your hook wait for the `orm` hook to load, you could make your `initialize` similar to the following:
```javascript
initialize: async function() {
return new Promise((resolve)=>{
sails.on('hook:orm:loaded', ()=>{
// Finish initializing custom hook
// Then resolve.
resolve();
});
});
}
```
To make a hook dependent on several others, gather the event names to wait for into an array and call `sails.after`:
```javascript
initialize: async function() {
return new Promise((resolve)=>{
var eventsToWaitFor = ['hook:orm:loaded', 'hook:mygreathook:loaded'];
sails.after(eventsToWaitFor, ()=>{
resolve();
});
});
}
```
================================================
FILE: docs/concepts/extending-sails/Hooks/hookspec/register-actions.md
================================================
# `.registerActions()`
If your hook adds new actions to an app, and you want to guarantee that those actions will be maintained even after a call to [`sails.reloadActions()`](https://sailsjs.com/documentation/reference/application/sails-reload-actions), you should register the actions from within a `registerActions` method.
For example, the core Sails security hook registers the [`grant-csrf-token` action](https://sailsjs.com/documentation/concepts/security/csrf#?using-ajax-websockets) from within a `registerActions()` method.
`registerActions` should be implemented as a function with a single argument (a callback) to be called after the hook is done adding actions. In the interest of avoiding duplicate code, you may want to call this method yourself from within the hook’s [`initialize()` method]((https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification/initialize)).
```
registerActions: function(cb) {
// Register an action as `myhook/greet` that an app can bind to any route they like.
sails.registerAction(function greet(req, res) {
var name = req.param('name') || 'stranger';
return res.status(200).send('Hey there, ' + name + '!');
}, 'myhook/greet');
return cb();
}
```
================================================
FILE: docs/concepts/extending-sails/Hooks/hookspec/routes.md
================================================
# `.routes`
The `routes` feature allows a custom hook to easily bind new routes to a Sails app at load time. If implemented, `routes` should be an object with either a `before` key, an `after` key, or both. The values of those keys should in turn be objects whose keys are [route addresses](https://sailsjs.com/documentation/concepts/routes/custom-routes#?route-address), and whose values are route-handling functions with the standard `(req, res, next)` parameters. Any routes specified in the `before` object will be bound *before* custom user routes (as defined in [sails.config.routes](https://sailsjs.com/documentation/reference/configuration/sails-config-routes)) and [blueprint routes](https://next.sailsjs.com/documentation/reference/blueprint-api#?restful-shortcut-routes-and-actions). Conversely, routes specified in the `after` object will be bound *after* custom and blueprint routes. For example, consider the following `count-requests` hook:
```javascript
module.exports = function (sails) {
// Declare a var that will act as a reference to this hook.
var hook;
return {
initialize: function(cb) {
// Assign this hook object to the `hook` var.
// This allows us to add/modify values that users of the hook can retrieve.
hook = this;
// Initialize a couple of values on the hook.
hook.numRequestsSeen = 0;
hook.numUnhandledRequestsSeen = 0;
// Signal that initialization of this hook is complete
// by calling the callback.
return cb();
},
routes: {
before: {
'GET /*': function (req, res, next) {
hook.numRequestsSeen++;
return next();
}
},
after: {
'GET /*': function (req, res, next) {
hook.numUnhandledRequestsSeen++;
return next();
}
}
}
};
};
```
This hook will process all requests via the function provided in the `before` object, and increment its `numRequestsSeen` variable. It will also process any *unhandled* requests via the function provided in the `after` object—that is, any routes that aren't bound in the app via a custom route configuration or a blueprint.
> The two variables set up in the hook will be available to other modules in the Sails app as `sails.hooks["count-requests"].numRequestsSeen` and `sails.hooks["count-requests"].numUnhandledRequestsSeen`
================================================
FILE: docs/concepts/extending-sails/Hooks/installablehooks.md
================================================
# Creating an installable hook
Installable hooks are custom Sails hooks that reside in an application’s `node_modules` folder. They are useful when you want to share functionality between Sails apps, or publish your hook to [NPM](http://npmjs.org) to share it with the Sails community. If you wish to create a hook for use in *just one* Sails app, see [creating a project hook](https://sailsjs.com/documentation/concepts/extending-sails/hooks/project-hooks) instead.
To create a new installable hook:
1. Choose a name for your new hook. It must not conflict with any of the [core hook names](https://github.com/balderdashy/sails/blob/master/lib/app/configuration/default-hooks.js).
1. Create a new folder on your system with the name `sails-hook-`. The `sails-hook-` prefix is optional but recommended for consistency; it is stripped off by Sails when the hook is loaded.
1. Create a `package.json` file in the folder. If you have `npm` installed on your system, you can do this easily by running `npm init` and following the prompts. Otherwise, you can create the file manually, and ensure that it contains at minimum the following:
```json
{
"name": "sails-hook-your-hook-name",
"version": "0.0.0",
"description": "a brief description of your hook",
"main": "index.js",
"sails": {
"isHook": true
}
}
```
If you use `npm init` to create your `package.json`, be sure to open the file afterwards and manually insert the `sails` key containing `isHook: true`.
1. Write your hook code in `index.js` in accordance with the [hook specification](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification).
Your new folder may contain other files as well, which can be loaded in your hook via `require`; only `index.js` will be read automatically by Sails. Use the `dependencies` key of your `package.json` to refer to any dependencies that need to be installed in order for your hook to work (you may also use `npm install --save` to easily save dependency information to `package.json`).
### Specifying the internal name Sails uses for your hook (advanced)
In certain cases, especially when using a [scoped NPM package](https://docs.npmjs.com/misc/scope) to override a core Sails hook, you will want to change the name that Sails uses internally when it loads your hook. You can use the `sails.hookName` configuration option in your `package.json` file for this. The value should be the name you want to be loaded into the `sails.hooks` dictionary, so you generally will _not_ want a `sails-hooks-` prefix. For example, if you have a module `@mycoolhooks/sails-hook-sockets` that you wish to use to override the core `sails-hook-sockets` module, the `package.json` might look like:
```json
{
"name": "@mycoolhooks/sails-hook-sockets",
"version": "0.0.0",
"description": "my own sockets hook",
"main": "index.js",
"sails": {
"isHook": true,
"hookName": "sockets"
}
}
```
### Testing your new hook
Before you distribute your installable hook to others, you’ll want to write some tests for it. This will help ensure compatibility with future Sails versions and significantly reduce hair-pulling and destruction of nearby objects in fits of rage. While a full guide to writing tests is outside the scope of this doc, the following steps should help get you started:
1. Add Sails as a `devDependency` in your hook’s `package.json` file:
```json
"devDependencies": {
"sails": "~0.11.0"
}
```
1. Install Sails as a dependency of your hook with `npm install sails` or `npm link sails` (if you have Sails installed globally on your system).
1. Install [Mocha](http://mochajs.org/) on your system with `npm install -g mocha`, if you haven’t already.
1. Add a `test` folder inside your hook’s main folder.
2. Add a `basic.js` file with the following basic test:
```javascript
var Sails = require('sails').Sails;
describe('Basic tests ::', function() {
// Var to hold a running sails app instance
var sails;
// Before running any tests, attempt to lift Sails
before(function (done) {
// Hook will timeout in 10 seconds
this.timeout(11000);
// Attempt to lift sails
Sails().lift({
hooks: {
// Load the hook
"your-hook-name": require('../'),
// Skip grunt (unless your hook uses it)
"grunt": false
},
log: {level: "error"}
},function (err, _sails) {
if (err) return done(err);
sails = _sails;
return done();
});
});
// After tests are complete, lower Sails
after(function (done) {
// Lower Sails (if it successfully lifted)
if (sails) {
return sails.lower(done);
}
// Otherwise just return
return done();
});
// Test that Sails can lift with the hook in place
it ('sails does not crash', function() {
return true;
});
});
```
1. Run the test with `mocha -R spec` to see full results.
1. See the [Mocha](http://mochajs.org/) docs for a full reference.
### Publishing your hook
Assuming your hook is tested and looks good, and assuming that the hook name isn’t already in use by another [NPM](http://npmjs.org) module, you can share it with world by running `npm publish`. Go you!
* [Hooks overview](https://sailsjs.com/documentation/concepts/extending-sails/hooks)
* [Using hooks in your app](https://sailsjs.com/documentation/concepts/extending-sails/hooks/using-hooks)
* [The hook specification](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification)
* [Creating a project hook](https://sailsjs.com/documentation/concepts/extending-sails/hooks/project-hooks)
================================================
FILE: docs/concepts/extending-sails/Hooks/projecthooks.md
================================================
# Creating a project hook
Project hooks are custom Sails hooks that reside in an application’s `api/hooks` folder. They are most useful when you want to take advantage of hook features like [defaults](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification/defaults) and [routes](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification/routes) for code that is used by multiple components in a single app. If you wish to re-use a hook in *more than one* Sails app, see [creating an installable hook](https://sailsjs.com/documentation/concepts/extending-sails/hooks/installable-hooks) instead.
To create a new project hook:
1. Choose a name for your new hook. It must not conflict with any of the [core hook names](https://github.com/balderdashy/sails/blob/master/lib/app/configuration/default-hooks.js).
2. Create a folder with that name in your app’s `api/hooks` folder.
3. Add an `index.js` file to that folder.
4. Write your hook code in `index.js` in accordance with the [hook specification](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification).
Your new folder may contain other files as well, which can be loaded in your hook via `require`; only `index.js` will be read automatically by Sails.
As an alternative to a folder, you may create a file in your app’s `api/hooks` folder like `api/hooks/myProjectHook.js`.
#### Testing that your hook loads properly
To test that your hook is being loaded by Sails, lift your app with `sails lift --verbose`. If your hook is loaded, you will see a message like:
`verbose: your-hook-name hook loaded successfully.`
in the logs.
* [Hooks overview](https://sailsjs.com/documentation/concepts/extending-sails/hooks)
* [Using hooks in your app](https://sailsjs.com/documentation/concepts/extending-sails/hooks/using-hooks)
* [The hook specification](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification)
* [Creating an installable hook](https://sailsjs.com/documentation/concepts/extending-sails/hooks/installable-hooks)
================================================
FILE: docs/concepts/extending-sails/Hooks/usinghooks.md
================================================
# Using hooks in a Sails app
## Using a project hook
To use a project hook in your app, first create the `api/hooks` folder if it doesn’t already exist. Then [create the project hook](https://sailsjs.com/documentation/concepts/extending-sails/hooks/project-hooks) or copy the folder for the hook you want to use into `api/hooks`.
## Using an installable hook
To use an installable hook in your app, simply run `npm install` with the package name of the hook you wish to install (e.g. `npm install sails-hook-autoreload`). You may also manually copy or link an [installable hook folder that you've created](https://sailsjs.com/documentation/concepts/extending-sails/hooks/installable-hooks) directly into your app’s `node_modules` folder.
## Calling hook methods
Any methods that a hook exposes are available in the `sails.hooks[]` object. For example, the `sails-hook-email` hook provides a `sails.hooks.email.send()` method (note that the `sails-hook-` prefix is stripped off). Consult a hook’s documentation to determine which methods it provides.
## Configuring a hook
Once you’ve added an installable hook to your app, you can configure it using the regular Sails config files like `config/local.js`, `config/env/development.js`, or a custom config file you create yourself. Hook settings are typically namespaced under the hook’s name, with any `sails-hook-` prefix stripped off. For example, the `from` setting for `sails-hook-email` is available as `sails.config.email.from`. The documentation for the installable hook should describe the available configuration options.
## Changing the way Sails loads an installable hook
On rare occassions, you may need to change the name that Sails uses for an installable hook, or change the configuration key that the hook uses. This may be the case if you already have a project hook with the same name as an installable hook, or if you’re already using a configuration key for something else. To avoid these conflicts, Sails provides the `sails.config.installedHooks.` configuration option. The hook identity is *always* the name of the folder that the hook is installed in.
```javascript
// config/installedHooks.js
module.exports.installedHooks = {
"sails-hook-email": {
// load the hook into sails.hooks.emailHook instead of sails.hooks.email
"name": "emailHook",
// configure the hook using sails.config.emailSettings instead of sails.config.email
"configKey": "emailSettings"
}
};
```
> Note: you may have to create the `config/installedHooks.js` file yourself.
* [Hooks overview](https://sailsjs.com/documentation/concepts/extending-sails/hooks)
* [The hook specification](https://sailsjs.com/documentation/concepts/extending-sails/hooks/hook-specification)
* [Creating a project hook](https://sailsjs.com/documentation/concepts/extending-sails/hooks/project-hooks)
* [Creating an installable hook](https://sailsjs.com/documentation/concepts/extending-sails/hooks/installable-hooks)
================================================
FILE: docs/concepts/extending-sails/extending-sails.md
================================================
# Extending Sails
In keeping with the Node philosophy, Sails aims to keep its core as small as possible, delegating all but the most critical functions to separate modules. There are currently three types of extensions that you can add to Sails:
+ [**Generators**](https://sailsjs.com/documentation/concepts/extending-sails/Generators): for adding and overriding functionality in the Sails CLI. *Example*: [sails-generate-model](https://www.npmjs.com/package/sails-generate-model), which allows you to create models on the command line with `sails generate model foo`.
+ [**Adapters**](https://sailsjs.com/documentation/concepts/extending-sails/Adapters): for integrating Waterline (Sails' ORM) with new data sources, including databases, APIs, or even hardware. *Example*: [sails-postgresql](https://www.npmjs.com/package/sails-postgresql), the official [PostgreSQL](http://www.postgresql.org/) adapter for Sails.
+ [**Hooks**](https://sailsjs.com/documentation/concepts/extending-sails/Hooks): for overriding or injecting new functionality in the Sails runtime. *Example*: [sails-hook-autoreload](https://www.npmjs.com/package/sails-hook-autoreload), which adds auto-refreshing for a Sails project's API without having to manually restart the server.
If you’re interested in developing a plugin for Sails, you will most often want to make a [hook](https://sailsjs.com/documentation/concepts/extending-sails/Hooks).
* _Core hooks_, like `http`, `request`, etc. are hooks which are bundled with Sails out of the box. They can be disabled by specifying a `hooks` configuration in your `.sailsrc` file, or when lifting Sails programatically.
================================================
FILE: docs/concepts/shell-scripts/shell-scripts.md
================================================
# Shell scripts
Sails comes bundled with [Whelk](https://github.com/sailshq/whelk), which lets you run JavaScript functions as shell scripts. This can be useful for running scheduled jobs (cron, Heroku scheduler), worker processes, and any other custom, one-off scripts that need access to your Sails app's models, configuration, and helpers.
### Your first script
To add a new script, just create a file in the `scripts/` folder of your app.
```bash
sails generate script hello
```
Then, to run it, use:
```bash
sails run hello
```
> If you need to run a script without global access to the `sails` command-line interface (in a Procfile, for example), use `node ./node_modules/sails/bin/sails run hello`.
### Example
Here's a more complex example that you might see in a real-world app:
```js
// scripts/send-email-proof-reminders.js
module.exports = {
description: 'Send a reminder to any recent users who haven\'t confirmed their email address yet.',
inputs: {
template: {
description: 'The name of another email template to use as an optional override.',
type: 'string',
defaultsTo: 'reminder-to-confirm-email'
}
},
fn: async function (inputs, exits) {
await User.stream({
emailStatus: 'pending',
emailConfirmationReminderAlreadySent: false,
createdAt: { '>': Date.now() - 1000*60*60*24*3 }
})
.eachRecord(async (user, proceed)=>{
await sails.helpers.sendTemplateEmail.with({
template: inputs.template,
templateData: {
user: user
},
to: user.emailAddress
});
return proceed();
});//∞
return exits.success();
}
};
```
Then you can run:
```bash
sails run send-email-proof-reminders
```
For more detailed information on usage, see the [`whelk` README](https://github.com/sailshq/whelk/blob/master/README.md).
================================================
FILE: docs/contributing/adapter-specification.md
================================================
# Adapter interface reference
> The adapter interface specification is currently under active development and may change.
## Semantic (interface)
> e.g. `RestAPI` or `MySQL`
> ##### Stability: [3](http://nodejs.org/api/documentation.html#documentation_stability_index) - Stable
Implementing the basic semantic interface (CRUD) is really a step towards a complete implementation of the Queryable interface, but with some services/datasources, about as far as you'll be able to get using native methods.
By supporting the Semantic interface, you also get the following:
+ if you write a `find()` function, developers can also use all of its synonyms, including dynamic finders and `findOne()`. When they're called, they'll automatically be converted into the appropriate criteria object for the basic `find()` definition in your adapter.
+ as long as you implement basic `where` functionality (see `Queryable` below), Waterline can derive a simplistic version of associations support for you. To optimize the default assumptions with native methods, override the appropriate methods in your adapter.
> All officially supported Sails.js database adapters implement the `Semantic` interface.
###### Class methods
+ `Model.create()`
+ `Model.find()`
+ `Model.update()`
+ `Model.destroy()`
+ Optimizations:
+ `findOrCreate()`
+ `createEach()`
+ Not yet available:
+ `destroyEach()`
+ `updateEach()`
+ `findOrCreateEach()`
+ `findAndUpdateOrCreate()`
+ `findAndUpdateOrCreateEach()`
## Queryable (interface)
> ##### Stability: [3](http://nodejs.org/api/documentation.html#documentation_stability_index) - Stable
Query building features are common in traditional ORMs, but not at all a guarantee when working with Waterline. Since Waterline adapters can support services as varied as Twitter, SMTP, and Skype, traditional assumptions around structured data don't always apply.
If query modifiers are enabled, the adapter must support `Model.find()`, as well as the **complete** query interface, or, where it is impossible to do so, at least provide good error messages. If coverage of the interface is unfinished, it's still not a bad idea to make the adapter available, but it's important to clearly state the unifinished parts, and consequent limitations, up front. This helps prevent the creation of off-topic issues in Sails/Waterline core, protects developers from unexpected consequences, and perhaps most importantly, helps focus contributors on high-value tasks.
> All officially supported Sails.js database adapters implement this interface.
###### Query modifiers
Query modifiers include normalized syntax:
+ `where`
+ `limit`
+ `skip`
+ `sort`
+ `select`
And WHERE supports:
Boolean logic:
+ `and`
+ `or`
+ `not`
`IN` queries:
Adapters which implement `where` should recognize a list of values (e.g. `name: ['Gandalf', 'Merlin']`) as an `IN` query. In other words, if `name` is either of those values, a match occured.
Sub-attribute modifiers:
You are also responsible for sub-attribute modifiers, (e.g. `{ age: { '>=' : 65 } }`) with the notable exception of `contains`, `startsWith`, and `endsWith`, since support for those modifiers can be derived programatically by leveraging your definition of `like`.
+ `like` (SQL-style, with % wildcards)
+ `'>' ` (you can also opt to use the more verbose `.greaterThan()`, etc.)
+ `'<' `
+ `'>='`
+ `'<='`
## Migratable (interface)
> ##### Stability: [1](http://nodejs.org/api/documentation.html#documentation_stability_index) - Experimental
Adapters which implement the Migratable interface are usually interacting with SQL databases. This interface enables the `migrate` configuration option on a per-model or adapter-global basis, as well as access to the prototypal/class-level CRUD operations for working with tables.
###### Adapter methods
> This is not how it actually works, but how it could work soon:
+ `Adapter.define()`
+ `Adapter.describe()`
+ `Adapter.drop()`
+ `Adapter.alter()` (change table name, other table metadata)
+ `Adapter.addAttribute()` (add column)
+ `Adapter.removeAttribute()` (remove column)
+ `Adapter.alterAttribute()` (rename column, add or remove uniquness constraint to column)
+ `Adapter.addIndex()`
+ `Adapter.removeIndex()`
###### Auto-migration strategies
+ `"safe"` (default in production env)
+ do nothing
+ `"drop"` (default in development env)
+ drop all tables and recreate them each time the server starts-- useful for development
+ `"alter"`
+ experimental automigrations
+ `"create"`
+ create all missing tables/columns without modifying existing data
## SQL (interface)
> ##### Stability: [1](http://nodejs.org/api/documentation.html#documentation_stability_index) - Experimental
Adapters which implement the SQL interface interact with databases supporting the SQL language. This interface exposes the method `.query()` allowing the user to run *raw* SQL queries against the database.
###### Adapter methods
+ `Adapter.query(query,[ data,] cb)`
================================================
FILE: docs/contributing/code-of-conduct.md
================================================
# Code of conduct
> The Code of Conduct explains the *bare minimum* behavior expectations the Sails project requires of its contributors. This Code of Conduct is adapted from the version used by the [Node.js core team](https://github.com/nodejs/node/blob/master/CODE_OF_CONDUCT.md). Their version was originally borrowed from [Rust lang's excellent CoC](http://www.rust-lang.org/conduct.html).
- We are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, disability, ethnicity, religion, or similar personal characteristic.
- Please avoid using overtly sexual, racial, or political nicknames, or any other nicknames that might detract from a friendly, safe and welcoming environment for all.
- Please be kind and courteous. There's no need to be mean or rude.
- Avoid the use of personal pronouns in any code comments or documentation where such use could be perceived in a negative light. There is no need to address persons when explaining code (e.g. "When the developer").
- Respect that some individuals and cultures consider the casual use of profanity offensive and off-putting.
- Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
- Please keep unstructured critique to a minimum. If you have ideas you want to experiment with, make a fork and see how it works.
- We will exclude you from interaction if you insult, demean or harass
anyone. That is not welcome behavior. We interpret the term
"harassment" as including the definition in the [Citizen Code of
Conduct](http://citizencodeofconduct.org/); if you have any lack of
clarity about what might be included in that concept, please read
their definition, or ask one of the project maintainers first.
In particular, we don't tolerate defamatory remarks or behavior that
excludes people in socially marginalized groups, or for whom English
is not a native language.
- Private harassment is also unacceptable. No matter who you are, if
you feel you have been or are being harassed or made uncomfortable
by a community member, please contact one of the core maintainers immediately
via private message on Twitter or by emailing [inquiries@sailsjs.com](inquiries@sailsjs.com).
In either case, include a capture (screenshot, log, photo, email) of
the harassment if possible. Whether you're a regular contributor or
a newcomer, we care about making this community a safe, comfortable
place for you and we've got your back.
- Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome,
and will result in your exclusion.
================================================
FILE: docs/contributing/code-submission-guidelines/best-practices.md
================================================
# Best practices
There are many undocumented best practices and workflow improvements for developing in Sails that contributors have established over the years. This section is an attempt to document some of the basics, but be sure and pop into [Gitter](https://gitter.im/balderdashy/sails) if you ever have a question about how to set things up or want to share your own tool chain.
The best way to work with Sails core is to fork the repository, `git clone` it to your filesystem, and then run `npm link`. In addition to writing tests, you'll often want to use a sample project as a harness; to do that, `cd` into the sample app and run `npm link sails`. This will create a symbolic link in the `node_modules` directory of your sample app that points to your local cloned version of Sails. This keeps you from having to copy the framework over every time you make a change. You can force your sample app to use the local Sails dependency by running `node app` instead of `sails lift` (although `sails lift` **should** use the local dependency, if one exists). If you need to test the command line tool this way, you can access it from your sample app as `node node_modules/sails/bin/sails`. For example, if you were working on `sails new`, and you wanted to test it manually, you could run `node node_modules/sails/bin/sails new testProj`.
#### Installing different versions of Sails
| Release | Install Command | Build Status |
|-----------------------|--------------------------|-------------------|
| [latest](https://npmjs.com/package/sails) | `npm install sails` | Stable |
| [edge](https://github.com/balderdashy/sails/tree/master) | `npm install sails@git://github.com/balderdashy/sails.git` | [](https://travis-ci.org/balderdashy/sails/branches) |
#### Installing an unreleased branch for testing
In general, you can `npm install` Sails directly from Github as follows:
```sh
# Install an unreleased branch of Sails in the current directory's `node_modules`
$ npm install sails@git://github.com/balderdashy/sails.git#nameOfDesiredBranch
```
This is useful for testing/installing hot-fixes and just a good thing to know how to do in general.
#### Submitting Pull Requests
0. If this is your first time forking and submitting a PR, [follow our instructions here](https://sailsjs.com/documentation/contributing/code-submission-guidelines/sending-pull-requests).
1. Fork the repo.
2. Add a test for your change. Only refactoring and documentation changes require no new tests. If you are adding functionality or fixing a bug, we need a test!
4. Make the tests pass and make sure you follow [our syntax guidelines](https://github.com/balderdashy/sails/blob/master/.jshintrc).
5. Add a line of what you did to CHANGELOG.md (right under `master`).
6. Push to your fork and submit a pull request to the appropriate branch:
+ [Master](https://github.com/balderdashy/sails/tree/master)
+ Corresponds with the "edge" version—the latest, not-yet-released version of Sails. Most pull requests should be sent here.
+ [Latest (or "stable")](https://npmjs.com/package/sails)
+ Corresponds with the latest stable release on npm (if you have a high-priority hotfix, send the PR explaining that).
================================================
FILE: docs/contributing/code-submission-guidelines/code-submission-guidelines.md
================================================
# Code submission guidelines
There are two types of code contributions we can accept in Sails core: patches and new features.
**Patches** are small fixes and represent everything from typos to timing issues. Removing an unused `require()` from the top of a file, or fixing a typo that is crashing the master branch tests on Travis are two great examples of patches. Major refactoring projects that change whitespace and variable names across multiple files are **not** patches. Also, keep in mind that even a seemingly trivial change is not a patch if it affects the usage of a documented feature of Sails, or if it adds an undocumented public function.
**New features** are TODOs summarized in the [Sails Roadmap](https://github.com/balderdashy/sails/blob/master/ROADMAP.md) file, with more information in an accompanying pull request. Anything that is not specifically in the ROADMAP.md file should not be submitted as a new feature.
If in doubt about whether a change you would like to make would be considered a "patch", please open an issue in the [issue tracker](https://github.com/balderdashy/sails/issues/new) or contact someone from our [core team](https://sailsjs.com/about) on Twitter _before_ you begin work on the pull request. Especially do so if you plan to work on something big. Nothing is more frustrating than seeing your hard work go to waste because your vision does not align with planned or ongoing development efforts of the project's maintainers.
#### General rules
- **Javascript supported by [maintained LTS](https://github.com/nodejs/Release/blob/0e0b592273104d1cca9154588092654b932659b1/README.md) only, please**. For consistency, all imperative code in Sails core, including core hooks and core generators, must be written in JavaScript—not CoffeeScript, TypeScript, or any other pre-compiled or transpiled language. Don't get us wrong: we think it's great to use ES6, TypeScript, and/or CoffeeScript syntax in userland code if it boosts your productivity! But for compatibility and consistency reasons, we cannot merge a pull request unless it is written in maintained LTS-supported JavaScript.
- Do not auto-format code or attempt to fix perceived style problems in existing files in core.
- Keep each pull request narrowly focused on a single goal, and change as few LoC/files as possible.
- Do not submit pull requests that implement new features or enhance existing features unless you are working from a very clearly-defined proposal. As stated above, nothing is more frustrating than seeing your hard work go unmerged because your vision does not align with a project's maintainers.
- Before beginning work on a feature, be sure to leave a comment telling other contributors that you are working on that feature. Note that if you do not actively keep other contributors informed about your progress, your silence may be taken as inactivity, and someone else may start their own work on that feature.
#### Contributing to core
Sub-modules within the Sails core are at varying levels of API stability. Bug fixes (patches) are always welcome, but API or behavioral changes cannot be merged without serious planning, as documented in the process for feature proposals above.
Sails has several dependencies referenced in the `package.json` file that are not part of the project proper. Any proposed changes to those dependencies or _their_ dependencies should be sent to their respective projects (e.g. Express, Socket.io, etc.) Please do not send your patch or feature request to the Sails repository—we cannot accept or fulfill it. (Though if you reach out via chat, we'll try to help if we can.)
#### Contributing to an adapter
If the adapter is part of core (code base located in the Sails repo), please follow the general best practices for contributing to Sails core. If it is located in a different repo, please send feature requests and patches there.
#### Authoring a new adapter
Sails adapters translate Waterline query syntax into the lower-level language of the integrated database, and they take the results from the database and map them to the response expected by Waterline, the Sails framework's ORM. While creating a new adapter should not be taken lightly, in many cases, writing an adapter is not as hard as it sounds (since you usually end up wrapping around an existing npm package), and it's a great way to get your feet wet with contributing to the ORM hook in Sails and to the Waterline code base.
Before starting work on a new adapter, just make sure and do a thorough search on npm, Google and Github to check that someone else hasn't already started working on the same thing. Read more about adapters in [Concepts > Extending Sails > Adapters](https://sailsjs.com/documentation/concepts/extending-sails/adapters).
#### Contributing to a hook
If the hook is part of core (code base is located in the Sails repo), please follow the general best practices for contributing to Sails core. If the hook is located in a different repo, please send feature requests, patches, and issues there. Many core hooks have README.md files with extensive documentation of their purpose, the methods they attach, the events they trigger, and any other relevant information about their implementation.
#### Authoring a new hook
Creating a hook is a great way to accomplish _almost anything_ in Sails core. Before starting work on a new custom hook, just make sure and do a thorough search on npm, Google, and Github to make sure someone else hasn't already started working on the same thing. Read more about custom hooks in [Concepts > Extending Sails > Hooks](https://sailsjs.com/documentation/concepts/extending-sails/hooks).
#### Contributing to a generator
If the generator is part of core (code base is located in the Sails repo), please follow the general best practices for contributing to Sails core. If it is located in a different repo, please send feature requests, patches, and issues there.
#### Authoring a new generator
The custom generator API is not 100% stable yet, but it is settling. Feel free to start work on a new custom generator, but first make sure and do a thorough search on npm, Google and Github to make sure someone else hasn't already started working on the same thing. A custom generator is a great way to get your feet wet with contributing to the Sails code base.
================================================
FILE: docs/contributing/code-submission-guidelines/sending-pull-requests.md
================================================
# Sending pull requests
This guide is designed to get you started contributing to the Sails framework. It assumes basic familiarity with Github, but it should be useful for contributors of all levels.
## Contribution guidelines
Like any open-source project, we must have guidelines for contributions—it helps protect the quality of the code and ensures that our framework stays robust and dependable.
For these reasons, it's important that contribution protocols are followed for *all* contributions to Sails, whether they be bug fixes or whole sets of new features.
Before submitting a pull request, please make sure:
- Any bug fixes have accompanying tests where possible. We use [Mocha](http://visionmedia.github.io/mocha/) for testing.
- Code follows our style guide, to maintain consistency (see `.jshint` and/or `.editorconfig` files in repo).
If you have a high-priority hot-fix for the currently deployed version, please [post an issue on Github](https://github.com/balderdashy/sails/issues?milestone=none&state=open) and mention @mikermcneil. Also, for emergencies, please feel free to tweet @sailsjs.
Now that we are all on the same page, lets get to coding some awesomeness of our own :D
## Fork
Start by forking the repository:

## Clone
Then clone your fork into your local filesystem:
git clone `git@github.com:YOUR_USER_NAME/sails.git`
## Update
To merge recent changes into your fork, inside your project dir:
```
git remote add core https://github.com/balderdashy/sails.git
git fetch core
git merge core/master
```
For additional details, see [Github](https://help.github.com/articles/fork-a-repo).
## Code
Make your enhancements, fix bugs, do your thang.
## Test
Please write a test for your addition/fix. I know it kind of sucks if you're not used to it, but it's how we maintain great code.
For our test suite, we use [Mocha](http://visionmedia.github.com/mocha/). You can run the tests with `npm test`. See the "Testing" section in the contribution guide for more information.

## Pull request
When you're done, you can commit your fix, push up your changes, and then go into Github and submit a pull request. We'll look it over and get back to you ASAP.

## Running your fork with your application
If you forked Sails and you want to test your Sails app against your fork, here's how you do it:
In your local copy of your fork of Sails:
`sudo npm link`
In your Sails app's repo:
`npm link sails`
This creates a symbolic link as a local dependency (in your app's `node_modules` folder). This has the effect of letting you run your app with the version Sails you `linked`.
```bash
$ sails lift
```
### *Thanks for your contributions!*
================================================
FILE: docs/contributing/code-submission-guidelines/writing-tests.md
================================================
# Writing tests
### What to test
In an ideal world, any possible action you could perform as a Sails user—whether programatically or via the command-line tool—would have a test. However, the number of configuration variations in Sails, along with the fact that userland code can override just about any key piece of core, means we'll never _quite_ get to this point. And that's okay.
Instead, the Sails project's goal is for any _feature of Sails_ you might use—programatically or via the command-line tool—to have a test. In cases where these features are implemented within a dependency, the only tests for that feature exist within that dependency (e.g. [Waterline](https://github.com/balderdashy/waterline/tree/master/test), [Skipper](https://github.com/balderdashy/skipper/tree/master/test), and [Captains Log](https://github.com/balderdashy/captains-log/tree/master/test)). Even in these cases, though, tests in Sails inevitably end up retesting certain features that are already verified by Sails' dependencies, and there's nothing wrong with that.
### What _not_ to test
We should strive to avoid tests which verify exclusivity: it cripples our ability to develop quickly. In other words, tests should not fail with the introduction of additive features.
For instance, if you're writing a test to check that the appropriate files have been created with `sails new`, it would make sense to check for those files, but it would _not_ make sense to ensure that ONLY those files were created (i.e. adding a new file should not break the tests).
Another example is a test which verifies the correctness of blueprint configuration, e.g. `sails.config.blueprints.rest`. The test should check that blueprints behave properly with the `rest` config enabled and disabled. We could change the configuration, add more controller-specific options, etc., and we'd only need to write new tests.
If, on the other hand, our strategy for testing the behavior of the blueprints involved evaluating the behavior and *then* making a judgement on what the config "_should_" look like, we'd have to modify the tests when we added new options. This may not sound like a big deal, but it can grow out of proportion quickly!
================================================
FILE: docs/contributing/contributing-to-the-documentation.md
================================================
# Contributing to the documentation
The official documentation on the Sails website is compiled from markdown files in the [sails](https://github.com/balderdashy/sails/sails-docs) repo. Please send a pull request to the **master** branch with amendments and they'll be double-checked and merged as soon as possible.
We are open to suggestions about the process we're using to manage our documentation, and to working with the community in general. Please post to the [Gitter](https://gitter.im/balderdashy/sails) with your ideas; or, if you're interested in helping directly, contact @fancydoilies or @mikermcneil on Twitter.
#### What branch should I edit?
That depends on what kind of edit you are making. Most often, you'll be making an edit that is relevant for the latest stable version of Sails (i.e. the version on [NPM](npmjs.org/package/sails)) and so you'll want to edit the `master` branch of _this_ repo (what you see in the sails repo by default). The docs team merges master into the appropriate branch for the latest stable release of Sails, and then deploys that to sailsjs.com about once per week.
On the other hand, if you are making an edit related to an unreleased feature in an upcoming version—usually as an accompaniment a feature proposal or open pull request to Sails or a related project—then you will want to edit the branch for the next, unreleased version of Sails (sometimes called "edge").
| Branch (in `sails` or `sails-docs`) | Documentation for Sails Version... | Preview At... |
|-------------------------------------------------------------------------------------|------------------------|:-------------------|
| [`master`](https://github.com/balderdashy/sails/tree/master/docs) | [](http://badge.fury.io/js/sails) | [preview.sailsjs.com](http://preview.sailsjs.com)
| [`0.12`](https://github.com/balderdashy/sails-docs/tree/0.12) | Sails v0.12.x | [sailsjs.com](https://sailsjs.com)
| [`0.11`](https://github.com/balderdashy/sails-docs/tree/0.11) | Sails v0.11.x | [0.11.sailsjs.com](http://0.11.sailsjs.com)
#### How are these docs compiled and pushed to the website?
We use a module called `doc-templater` to convert the .md files to the HTML for the website. You can learn more about how it works in [the doc-templater repo](https://github.com/uncletammy/doc-templater).
Each .md file has its own page on the website (e.g. all reference, concepts, and anatomy files), and should include a special `` tag with a `value` property specifying the title for the page. This will impact how the doc page appears in search engine results, and it will also be used as its display name in the navigation menu on sailsjs.com. For example:
```markdown
```
#### When will my change appear on the Sails website?
Documentation changes go live when they are merged onto a special branch corresponding with the current stable version of Sails (e.g. 0.12). We cannot merge pull requests sent directly to this branch—its sole purpose is to reflect the content currently hosted on sailsjs.com, and content is only merged just before redeploying the Sails website.
If you want to see how documentation changes will appear on sailsjs.com, you can visit [preview.sailsjs.com](http://preview.sailsjs.com). The preview site updates itself automatically as changes are merged into the master branch of sails.
#### How can I help translate the documentation?
A great way to help the Sails project, especially if you're a native speaker of a language other than English, is to volunteer to translate the Sails documentation.
If you are interested in beginning a translation project, follow these steps:
+ Bring the documentation folder from the [sails repo](https://github.com/balderdashy/sails/tree/master/docs) (`balderdashy/sails/docs`) into a new repo named `sails-docs-{{IETF}}` where {{IETF}} is the [IETF language tag](https://en.wikipedia.org/wiki/IETF_language_tag) for your language.
+ Edit [the documentation README](https://github.com/balderdashy/sails/tree/master/docs) to summarize your progress so far, provide any other information you think would be helpful for others reading your translation, and let interested contributors know how to contact you.
+ When you are satisfied with the first complete version of your translation, open an issue and someone from our docs team will be happy to help you preview it in the context of the Sails website, get it live on a domain (yours, or a subdomain of sailsjs.com, whichever makes the most sense), and share it with the rest of the Sails community.
================================================
FILE: docs/contributing/contributors-pledge.md
================================================
# Contributor's pledge
By making a contribution to this project, I certify that:
* (a) The contribution was created in whole or in part by me and I
have the right to submit it under the MIT license; or
* (b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source license
and I have the right under that license to submit that work with
modifications, whether created in whole or in part by me, under the
same open source license (unless I am permitted to submit under a
different license), as indicated in the file; or
* (c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified it.
> The certificate of origin above is based on the "[Developer's Certificate of Origin 1.0](https://github.com/nodejs/node/blob/master/CONTRIBUTING.md#developers-certificate-of-origin-10)" used by Node.js core.
================================================
FILE: docs/contributing/core-maintainers.md
================================================
# Core maintainers
The Sails.js core maintainers constitute a small team of individuals located in Austin, TX who are passionate about making it easier for everyone to develop scalable, secure, custom web applications. We fell in love with Node.js at first sight and are firm believers in the continued, unprecedented dominance of JavaScript as a unifying force for good. We see Node.js as the logical continuation of the web standards movement into the world of server-side development.
The Sails core team maintains the framework and its related sub-projects, including the Waterline ORM, the Node-Machine project, the Skipper body parser, and all officially-supported generators, adapters, and hooks. We rely heavily on the help of a network of contributors and users all over the world, but we make all final decisions about our releases and roadmap.
#### History
Sails.js was originally developed by [Mike McNeil](http://twitter.com/mikermcneil) with the help of his company [Balderdash](http://www.bizjournals.com/sanantonio/blog/socialmadness/2013/03/sxsw-2013-Balderdash-startup-web-app.html), a small development and design studio in Austin, TX. The first stable version of Sails was released as open source in 2012. Today, it is still actively maintained by the same [core team members](https://sailsjs.com/about), along with the help of many amazing [contributors](https://github.com/balderdashy/sails/network/members).
#### Financial Support
Today, Sails.js is financially supported by [The Sails Company](https://sailsjs.com/about) ([YC W15](http://techcrunch.com/2015/03/11/treeline-wants-to-take-the-coding-out-of-building-a-backend/)). Please feel free to [contact us directly](https://sailsjs.com/contact) with questions about the company, our [team](https://sailsjs.com/about), or our mission.
================================================
FILE: docs/contributing/intro-to-custom-adapters.md
================================================
# Introduction to custom adapters for Sails/Waterline
> ##### Stability: Varies
## Reference
Please see the [adapter interface specification](https://github.com/balderdashy/sails/blob/master/docs/contributing/adapter-specification.md).
### What is an adapter?
Adapters expose **interfaces**, which imply a conract to implemnt certain functionality. This allows us to guarantee conventional usage patterns across multiple models, developers, apps, and even companies, making app code more maintainable, efficient, and reliable. Adapters are useful for integrating with databases, open APIs, internal/proprietary web services, or even hardware.
### What kind of things can I do in an adapter?
Adapters are mainly focused on providing model-contextualized CRUD methods. CRUD stands for create, read, update, and delete. In Sails/Waterline, we call these methods `create()`, `find()`, `update()`, and `destroy()`.
For example, a `MySQLAdapter` implements a `create()` method which, internally, calls out to a MySQL database using the specified table name and connection information and runs an `INSERT ...` SQL query.
In practice, your adapter can really do anything it likes-- any method you write will be exposed on the raw datastore objects and any models which use them.
## Why would I need a custom adapter?
When building a Sails app, the sending or receiving of any asynchronous communication with another piece of hardware can be normalized into an adapter. (viz. API integrations)
> **From Wikipedia:**
> *http://en.wikipedia.org/wiki/Create,_read,_update_and_delete*
> Although a relational database provides a common persistence layer in software applications, numerous other persistence layers exist. CRUD functionality can be implemented with an object database, an XML database, flat text files, custom file formats, tape, or card, for example.
In other words, Waterline is not just an ORM for your database. It is a purpose-agnostic, open standard and toolset for integrating with all kinds of RESTful services, datasources, and devices, whether it's LDAP, Neo4J, or [a lamp](https://www.youtube.com/watch?v=OmcQZD_LIAE).
I know, I know... Not everything fits perfectly into a RESTful/CRUD mold! Sometimes the service you're integrating with has more of an RPC-style interface, with one-off method names. That's ok-- you can define any adapter methods you like! You still get all of the trickle-down config and connection-management goodness of Waterline core.
## Why should I build a custom adapter?
To recap, writing your API integrations as adapters is **easier**, takes **less time**, and **absorbs a considerable amount of risk**, since you get the advantage of a **standardized set of conventions**, a **documented API**, and a **built-in community** of other developers who have gone through the same process. Best of all, you (and your team) can **reuse the adapter** in other projects, **speeding up development** and **saving time and money**.
Finally, if you choose to release your adapter as open-source, you provide a tremendous boon to our little framework and our budding Sails.js ecosystem. Even if it's not via Sails, I encourage you to give back to the OSS community, even if you've never forked a repo before-- don't be intimidated, it's not that bad!
The more high-quality adapters we collectively release as open-source, the less repetitive work we all have to do when we integrate with various databases and services. My vision is to make building server-side apps more fun and less repetitive for everyone, and that happens one community adapter at a time.
I tip my hat to you in advance :)
## What is an Adapter Interface?
The functionality of adapters is as varied as the services they connect. That said, there is a standard library of methods, and a support matrix you should be aware of. Adapters may implement some, all, or none of the interfaces below, but rest assured that **if an adapter implements one method in an interface, it should implement *all* of them**. This is not always the case due to limitations and/or incomplete implementations, but at the very least, a descriptive error message should be used to keep developers informed of what's supported and what's not.
##### Class methods
Below, `class methods` refer to the static, or collection-oriented, functions available on the model itself, e.g. `User.create()` or `Menu.update()`. To add custom class methods to your model (beyond what is provided in the adapters it implements), define them as top-level key/function pairs in the model object.
##### Instance methods
`instance methods` on the other hand, (also known as object, or model, methods) refer to methods available on the individual result models themselves, e.g. `User.findOne(7).done(function (err, user) { user.someInstanceMethod(); });`. To add custom instance methods to your model (beyond what is provided in the adapters it implements), define them as key/function pairs in the `attributes` object of the model's definition.
##### DDL and auto-migrations
`DDL` stands for data-definition language, and is a common fixture of schema-oriented databases. In Sails, auto-migrations are supported out of the box. Since adapters for the most common SQL databases support `alter()`, they also support automatic schema migration! In your own adapter, if you write the `alter()` method, the same behavior will take effect. The feature is configurable using the `migrate` property, which can be set to `safe` (don't touch the schema, period), `drop` (recreate the tables every time the app starts), or `alter` (the default-- merge the schema in the apps' models with what is currently in the database).
## Offcially supported adapters
Cody, Mike, and the team behind Sails.js at Balderdash support a handful of commonly used adapters.
### Disk
Write to your computer's hard disk, or a mounted network drive. Not suitable for at-scale production deployments, but great for a small project, and essential for developing in environments where you may not always have a database set up. This adapter is bundled with Sails and works out of the box with zero configuration.
###### Interfaces implemented:
+ Semantic
+ Queryable
+ Streaming
### Memory
Pretty much like Disk, but doesn't actually write to disk, so it's not persistent. Not suitable for at-scale production deployments, but useful when developing on systems with little or no disk space.
###### Interfaces implemented:
+ Semantic
+ Queryable
+ Streaming
### MySQL
MySQL is the world's most popular relational database.
http://en.wikipedia.org/wiki/MySQL
###### Interfaces implemented:
+ Semantic
+ Queryable
+ Streaming
+ Migratable
### PostgreSQL
[PostgreSQL](http://en.wikipedia.org/wiki/PostgreSQL) is another popular relational database.
###### Interfaces implemented:
+ Semantic
+ Queryable
+ Streaming
+ Migratable
### MongoDB
[MongoDB](http://en.wikipedia.org/wiki/MongoDB) is the leading NoSQL database.
###### Interfaces implemented:
+ Semantic
+ Queryable
+ Streaming
### Redis
[Redis](http://redis.io/) is an open source, BSD licensed, advanced key-value store.
###### Interfaces implemented:
+ Semantic
+ Queryable
> Under active development:
>
> + sails-s3
> + sails-local-fs
## Notable Community Adapters
> ##### Stability: Varies
> in various states of completion
Community adapters are crucial to the success and central to the philosophy of an open ecosystem for API integrations. The more high-quality adapters you release as open-source, the less repetitive work we all have to do when we integrate with various databases and services. My vision is to make building server-side apps more fun and less repetitive for everyone, and that happens one community adapter at a time. We welcome your support!
### [Mandrill (email-sending service by MailChimp)](https://github.com/mikermcneil/sails-mandrill)
+ One-Way
### Heroku
> Not currently available as open-source.
### Git
> Not currently available.
### [CouchDB](https://github.com/craveprogramminginc/sails-couchdb)
+ Semantic
### [Riak](https://npmjs.org/package/sails-riak)
+ Semantic
### [REST](https://github.com/zohararad/sails-rest)
+ Semantic
### [IRC](https://github.com/balderdashy/sails-irc)
+ Pubsub
### [Twitter](https://github.com/balderdashy/sails-twitter)
### [ElasticSearch](https://github.com/UsabilityDynamics/waterline-elasticsearch)
+ Semantic
### [JSDom](https://github.com/mikermcneil/sails-jsdom)
### [Yelp](https://github.com/balderdashy/sails-adapter-boilerplate/pull/2)
### [OrientDB](https://github.com/appscot/sails-orientdb)
[OrientDB](http://en.wikipedia.org/wiki/OrientDB) is an Open Source NoSQL DBMS with the features of both Document and Graph DBMSs.
###### Interfaces implemented:
+ Semantic
+ Queryable
+ Associations
+ Migratable
> Search google and NPM for more-- there are new adapters being written all the time.
> Check out the docs to learn how to write your own custom adapter (whether it's a private, internal project for a proprietary API or something you can share as open-source)
> Want to see your adapter listed here? Send a pull request with a link and we'll merge it!
================================================
FILE: docs/contributing/issue-contributions.md
================================================
# Issue contributions
When opening new issues or commenting on existing issues in any of the repositories in this GitHub organization, please make sure discussions are related to concrete technical issues of the Sails.js software. Feature requests and ideas are always welcome, but they should not be submitted as GitHub issues. See [Requesting Features](https://sailsjs.com/documentation/contributing/proposing-features-enhancements) below for submission guidelines.
For general help using Sails, please refer to the [official Sails documentation](https://sailsjs.com/documentation). For additional help, ask a question on [StackOverflow](http://stackoverflow.com/questions/ask) or refer to any of the [other recommended avenues of support](https://sailsjs.com/support).
If you have found a security vulnerability in Sails or any of its dependencies, _do not report it in a public issue_. Instead, alert the core maintainers immediately using the instructions detailed in the [Sails Security Policy](https://sailsjs.com/security). Please observe this request _even for external dependencies not directly maintained by the core Sails.js team_ (e.g. Socket.io, Express, Node.js, or openssl). Whether or not you believe the core team can do anything to fix an issue, please follow the instructions in our security policy to privately disclose the vulnerability as quickly as possible.
Finally, discussion of a non-technical nature, including subjects like team membership, trademark, code of conduct, and high-level questions or concerns about the project should be sent directly to the core maintainers by emailing [inquiries@sailsjs.com](inquiries@sailsjs.com).
#### Opening an issue
> Sails is composed of a number of different sub-projects, many of which have their [own dedicated repository](https://sailsjs.com/architecture). Even so, the best place to submit a suspected issue with a module maintained by the Sails core team is in the main Sails repo. This helps us stay on top of issues and keep organized.
Before submitting an issue, please follow these simple instructions:
First, search for issues similar to yours in [GitHub search](https://github.com/balderdashy/sails/search?type=Issues) within the main Sails repo.
- If your original bug report is covered by an existing open issue, then add a comment to that issue instead of opening a new one.
- If all clearly related issues are closed, then open a new issue and paste links to the URLs of the already closed issue(s) at the bottom.
- If you cannot find any related issues, try using different search keywords, if appropriate (in case this affects how you search, at the time of this writing, GitHub uses ElasticSearch, which is based on Lucene, to index content). If you still cannot find any relevant existing issues, then create a new one.
- Please consider the importance of backlinks. A contributor responding to your issue will almost always need to search for similar existing issues theirself, so having the URLs all in one place is a huge time-saver. Also keep in mind that backlinking from new issues causes GitHub to insert a link to the URL of the new issue in referenced original issues automatically. This is very helpful, since many visitors to our GitHub issues arrive from search engines.
Once you've determined that a new issue should be created,
+ Make sure your new issue does not report multiple unrelated problems.
- If you are experiencing more than one problem—and the problems are clearly distinct—create a separate issue for each one, but start with the most urgent.
- If you are experiencing multiple related problems (problems that you have only been able to reproduce in tandem), then please create only a single issue. Be sure to describe both problems thoroughly, though, as well as the steps necessary to cause them both to appear.
+ Check that your issue has a concise, on-topic title that uses polite, neutral language to explain the problem as best you can in the available space. The ideal title for your issue is one that communicates the problem at a glance.
- For example, _"jst.js being removed from layout.ejs on lift"_ is a **very helpful** title for an issue.
- Here are some **non-examples**—that is, examples of issue titles which are **not helpful**:
- _"templates dont work"_ : This title is too vague. Even if more information cannot be gleaned, wording like _"unexpected behavior with templates"_ is a little more specific and would likely generate a quicker response.
- _"app broken cannot access templates on filesystem because it is broken in the asset pipeline please help"_ : This title is repetative and contains unnecessary content ("_please help_"). Remember that a useful title is both desciptive and concise.
- _"jst.js is being REMOVED!!!!!!!!!"_: This title contains unnecessary capitalization and punctuation, which is distracting at best, and may be perceived as impolite. In either case, it's unlikely to speed the response to your issue.
- _"How does this dumb, useless framework remove jst.js from my app?"_: This title contains unnecessary negativity, which doesn't encourage participant review. Try keeping titles as objective as possible for the best possible issue resolution experience.
- _"Thousands of files being corrupted in our currently deployed production app every time the server crashes."_: Language like this might be perceived as hyperbolic and could lessen the credibility of your claim. In this instance, it may even confuse the issue (e.g. "Is this only happening when NODE_ENV===production?").
+ Before putting together steps to reproduce your issue, normalize as many of the variables on your personal development environment as possible:
- Make sure you have the right app lifted.
- Make sure you've killed the Sails server with CTRL+C and started it again.
- Make sure you do not have any open browser tabs pointed at localhost.
- Make sure you do not have any other Sails apps running in other terminal windows.
- Make sure the app you are using to reproduce the issue has a clean `node_modules/` directory, meaning:
- no dependencies are linked (e.g. you haven't run `npm link foo`)
- you haven't made any inline changes to files in the `node_modules/` folder
- you don't have any weird global dependency loops
The easiest way to double-check any of the above, if you aren't sure, is to run: `rm -rf node_modules && npm cache clear && npm install`.
+ Remember to provide the version of Sails that your app is using (`sails -v`).
- Note that this could be different than the version of Sails you have globally installed.
+ Provide your currently-installed version of Node.js (`node -v`), your version of NPM (`npm -v`), and the operating system that you are running (OS X, Windows, Ubuntu, etc.)
- If you are using `nvm` or another Node version manager like `n`, please be sure to mention that in the issue.
+ Provide detailed steps to reproduce the problem from a clean Sails app (i.e. an app created with `sails new` on a computer with no special environment variables or `.sailsrc` files)
+ Finally, take a moment to think about what you are about to post and how it will be interpreted by the rest of the Sails userbase. Make sure it is aligned with our Code of Conduct, and make sure you are not endangering other Sails users by posting a [security vulnerability](https://sailsjs.com/security) publicly.
Issues which do not meet these guidelines will usually be closed without being read, with a response asking that the submitter review this contribution guide. If this happens to you, _realize that it's nothing personal_, and that it may even happen again. Please understand that Sails is a large project that receives hundreds of new issue submissions every month, and that we truly appreciate the time you donate to post detailed issues. The more familiar you become with the conventions and ground rules laid out in this contribution guide, the more helpful your future contributions will be for the community. You will also earn the respect of core team members and set a good example for future contributors.
> You might think of these rules as guardrails on a beautiful mountain road: they may not always be pretty, and if you run into them you may get banged up a little bit, but, collectively, they keep us all from sliding off a turn and into the abyss.
================================================
FILE: docs/contributing/preface.md
================================================
# Contributing to Sails
This guide is designed to help you get off the ground quickly contributing to Sails. Reading it thoroughly will help you write useful issues, make eloquent proposals, and submit top-notch code that can be merged quickly. Respecting the guidelines laid out here helps make the core maintainers of Sails more productive, and makes the experience of working with Sails positive and enjoyable for the community at large.
If you are working on a pull request, **please carefully read the this guide in its entirety**. In case of doubt, [open an issue on GitHub](https://github.com/balderdashy/sails/issues/new) or contact someone from our [core team](https://sailsjs.com/about) on Twitter. Especially do so if you plan to work on something big. Nothing is more frustrating than seeing your hard work go to waste because your vision does not align with planned or ongoing development efforts of the project's maintainers.
> Note that unless otherwise specified, the content in this section is either straight from the hearts of the Sails.js core team, or based on the [Node.js contribution guide](https://github.com/joyent/node/blob/master/CONTRIBUTING.md#contributing).
================================================
FILE: docs/contributing/proposing-features/proposing-features.md
================================================
# Proposing features and enhancements
Sails contributors have learned over the years that keeping track of feature requests in the same bucket as potentially-critical issues leads to a dizzying number of open issues on GitHub, and makes it harder for the community as a whole to respond to bug reports. It also introduces a categorization burden: Imagine a GitHub issue that is 2 parts feature request, 3 parts question, but also has a _teensie pinch_ of immediately-relevant-and-critical-issue-with-the-latest-stable-version-of-Sails-that-needs-immediate-attention.
If suggestions, requests, or pleas for features or enhancements are submitted as GitHub issues, they will be closed by [sailsbot](http://asksailsbot.tumblr.com/) or one of her lackeys in the Sails core team. This doesn't mean the core team does not appreciate your willingness to share your experience and ideas with us; we just ask that you use our new process. Instead of creating a GitHub issue, please submit your proposal for a new feature or an extension to an existing feature using the process outlined under [Submitting a Proposal](https://sailsjs.com/documentation/contributing/proposing-features-enhancements/submitting-a-proposal).
Please **do not propose _changes to the established conventions or default settings_ of Sails**. These types of discussions tend to start "religious wars" about topics like EJS vs. Jade, Grunt vs. Gulp, Express vs. Hapi, etc., and managing those arguments creates rifts and consumes an inordinate amount of contributors' time. Instead, if you have concerns about the opinions, conventions or default configuration in Sails, please [contact the core maintainers directly](mailto:inquiries@sailsjs.com).
================================================
FILE: docs/contributing/proposing-features/submitting-a-proposal.md
================================================
# Submitting a proposal
Before submitting a new proposal, please consider the following:
Many individuals and companies (large and small) are happily using Sails in production projects (both greenfield and mature) with the currently-released feature set today, as-is. A lot of the reason for this is that Sails was built while the core team was running a development shop, where it was used to take many different kinds of applications from concept to production, and then to serve as the backend for those applications as they were maintained over the next few years.
Much like the canonical case of Ruby on Rails, this means that Sails was designed from the beginning to be both developer-friendly and enterprise-friendly using a convention over configuration methodology. **Conventions** make it quick and easy to build new Sails apps and switch between different existing Sails apps, while **configurability** allows Sails developers to be flexible and customize those apps as they mature using the full power of the underlying tool chain (configuration, plugins/overrides, Express, Socket.io, Node.js, and JavaScript).
Over the first year of Sails's life, the **configurability** requirement became even more important. As the user base grew and Sails started to be used on all sorts of different projects, and by developers with all sorts of different preferences, the number of feature requests skyrocketed. Sails solved this in 2013 by rewriting its core and becoming innately interoperable:
+ Since Sails apps are just Node apps, you can take advantage of any of the [millions](bit.ly/npm-numbers) of NPM packages on http://npmjs.org. (And more recently, you can also take advantage of any of the hundreds of automatically-documented machine functions curated from NPM at http://node-machine.org)
+ Since Sails uses the same req/res/next pattern as Express and Connect, you can take advantage of any middleware written for those middleware frameworks in your app, such as Lusca (security middleware from Paypal) or morgan (HTTP logging util).
+ Since Sails uses [Consolidate](https://github.com/tj/consolidate.js/), you can use any of the view engines compatible with Express such as Jade, Dust or Handlebars.
+ Since Sails uses a familiar MVC project structure, you and/or other developers on your team can quickly get up to speed with how the app works, the database schema, and even have a general notion of where common configuration options live.
+ Since Sails uses Grunt, you can install and use any of the thousands of available Grunt plugins on http://gruntjs.com/plugins in your app.
+ Sails's hook system allows you to disable, replace, or customize large swaths of functionality in your app, including pieces of Sails core, such as replacing Grunt with Gulp.
+ Waterline's adapter interface allows you to plug your models into any database such as Oracle, MSSQL, or Orient DB.
+ Skipper's adapter interface allows you to plug your incoming streaming file uploads into any blob storage container such as S3, GridFS, or Azure.
+ Sails's generator system allow you to completely control all files and folders that the Sails command-line tool generates when you run `sails new` or `sails generate *`.
It is important to realize that today, most (but certainly not all) new features in Sails can be implemented using one or more of the existing plugin interfaces, rather than making a change to core. If the feature you are requesting is an exception to that rule, then please proceed-- but realize that perhaps the most important part of your proposal is a clear explanation of why what you're suggesting is not possible today.
The core maintainers of Sails review all feature proposals, and we do our best to participate in the discussion in these PRs. However, many of these proposals can sometimes involve back and forth discussion that could require them to be open for months at a time. So it is important to understand going in that if you are proposing a feature, the onus is on you to fully specify how that feature would work; i.e. how it would be used, how it would be configured, and in particular its implementation-- that is, which modules would need to change to make it a reality, how it would be tested, whether it would be a major or minor-version breaking change, and the additions and/or modifications that would be necessary to the official Sails documentation.
With that in mind, to submit a proposal for a new feature, or an extension to an existing feature, please take the following steps:
0. First, look at the `backlog` table in [ROADMAP.MD](https://github.com/balderdashy/sails/blob/master/ROADMAP.md) and also search open pull requests in that file to make sure your change hasn't already been proposed.
- If the PR (pull request) has been merged, it means that a core maintainer has (A) looked over the proposal and discussion in the pull request, (B) personally agreed to him or herself that the feature would be a good fit for Sails core, and (C) confirmed the decision with [@mikermcneil](https://github.com/mikermcneil). It also means that the proposal is now in the backlog in ROADMAP.md, which means that the core team would be willing to merge a pull request with code changes adding the feature to Sails core (assuming that pull request follows our coding style conventions and the guidelines in this section).
- If the PR has been closed without being merged, it means that the core team has decided that the feature request should not be a part of Sails core. Just because the proposal is closed does not mean the feature will never be achievable in Sails, it just means that (A) it would need to be specced differently to be merged or (B) it would need to be implemented as a plugin (i.e. a hook, adapter, generator, view engine, grunt/gulp task, etc.)
- If the PR is _open_, it means that either (A) it was recently posted, (B) there is still an active discussion in progress, (C) that a core maintainer has not had time to look into it yet, or most commonly (D) that one or more core maintainers have looked at and potentially even responded to the proposal, but the team decided there wasn't enough information to make a firm "yes" or "no" judgement call. This fourth scenario is quite common, since it sometimes takes a great deal of time to develop a specification that is thorough enough to merge into the backlog. The core maintainers review and contribute to proposals as much as time allows, but ultimately it is the responsibility of the developers requesting a feature to do the work of fully speccing it out.
- While some of Sails's core maintainers carefully filter email from GitHub (because they also like to get other email sometimes), many contributors receive GitHub notifications every time a new comment is posted. Out of respect for them, please do not `*bump*` or `:+1:` feature proposals. Instead, write a concise (3-5 sentences) explanation of your real-world use case for the feature.
1. If it doesn't already exist, create a pull request editing [ROADMAP.MD](https://github.com/balderdashy/sails/blob/master/ROADMAP.md) (the easiest way to do this is opening ROADMAP.md while logged in to GitHub and clicking the "Edit" button).
2. Add a new row to the **Backlog** table with a very short description of the feature, then submit the change as a pull request (the easiest way to do this is to use the GitHub UI as discussed above, make your changes, then follow the on-screen instructions).
3. In the description for your pull request:
- First, write out a high-level summary of the feature you are proposing as a concise description (3-5 sentences) focused around a convincing real-world use case where the Sails app you are building or maintaining for your job, your clients, your company, your non-profit work, or your independent hobby project would be made easier by this feature or change.
- Next, describe in clear prose with relevant links to code files exactly why it would be difficult or impossible to implement the feature without changing Sails core (i.e. using one or more of the existing plugin mechanisms). If this is not the case, and this feature could be implemented as a plugin, then please reconsider writing your proposal (it is unlikely the core team will be able to accept it). If you are the author of one or more plugins, and feel that you or other users would benefit from having your work in Sails core, please contact the core team directly (see the instructions for submitting "high-level questions or concerns about the project" above).
- Finally, if you have time, take a first pass at proposing a spec for this feature (its configuration, usage, and how it would be implemented). If you do not have time to write out a first draft of a thorough specification, please make that point in your feature request, and clarify that it would be up to other contributors with the same or a similar use case to finish this proposal.
Proposals which do not meet these guidelines will be closed with a response asking that the submitter review this contribution guide. If this happens to you, _realize it is nothing personal_ and that it may even happen again. Please consider that a tremendous amount of effort has been put into the existing plugin systems in Sails, and so any proposed change to core must be carefully considered in relation to how it would affect existing plugins, existing apps, and future development of the framework. Many Sails contributors have become intimately familiar with how the various systems in Sails interact and will be willing to help you out; but in order for that process to be efficient, it is important that all new features and enhancements follow a common set of ground rules.
> ###### If your feature proposal is merged...
> Having your proposal merged does not necessarily mean that you are responsible for _implementing_ the feature; and you certainly won't be responsible for _maintaining_ future changes which might affect that feature for all eternity. _That_ privilege is reserved for Mike and the rest of the core team; which is why it is so important to spec out the vision for the usage, configuration, and implementation of your proposed feature from day 1. Working out this sort of a detailed proposal is not an easy task, and often involves more effort than the actual implementation. But if a proposal is accepted, it becomes part of the project's mission: which means once it is implemented and merged, the core team is committed to maintaining it as a part of Sails.
================================================
FILE: docs/contributing/stability-index.md
================================================
# Stability index
Throughout the documentation and in README files in Sails, you will see indications of a section's stability. The Sails framework is still somewhat changing, and as it matures, certain parts are more reliable than others. Some are so proven, and so relied upon, that they are unlikely to ever change at all. Others are brand new and experimental, or known to be hazardous and in the process of being redesigned.
Stability indices are used to describe individual methods, events, and configuration settings _as well_ as sub-modules of Sails core such as core hooks. The latter affordance is a soft science-- the core team labels hooks with stability indices in order to provide a better experience for developers building plugins for Sails and/or contributing to Sails core.
When a stability index refers to a module like a core hook, note that that index refers to the **features of that hook which are _explicitly public_**. For example, if the documentation for a hook mentions that it "exposes" a property called `foo` on the `sails` app object, then you can _only rely on that property_ to respect the hook's the stability level if it is also clearly marked as "public" elsewhere in the hook documentation. If in doubt, submit a pull request to the relevant hook's README file in the [GitHub repository for Sails core](https://github.com/balderdashy/sails) and add a question to the FAQ section.
The stability indices are as follows:
##### Stability: 0 - Deprecated
This feature is known to be problematic, and changes are planned. Do not rely on it in new code, and be sure to change existing code before upgrading. Use of the feature may cause warnings. Backwards compatibility should not be expected.
##### Stability: 1 - Experimental
This feature is subject to change or removal in future major releases of Sails.
##### Stability: 2 - Stable
This feature has proven satisfactory. Compatibility with existing Sails apps and the plugin ecosystem is a high priority, and so stable hooks/features/etc. will not be broken or removed in future major releases unless absolutely necessary.
##### Stability: 3 - Locked
This hook/feature/etc. will not undergo any future API changes, except as demanded by critical fixes related to security or performance. Please do not propose usage/philosophical changes for features/hooks/etc. at this stability index; they will be refused.
### Notes
> - Sails' stability index, and much of the verbiage of this file, is based on [the Stability Index used by Node.js core](https://nodejs.org/api/documentation.html#documentation_stability_index).
================================================
FILE: docs/faq/README.md
================================================
# docs/faq
This section contains the contents that will live on sailsjs.com/faq.
### Notes
> - This README file **is not compiled to HTML** for the website. It is just here to explain what you're looking at.
================================================
FILE: docs/faq/faq.md
================================================
# Frequently Asked Questions
### Table of Contents
1. [I'm having trouble installing Sails. What should I do?](https://sailsjs.com/faq#?im-having-trouble-installing-sails-what-should-i-do)
2. [What are the dependencies of Sails?](https://sailsjs.com/faq#?what-are-the-dependencies-of-sails)
3. [Who else is using Sails.js?](https://sailsjs.com/faq#?who-else-is-using-sailsjs)
4. [Are there professional support options?](https://sailsjs.com/faq#?are-there-professional-support-options)
5. [Where do I get help?](https://sailsjs.com/faq#?where-do-i-get-help)
6. [What are some good community tutorials?](https://sailsjs.com/faq#?what-are-some-good-community-tutorials)
7. [How can I convince the other girls/guys on my team?](https://sailsjs.com/faq#?how-can-i-convince-the-other-girls-guys-on-my-team)
8. [Where do I submit ideas? Report bugs?](https://sailsjs.com/faq#?where-do-i-submit-ideas-report-bugs)
9. [What version of Sails should I use?](https://sailsjs.com/faq#?what-version-of-sails-should-i-use)
10. [How do I get involved?](https://sailsjs.com/faq#?how-do-i-get-involved)
11. [How does the documentation end up on the Sails website?](https://sailsjs.com/faq#?how-does-the-documentation-end-up-on-the-sails-website)
12. [Where is the documentation for the different releases of Sails?](https://sailsjs.com/faq#?where-is-the-documentation-for-the-different-releases-of-sails)
### I'm having trouble installing Sails. What should I do?
Start with NPM's helpful [troubleshooting guide](https://github.com/npm/npm/wiki/Troubleshooting). If you continue to have problems, and you've tried Google searching but you're still stumped, please carefully review the updated Sails [contribution guide](https://sailsjs.com/documentation/contributing) and then create a GitHub issue in the Sails repo.
### What are the dependencies of Sails?
[](https://david-dm.org/balderdashy/sails)
We have learned again and again over the years to take versioning of dependencies very seriously. We lock Sails's dependency versions and only bump those versions if the associated updates fix a security issue or present other substantive advantages to Sails users (improved compatibility, performance, etc.) In addition, the core maintainers of Sails are committed to fixing any major security, performance, or stability bugs that arise in any of our core dependencies-- regardless of whether those modules are [officially maintained by another entity or not](https://github.com/balderdashy/sails/pull/3235#issuecomment-170417122).
Sails is tested with [node](http://nodejs.org/) versions 0.10.x and up, though, we recommend using The latest LTS version of Node. The framework is built on the rock-solid foundations of [Express](https://github.com/expressjs/) and [Socket.io](http://socket.io/). Out of the box, it also depends on other great modules, like `grunt`, `waterline`, and `fs-extra`. Click the badge above for the full list of dependencies in the latest stable release of Sails core.
> **Sails Flagship users:** We manually verify every dependency of Sails and other officially-maintained modules by hand, every single week. This includes core hooks, adapters, generators, client SDKs, and Flagship packages. We regularly send security/compatibility reports about dependencies to the primary email address associated with your account. If you'd like additional people on your team to receive these reports, no problem! Just [let us know](https://flagship.sailsjs.com/ask) their email addresses and we'll get them set up. _(These email addresses will also receive communications about patches, shrinkwrap updates, and compatibility notices.)_
If you have questions or concerns about our dependencies, [talk to a core team member](https://sailsjs.com/contact). _Please do not submit a pull request changing the version of a dependency without first (1) checking that dependency's changelog, (2) verifying compatibility, and (3) [submitting an accompanying PR to update **roadstead**](https://github.com/treelinehq/roadstead/edit/master/constants/verified-releases.type.js), our dependency wallah._
### Who else is using Sails.js?
Sails is used in production by individuals and companies, non-profits, and government entities all over the world, for all sorts of projects (greenfield and mature). You can see some examples [here](https://sailsjs.com/#?using-sails) of companies that have used Sails for their projects. (This small list is definitely not authoritative, so if you're using Sails in your app/product/service, [we'd love to hear about it](https://sailsjs.com/contact)!
### Are there professional support options?
[The Sails Company](https://sailsjs.com/about) offers custom development, services, training, enterprise-class products, and support for teams building applications on Sails.
##### Partner with us
Our studio provides development services for startups, SMBs, and the Fortune 500. As you might expect, the Sails core team has done a lot of custom Sails/Node.js development, but we also have experience across the full stack, including: advanced interaction design, practical/scalable JavaScript development practices for huge applications, and building rich user experiences across many different devices and screen resolutions.
We can build your app and API from scratch, modernize your legacy web platform, or catalyze the development efforts of your established team. If you're interested in working with us on your next project, [drop us a line](https://sailsjs.com/studio#?contact).
##### Sails Flagship for Enterprise
Sails Flagship is a platform on top of Sails which provides a suite of additional services, production-quality accoutrements, and support for enterprise use cases. This includes early access to new features and enhancements, a license for our internal tools, as well as exclusive reports and best-practice guides created by core maintainers. To learn more, [set up a call](https://sailsjs.com/contact) _(or [purchase online now](https://sailsjs.com/flagship/plans))_.
> We are actively expanding this product offering with new additions and official re-releases of some formerly-experimental modules. If you have specific suggestions/requests for new Flagship packages, please [let us know](http://flagship.sailsjs.com/contact).
##### Professional support / SLAs
The Sails Company also provides a lifeline for organizations using Sails to build their products. If you need guaranteed support in the event of a critical production issue, or just want an extra pair of eyes looking out for your code base during development, take a look at our [basic subscriptions](https://sailsjs.com/flagship/plans), or [contact us](https://flagship.sailsjs.com/contact) and we'll give you a call.
### Where do I get help?
Aside from the [official documentation](https://sailsjs.com/documentation), be sure and check out the [recommended support options on the Sails website](https://sailsjs.com/support), and pop in to our [Gitter chat room](https://gitter.im/balderdashy/sails). If you're stumped, make sure and [ask a question on StackOverflow](http://stackoverflow.com/questions/ask), where there's an [active Sails community](http://stackoverflow.com/questions/tagged/sailsjs?sort=newest&days=30). Members of our core team recently taught a [free video course](https://courses.platzi.com/courses/develop-apps-sails-js/) on [Platzi](http://platzi.com) and wrote [a book](https://www.manning.com/books/sails-js-in-action).
> If you're using [Sails Flagship](https://sailsjs.com/faq#?are-there-professional-support-options), you can contact the core team [here](http://flagship.sailsjs.com/ask).
### What are some good community tutorials?
> If you are the author of a tutorial or guide about Sails, please send us a pull request [here](https://github.com/balderdashy/sails/edit/master/docs/faq/faq.md) and we'll check it out. (Be sure to add your tutorial to the top of the applicable list, as we try to order these from newest to oldest.)
##### Multi-part guides:
+ [The busy JavaScript developer's guide to Sails.js](https://www.ibm.com/developerworks/library/wa-build-deploy-web-app-sailsjs-1-bluemix/index.html) -- 4-part series from IBM developerWorks. (Also available in [Chinese](http://www.ibm.com/developerworks/cn/web/wa-build-deploy-web-app-sailsjs-1-bluemix/) and [Japanese](http://www.ibm.com/developerworks/jp/web/library/wa-build-deploy-web-app-sailsjs-1-bluemix/).)
+ [SailsCasts](http://irlnathan.github.io/sailscasts/) - Short screencasts that take you through the basics of building traditional websites, single-page/mobile apps, and APIs using Sails. Perfect for both novice and tenured developers, but does assume some background on MVC.
+ [Sails.js Development channel on Medium](https://medium.com/sails-js-development/)
+ [Sails.js Course on Pluralsight](https://www.pluralsight.com/courses/two-tier-enterprise-app-api-development-angular-sails)
+ Sails API Development
+ [Datalayer -models, connections, waterline](http://www.codeproject.com/Articles/898221/Sails-API-development-Datalayer-models-connections)
+ [Custom methods, overriding default actions, and related](http://www.codeproject.com/Articles/985730/Sails-API-development-2-2-Custom-methods-overriding-default)
+ Desarrollar Webapps Realtime:
+ [Creación](http://jorgecasar.github.io/blog/desarrollar-webapps-realtime-creacion/)
+ [Usuarios](http://jorgecasar.github.io/blog/desarrollar-webapps-realtime-usuarios/)
+ [Auth](http://jorgecasar.github.io/blog/desarrollar-webapps-realtime-auth/)
+ [Auth con Passport](http://jorgecasar.github.io/blog/desarrollar-webapps-realtime-auth-con-passport/)
##### Articles & blog posts:
+ [Nanobox Blog: Getting Started - A Simple Sails.js App](https://content.nanobox.io/a-simple-sails-js-example-app/)
+ [Twitter Dev Blog: Guest Post: Twitter Sign-In with Sails.js](https://blog.twitter.com/2015/guest-post-twitter-sign-in-with-treelineio)
+ [Guest Post on Segment.io Blog: Webhooks with Slack, Segment, and Sails.js/Treeline](https://segment.com/blog/segment-webhooks-slack/)
+ [Postman Blog: Manage your Sails.js server bootstrap code](http://blog.getpostman.com/2015/08/28/manage-your-sailsjs-server-bootstrap-code/)
+ [Sails.js on Heroku](https://vort3x.me/sailsjs-heroku/)
+ [Angular + Sails.js (0.10.0-rc5) with angular-sails socket.io](https://github.com/maartendb/angular-sails-scrum-tutorial/blob/master/README.md)
+ [Angular + Sails! Help!](https://github.com/xdissent/spinnaker) - Sails Resources Service for AngularJS
+ [How to Create a Node.js App using Sails.js on an Ubuntu VPS](https://www.digitalocean.com/community/articles/how-to-create-an-node-js-app-using-sails-js-on-an-ubuntu-vps)
+ [Working With Data in Sails.js](http://net.tutsplus.com/tutorials/javascript-ajax/working-with-data-in-sails-js/) tutorial on NetTuts
##### Video tutorials:
+ [Develop Web Apps in Node.js and Sails.js](https://courses.platzi.com/courses/sails-js/)
+ [Jorge Casar: Introduccion a Sails.js](https://www.youtube.com/watch?v=7_zUNTtXtcg)
+ [Sails.js - How to render node views via Ajax, single page application, SPA](http://www.youtube.com/watch?v=Di50_eHqI7I&feature=youtu.be)
+ [Intro to Sails.js](https://www.youtube.com/watch?v=GK-tFvpIR7c) [@mikermcneil](https://github.com/mikermcneil)'s original screencast
### How can I convince the other girls/guys on my team?
##### Articles / interviews / press releases / whitepapers / talks
> + If you are the author of an article about Sails, please send us a pull request [here](https://github.com/balderdashy/sails/edit/master/docs/faq/faq.md). We'll check it out!
> + If you are a company interested in doing a press release about Sails, please contact [@mikermcneil](https://twitter.com/mikermcneil) on Twitter. We'll do what we can to help.
+ [InfoWorld: Why Node.js beats Java and .Net for web, mobile, and IoT apps](http://www.infoworld.com/article/2975233/javascript/why-node-js-beats-java-net-for-web-mobile-iot-apps.html) _(Speed, scalability, productivity, and developer politics all played a role in [AnyPresence](http://anypresence.com)’s selection of Sails.js/Node.js for its enterprise development platform)_
+ [TechRepublic: Build Robust Applications with the Node.js MVC framework](http://www.techrepublic.com/article/build-robust-node-applications-with-the-sails-js-mvc-framework/)
+ [Microsoft Case Study: Deploying Sails.js to Azure Web Apps](https://blogs.msdn.microsoft.com/partnercatalystteam/2015/07/16/y-combinator-collaboration-deploying-sailsjs-to-azure-web-apps/)
+ [Mike's interview w/ @freddier and @cvander from Platzi](https://www.youtube.com/watch?v=WN0YgPdPbRE)
+ [Smashing Magazine: Sailing with Sails.js](https://www.smashingmagazine.com/2015/11/sailing-sails-js-mvc-style-framework-node-js/)
+ [Presentation at Smart City Conference & Expo 2015](http://www.goodxense.com/blog/post/our-presentation-at-smart-city-conference-expo-2015/) (George Lu & YJ Yang)
+ [Radio interview with Mike McNeil w/ ComputerAmerica's Craig Crossman](https://www.youtube.com/watch?v=ERIvf2iUj5U&feature=youtu.be)
+ Sails.js, Treeline and the future of programming ([Article](https://courses.platzi.com/blog/sails-js-creator-mike-mcneil-on-treeline-and-frameworks/) | [Video](https://www.youtube.com/watch?v=nZKG7hLhbRs) | [Deck](https://speakerdeck.com/mikermcneil/what-even-is-software))
+ [UI-First API Design & Development: Apigee's I ♥ APIs, San Francisco, 2015](https://speakerdeck.com/mikermcneil/i-love-apis)
+ [Choosing the right framework for Node.js development](https://jaxenter.com/choosing-the-right-framework-for-node-js-development-126432.html)
+ [TechCrunch: Our 10 Favorite Companies From Y Combinator Demo Day](https://techcrunch.com/gallery/our-10-favorite-companies-from-y-combinator-demo-day-day-1/slide/11/)
+ [Sails.js used on the website for the city of Paris](https://twitter.com/parisnumerique/status/617999231182176256)
+ [18f Open Source Hack Series: Midas](https://18f.gsa.gov/2014/10/01/open-source-hack-series-midas/)
+ [From Rags to Open Source](https://speakerdeck.com/mikermcneil/all-things-open) (All Things Open, Raleigh, 2014)
+ SxSW Conference, Austin, TX: ([2014](https://speakerdeck.com/mikermcneil/2014-intro-to-sails-v0-dot-10-dot-x) | [2015](https://speakerdeck.com/mikermcneil/sxsw-2015))
+ [More talks by Mike and the Sails.js core team](http://lanyrd.com/profile/mikermcneil/)
+ [Dessarolo Web: Interview w/ Mike McNeil](https://www.youtube.com/watch?v=XMpf44oV2Og) (Spanish & English--English starts at 1:30)
+ [CapitalOne blog: Contrasting Enterprise Node.js Frameworks](http://www.capitalone.io/blog/contrasting-enterprise-nodejs-frameworks/) (by [Azat Mardan](https://www.linkedin.com/in/azatm), author of the book "Pro Express.js")
+ [Alternatives to MongoDB (Chinese article)](http://www.infoq.com/cn/news/2015/07/never-ever-mongodb)
+ [Introducción a Sails.js, un framework para crear aplicaciones realtime](https://abalozz.es/introduccion-a-sails-js-un-framework-para-crear-aplicaciones-realtime/)
+ [Austin startup finds success in responsive design](http://www.bizjournals.com/sanantonio/blog/socialmadness/2013/03/sxsw-2013-Balderdash-startup-web-app.html?ana=twt)
+ [Interact ATX](http://www.siliconhillsnews.com/2013/03/10/flying-high-with-interact-atx-adventures-in-austin-part-3-2-1/)
+ [Intro to Sails.js :: Node.js Conf: Italy, 2014](http://2014.nodejsconf.it/)
+ [Startup America](http://www.prlog.org/12038372-engine-pitches-startup-america-board-of-directors.html)
+ [Recent tweets about Sails.js](https://twitter.com/search?q=treelinehq%20OR%20%40treelinehq%20OR%20%23treelinehq%20OR%20%40waterlineorm%20OR%20treeline.io%20OR%20sailsjs.com%20OR%20github.com%2Fbalderdashy%2Fsails%20OR%20sailsjs%20OR%20sails.js%20OR%20%23sailsjs%20OR%20%40sailsjs&src=typd)
+ [How to use more open source](https://18f.gsa.gov/2014/11/26/how-to-use-more-open-source/) _(18F is an office inside the U.s. General Services Administration that helps other federal agencies build, buy, and share efficient and easy-to-use digital services.)_
+ [Express Web Server Advances in Node.js Ecosystem](https://adtmag.com/articles/2016/02/11/express-joins-node.aspx) ([auch auf Deutsch](http://www.heise.de/developer/meldung/IBM-uebergibt-JavaScript-Webframework-Express-an-Node-js-Foundation-3099223.html))
+ Interview w/ Tim Heckel [on InfoQ](http://www.infoq.com/news/2013/04/Sails-0.8.9-Released)
+ [Sails.js - Une Architecture MVC pour applications real-time Node.js](http://www.lafermeduweb.net/billet/sails-js-une-architecture-mvc-pour-applications-real-time-node-js-1528.html)
+ [Hacker News](https://news.ycombinator.com/item?id=5373342)
+ [Pulling the Plug: dotJS (Paris, 2014)](http://www.thedotpost.com/2014/11/mike-mcneil-pulling-the-plug)
+ [Intro to Sails.js :: Node PDX, Portland, 2013 (Slides)](http://www.slideshare.net/michaelrmcneil/node-pdx))
+ [Sail.js : un framework MVC pour Node.js](http://javascript.developpez.com/actu/52729/Sail-js-un-framework-MVC-pour-Node-js/)
+ [Build Custom & Enterprise Node.js Apps with Sails.js](http://www.webappers.com/2013/03/29/build-custom-enterprise-node-js-apps-with-sails-js/)
+ [New tools for web design and development: March 2013](http://www.creativebloq.com/design-tools/new-tools-web-design-and-development-march-2013-4132972)
+ [Sails 0.8.9: A Rails-Inspired Real-Time Node MVC Framework](http://www.infoq.com/news/2013/04/Sails-0.8.9-Released)
+ [Node.js の MVCフレームワーク Sails.js が良さげなので少し試してみた](http://nantokaworks.com/?p=1101)
+ [InfoWorld: 13 fabulous frameworks for Node.js](http://www.infoworld.com/article/3064653/application-development/13-fabulous-frameworks-for-nodejs.html#slide9)
+ [New web design tools that you need to check out](http://www.designyourway.net/blog/resources/new-web-design-tools-that-you-need-to-check-out/)
+ [Live code Sails.js avec Mike McNeil](http://www.weezevent.com/live-code-sailsjs-avec-mike-mcneil)
+ [#hack4good adds cities and welcomes Sails.js creator to speak and hack in Paris!](http://us2.campaign-archive1.com/?u=cf9af451f2674767755b02b35&id=fb98713f48&e=b2d87b15fe)
+ [TechCrunch: Sails.js Funded by Y-Combinator](http://techcrunch.com/2015/03/11/treeline-wants-to-take-the-coding-out-of-building-a-backend/)
### Where do I submit ideas? Report bugs?
The Sails project tracks bug reports in GitHub issues and uses pull requests for feature proposals. Please read the [contribution guide](https://sailsjs.com/documentation/contributing) before you create an issue, submit a proposal, or begin working on pull request.
### What version of Sails should I use?
[](http://badge.fury.io/js/sails)
Unless you are a contributor running a pre-release version of the framework in order to do some testing or work on core, you should use the latest stable version of Sails from NPM (click the badge above). Installing is easy- just follow [these instructions](https://sailsjs.com/get-started).
> Note: to install/upgrade to the latest version of Sails locally in an existing project, run `npm install sails@latest --save`. If you are having trouble and are looking for a bazooka, you might also want to run `rm -rf node_modules && npm cache clear && npm install sails@latest --force --save && npm install`.
If you are looking to install a pre-release version of Sails, you can install from the `beta` tag on npm (i.e. `npm install sails@beta`). This is a great way to try out a coming release ahead of time and start upgrading before the release becomes official. The beta npm release candidate corresponds with the `beta` branch in the Sails repo. (Just be sure to also use the right version of your favorite adapters and other plugins. If in doubt, [feel free to ask](https://sailsjs.com/support).)
Finally, if you like living on the edge, or you're working on adding a feature or fixing a bug in Sails, install the edge version from the `master` branch on github. The edge version is not published on the registry since it's constantly under development, but you can _still use npm to install it_ (e.g. `npm install sails@git://github.com/balderdashy/sails.git`)
For more instructions on installing the beta and edge versions of Sails, check out the [contribution guide](https://sailsjs.com/documentation/contributing).
### How do I get involved?
There are many different ways to contribute to Sails; for example you could help us improve the [official documentation](https://github.com/balderdashy/sails/tree/master/docs), write a [plugin](https://sailsjs.com/documentation/concepts/extending-sails), answer [StackOverflow questions](http://stackoverflow.com/questions/tagged/sails.js), start a Sails meetup, help troubleshoot GitHub issues, write some tests, or submit a patch to Sails core or one of its dependencies. Please look through the [contribution guide](https://sailsjs.com/documentation/contributing) before you get started. It's a short read that covers guidelines and best practices that ensure your hard work will have the maximum impact.
### How does the documentation end up on the Sails website?
The documentation is compiled from the markdown files in the [`sails` repo on github](https://github.com/balderdashy/sails/tree/master/docs). A number of Sails users have expressed interest in emulating the process we use to generate the pages on the Sails website. Good news is it's pretty simple: The compilation process for the Sails docs involves generating HTML from Markdown files in the sails repo, then performing some additional transformations such as adding data type bubbles, tagging permalinks for individual sections of pages, building JSON data to power the side navigation menu and setting HTML `` attributes for better search engine discoverability of individual doc pages. See the [doc-templater](https://github.com/uncletammy/doc-templater) module for more information.
### Where is the documentation for the different releases of Sails?
The [documentation on the main website](https://sailsjs.com/documentation) is for the latest stable npm release of Sails, and is mirrored by the docs in the [master branch of the `sails` repo on github](https://github.com/balderdashy/sails/tree/master/docs) (Master is sometimes a few commits ahead, but any critical documentation updates make it onto the website within a day or two.)
For older releases of Sails that are still widely used, the documentation is compiled from the relevant `sails-docs` branches and hosted on the following subdomains:
+ [0.12.sailsjs.com](http://0.12.sailsjs.com/)
+ [0.11.sailsjs.com](http://0.11.sailsjs.com/)
================================================
FILE: docs/irc/irc.md
================================================
## Grab An IRC Client
Below you'll find some of the more popular IRC Clients.
### Linux
- [xChat](http://xchat.org)
- [irssi](http://irssi.org)
- [weeChat](http://www.weechat.org)
#### Using apt package manager for Ubuntu/Debian
```
sudo apt-get install weechat
```
### OSX
- [irssi](http://irssi.org)
```
sudo steveJobsPM --prettyPlease install -m 'is this okay?' irssi
```
### Windows
- [xChat](http://xchat.org)
- [hydra IRC](http://www.hydrairc.com/content/downloads)
## Setting Up Your Client
### Registering On Freenode
Our chat room is on the Freenode network. Freenode does not require that you register your `nick` name. You do have the option to though. If you want to do this, read about how to do it [on the freenode website](https://freenode.net/faq.shtml#registering)
### Getting on Freenode
Each IRC Client is a little different to configure. All of the ones we have recommended have very straight forward configuration process. If your client provides a list of available servers, look for the one called Freenode.
Make sure to put in a `nick` to go by.
Upon connecting to the Freenode network, join us by typing `/join #sailsjs`.
If you registered a nick, you can identify yourself with `/msg nickserv identify `
## Getting help on IRC
### `#sailsjs` on irc.freenode.net
If you are looking for a quick answer and you can't find what you're looking for in the docs, come ask in our IRC chat room. While there is typically somebody there who can answer your question, please remember that #sailsjs is 100% community maintained. That means that help is given at the discretion of the community. For best results, be polite and to the point.
If you've never been on IRC, now is the perfect time. Getting started is easy.
## Sails Troll
Sails Troll is our resident IRC Bot. His job is to write down what people say in case someone wants to find it later.
He also informs the room whenever someone pushes up a change to any of the repos in the Sails.js ecosystem.
================================================
FILE: docs/reference/README.md
================================================
# docs/reference
This section contains the official reference documentation for Sails. It is made available at https://sailsjs.com/documentation/reference.
### Notes
> - This README file **is not compiled to HTML** for the website. It is just here to explain what you're looking at.
> - Depending on what branch of `sails` you are currently viewing, the domain may vary. See the top-level documentation README file for information about working with the markdown files in this repo, and to understand the branching/versioning strategy.
================================================
FILE: docs/reference/application/advanced-usage/advanced-usage.md
================================================
# Advanced usage
Most users of the Sails framework will never need to access more than a few basic methods of the `sails` application object. However, if you have an advanced use case or are considering [contributing to Sails](https://sailsjs.com/documentation/contributing), you may need to delve into some of these lesser-used methods or reference the [loading order of Sails core](https://sailsjs.com/documentation/reference/application/advanced-usage/lifecycle).
### Disabling the `sails` global
We recommended using the `sails` global with Sails.
However, the auto-globalization of `sails` [can be disabled](https://sailsjs.com/documentation/reference/configuration/sails-config-globals). Disabling the `sails` global might be a good idea for use cases where multiple Sails app instances need to exist at once, or where globals are not an option.
If the `sails` global is disabled, then you'll need another way to reference the application instance. Luckily, this is possible from almost anywhere in your app:
+ in the `fn` of an [action](https://sailsjs.com/documentation/concepts/actions-and-controllers) (`this.sails`)
+ in the `fn` of a [helper](https://sailsjs.com/documentation/concepts/helpers) (`this.sails`).
+ on an incoming request (`req._sails`)
### Properties (advanced)
##### sails.hooks
A dictionary of all loaded [Sails hooks](https://sailsjs.com/documentation/concepts/extending-sails/hooks), indexed by their _identity_. Use `sails.hooks` to access properties and methods of hooks you've installed to extend Sails—for example, by calling `sails.hooks.email.send()`. You can also use this dictionary to access the Sails [core hooks](https://sailsjs.com/documentation/concepts/extending-sails/hooks#?types-of-hooks), for advanced usage.
By default, a hook's identity is the lowercased version of its folder name, with any `sails-hook-` prefix removed. For example, the default identity for a hook loaded from `node_modules/sails-hook-email` would be `email`, and the hook would be accessible via `sails.hooks.email`. An installed hook's identity can be changed via the [`installedHooks` config property](https://sailsjs.com/documentation/concepts/extending-sails/hooks/using-hooks#?changing-the-way-sails-loads-an-installable-hook).
See the [hooks concept documentation](https://sailsjs.com/documentation/concepts/extending-sails/hooks) for more information about hooks.
##### `sails.io`
The API exposed by the [`sails.sockets.*` methods](https://sailsjs.com/documentation/reference/web-sockets/sails-sockets) is flexible enough out of the box to cover the requirements of most applications, and using them will future-proof your app against possible changes in the underlying implementation. However, if you are working on bringing some legacy code from a vanilla Socket.io app into your Sails app, it can be useful to talk to Socket.io directly. To accomplish this, Sails provides raw access to the underlying [socket.io](http://socket.io/) server instance (`io`) as `sails.io`. See the [Socket.io docs](http://socket.io/docs/) for more information. If you decide to use Socket.io directly, please proceed with care.
> Sails bundles `socket.io` as a dependency of [sails-hook-sockets](github.com/balderdashy/sails-hook-sockets), a core hook.
### Where does the application object come from?
An application instance automatically created _the first time_ you `require('sails')`.
This is what is happening in the generated `app.js` file:
```javascript
var sails = require('sails');
```
Note that any subsequent calls to `require('sails')` return the same app instance. (This is why you might sometimes hear the Sails app instance referred to as a "singleton".)
### Creating a new application object (advanced)
If you are implementing something unconventional (e.g. writing tests for Sails core)
where you need to create more than one Sails application instance in a process, you _should not_ use
the instance returned by `require('sails')`, as this can cause unexpected behavior. Instead, you should
obtain application instances by using the Sails constructor:
```javascript
var Sails = require('sails').constructor;
var sails0 = new Sails();
var sails1 = new Sails();
var sails2 = new Sails();
```
Each app instance (`sails0`, `sails1`, `sails2`) can be loaded/lifted separately,
using different configuration.
For more on using Sails programatically, see the conceptual overview on [programmatic usage in Sails](https://sailsjs.com/documentation/concepts/programmatic-usage).
================================================
FILE: docs/reference/application/advanced-usage/lifecycle.md
================================================
# The Sails app lifecycle
The Sails core has been iterated upon several times to make it easier to maintain and extend. As a result, it has a very particular loading order, which its hooks depend on heavily. This process is summarized below.
### (1) Load configuration "overrides"
Gather the set of configuration values passed in on the command line, in environment variables, and in programmatic configuration (i.e. options passed to [`sails.load`](https://sailsjs.com/documentation/reference/application/sails-load) or [`sails.lift`](https://sailsjs.com/documentation/reference/application/sails-lift)). When an app is started via the command-line interface (by typing `sails lift` or `sails console`), the values of any `.sailsrc` files will also be merged into the config overrides. These override values will take precedence over any user configuration encountered in the next step.
### (2) Load user configuration
Unless the `userconfiguration` hook is explicitly disabled, Sails will next load the configuration files in the `config` folder (and subfolders) underneath the current working directory. See [**Concepts > Configuration**](https://sailsjs.com/documentation/concepts/configuration) for more details about user configuration. Configuration settings from step 1 will be merged on top of these values to form the `sails.config` object.
### (3) Load hooks
Next, Sails will load the other hooks. [Core hooks](https://sailsjs.com/documentation/concepts/extending-sails/hooks#?types-of-hooks) will load first, followed by user hooks and installable hooks. Note that hooks typically include configuration of their own which will be used as _default values_ in `sails.config`. For example, if no `port` setting is configured by this point, the `http` hook's default value of 1337 will be used.
### (4) Assemble router
Sails prepares the core Router, then emits multiple events on the `sails` object informing hooks that they can safely bind routes.
### (5) Expose global variables
After all hooks have initialized, Sails exposes global variables (by default: `sails` object, models, services, `_`, and `async`).
### (6) Initialize app runtime
> This step does not run when `sails.load()` is used programmatically.
> To run the initialization step, use `sails.lift()` instead.
+ Run the bootstrap function (`sails.config.bootstrap`)
+ Start attached servers (by default, Express and Socket.io)
### FAQ
+ What is the difference between `sails.lift()` and `sails.load()`?
+ `lift()` === `load()` + `initialize()`. It does everything `load()` does, plus it starts any attached servers (e.g. HTTP) and logs a picture of a boat.
================================================
FILE: docs/reference/application/advanced-usage/sails.LOOKS_LIKE_ASSET_RX.md
================================================
# sails.LOOKS_LIKE_ASSET_RX
A regular expression designed for use in identifying URL paths that seem like they are _probably_ for a static asset of some kind (e.g. image, stylesheet, `favicon.ico`, `robots.txt`, etc.).
### Usage
```usage
sails.LOOKS_LIKE_ASSET_RX;
```
**Type:** ((RegExp))
> This regex is **by no means foolproof**, and may match URLs too aggressively for some applications. It is just a reasonable approximation made available for convenience.
### Example
To avoid disabling built-in session support for any request to a URL path that ends in `.json`, but still disable sessions for other requests for static assets, you might use the following configuration:
```javascript
// In `config/session.js`
isSessionDisabled: function (req){
if (req.path.match(/\.json$/)) {
// Don't disable sessions.
return;
}
var seemsToWantSomeOtherStaticAsset = !!req.path.match(sails.LOOKS_LIKE_ASSET_RX);
if (seemsToWantSomeOtherStaticAsset) {
// Disable sessions.
return true;
}
// Otherwise, don't disable sessions.
return;
}
```
================================================
FILE: docs/reference/application/advanced-usage/sails.getActions.md
================================================
# sails.getActions()
Return a dictionary of Sails [actions](https://sailsjs.com/documentation/concepts/actions-and-controllers).
```usage
sails.getActions();
```
The result is a flat (i.e. one-level) dictionary where the keys are the kebab-cased, dash-delimited action identities, and the values are the action functions. All actions in the dictionary will have been converted to `req, res` functions at this point, even if they were defined using [actions2 syntax](https://sailsjs.com/documentation/concepts/actions-and-controllers#?actions-2).
================================================
FILE: docs/reference/application/advanced-usage/sails.getBaseUrl.md
================================================
# sails.getBaseUrl()
> ##### _**This method is deprecated and will likely be removed or changed in an upcoming release.**_
> There is no reliable, cross-platform way to automatically detect the external URL of a running Sails app (or any other Node app). Instead, configure your base URL explicitly and save it in [custom configuration](https://sailsjs.com/documentation/reference/configuration/sails-config-custom) (e.g. `sails.config.custom.baseUrl`) that you can reference throughout the app. (This can then be overridden in production, staging, etc. as needed using [environment-dependent configuration](https://sailsjs.com/documentation/concepts/configuration#?environmentspecific-files-config-env).)
Return a (possibly incorrect) best guess of the base URL for this app, based on a combination of user-supplied and default configuration values.
```usage
sails.getBaseUrl();
```
`getBaseUrl()` constructs a URL string by inspecting various configuration values and defaults. For example, if `sails.config.ssl.key` and `sails.config.ssl.cert` both have values, the URL will start with `https://` instead of `http://`. If `sails.config.explicitHost` is not undefined, its value will be used as the domain name, otherwise it will be `localhost`. If `sails.config.port` is not 80 or 443, its value will be appended to the URL as well.
### Usage
_This function does not accept any arguments._
#### Returns
**Type:** ((string))
```javascript
http://localhost:1337
```
### Example
In an email template...
```html
For more information, visit our web site.
```
================================================
FILE: docs/reference/application/advanced-usage/sails.getRouteFor.md
================================================
# sails.getRouteFor()
Look up the first route pointing at the specified target (e.g. `MeController.login`) and return a dictionary containing its method and URL.
```usage
sails.getRouteFor(target);
```
### Usage
| | Argument | Type | Details
|---|--------------------------- | ------------------- |:-----------
| 1 | target | ((string)) | The route target string; e.g. `MeController.login`
#### Returns
**Type:** ((dictionary))
```javascript
{
method: 'post',
url: '/auth/login'
}
```
### Example
In a controller action...
```javascript
return res.view('pages/some-page-with-a-form-on-it', {
formEndpoint: sails.getRouteFor('SomeotherController.someAction'),
// ...
});
```
So that in the rendered view...
```ejs
```
### Notes
> - This function searches the Sails app's explicitly configured routes; [`sails.config.routes`](https://sailsjs.com/documentation/reference/configuration/sails-config-routes). Shadow routes bound by hooks (including [blueprint routes](https://sailsjs.com/documentation/reference/blueprint-api#?blueprint-routes)) will not be matched.
> - If a matching target cannot be found, this function throws an `E_NOT_FOUND` error (i.e. if you catch the error and check its `code` property, it will be the string `E_NOT_FOUND`).
> - If more than one route matches the specified target, the first match is returned.
> - If you only need the URL for a route (e.g. to use as an `href` from within one of your views), you may want to use [`sails.getUrlFor()`](https://sailsjs.com/documentation/reference/application/sails-get-url-for) instead of this function.
================================================
FILE: docs/reference/application/advanced-usage/sails.lift.md
================================================
# sails.lift()
Lift a Sails app programmatically.
> This does exactly what you might be used to seeing by now when you run `sails lift`. It [loads](https://sailsjs.com/documentation/reference/application/sails-load) the app, runs its bootstrap, then starts listening for HTTP requests and WebSocket connections. Useful for building top-to-bottom integration tests that rely on HTTP requests, and for building higher-level tooling on top of Sails.
```usage
sailsApp.lift(configOverrides, function (err) {
});
```
_Or:_
+ `sailsApp.lift(function (err) {...});`
### Usage
| | Argument | Type | Details |
|---|:--------------------|----------------------------------------------|:-----------------------------------|
| 1 | _configOverrides_ | ((dictionary?)) | A dictionary of config that will override any conflicting options present in configuration files. If provided, this will be merged on top of [`sails.config`](https://sailsjs.com/documentation/reference/configuration).
##### Callback
| | Argument | Type | Details |
|---|:--------------------|---------------------|:---------------------------------------------------------------------------------|
| 1 | _err_ | ((Error?)) | An error encountered while lifting, or `undefined` if there were no errors.
### Example
```javascript
var Sails = require('sails').constructor;
var sailsApp = new Sails();
sailsApp.lift({
log: { level: 'warn' }
}, function (err) {
if (err) {
console.log('Error occurred lifting Sails app:', err);
return;
}
// --•
console.log('Sails app lifted successfully!');
});
```
### Notes
> - The difference between [`.lift()`](https://sailsjs.com/documentation/reference/application/sails-lift) and [`.load()`](https://sailsjs.com/documentation/reference/application/sails-load) is that `.lift()` takes the additional steps of (1) running the app's [bootstrap](https://sailsjs.com/documentation/reference/configuration/sails-config-bootstrap) (if any), and (2) emitting the `ready` event. The core `http` hook will typically respond to the `ready` event by starting an HTTP server on the port configured via `sails.config.port` (1337 by default).
> - When a Sails app is fully lifted, it also emits the [`lifted` event](https://sailsjs.com/documentation/concepts/extending-sails/hooks/events).
> - With the exception of `NODE_ENV` and `PORT`, [configuration set via environment variables](https://sailsjs.com/documentation/concepts/configuration#?setting-sailsconfig-values-directly-using-environment-variables) will not automatically apply to apps started using `.lift()`, nor will options set in [`.sailsrc` files](https://sailsjs.com/documentation/concepts/configuration/using-sailsrc-files). If you wish to use those configuration values, you can retrieve them via `require('sails/accessible/rc')('sails')` and pass them in as the first argument to `.lift()`.
================================================
FILE: docs/reference/application/advanced-usage/sails.load.md
================================================
# sails.load()
Load a Sails app into memory, but without lifting an HTTP server.
_Useful for writing tests, command-line scripts, and scheduled jobs._
```usage
sailsApp.load(configOverrides, function (err) {
});
```
_Or:_
+ `sailsApp.load(function (err) {...});`
#### Usage
| | Argument | Type | Details |
|---|:--------------------|----------------------------------------------|:-----------------------------------|
| 1 | _configOverrides_| ((dictionary?)) | A dictionary of config that will override any conflicting options present in configuration files. If provided, this will be merged on top of [`sails.config`](https://sailsjs.com/documentation/reference/configuration).
##### Callback
| | Argument | Type | Details |
|---|:--------------------|---------------------|:---------------------------------------------------------------------------------|
| 1 | _err_ | ((Error?)) | An error encountered while loading, or `undefined` if there were no errors.
### Example
```javascript
var Sails = require('sails').constructor;
var sailsApp = new Sails();
sailsApp.load({
log: {
level: 'error'
}
}, function (err) {
if (err) {
console.log('Error occurred loading Sails app:', err);
return;
}
// --•
console.log('Sails app loaded successfully!');
});
```
### Notes
> - This takes care of loading configuration files, initializing hooks (including the ORM), and binding routes. It **does not** run the bootstrap, and it **does not** start listening for HTTP requests and WebSocket connections.
> - More specifically, the difference between [`.lift()`](https://sailsjs.com/documentation/reference/application/sails-lift) and [`.load()`](https://sailsjs.com/documentation/reference/application/sails-load) is that `.lift()` takes the additional steps of (1) running the app's [bootstrap](https://sailsjs.com/documentation/reference/configuration/sails-config-bootstrap) (if any), and (2) emitting the `ready` event. The core `http` hook will typically respond to the `ready` event by starting an HTTP server on the port configured via `sails.config.port` (1337 by default).
> - Even though a "loaded-but-not-lifted" Sails app does not listen for requests on an HTTP port, you can make "virtual" requests to it using [`sails.request`](https://sailsjs.com/documentation/reference/application/sails-request)
> - For an example of this in practice, see [machine-as-script](https://github.com/treelinehq/machine-as-script/blob/ec8972137489afd24562bdf0b6a10ada11e540cc/index.js#L778-L791).
> - With the exception of `NODE_ENV` and `PORT`, [configuration set via environment variables](https://sailsjs.com/documentation/concepts/configuration#?setting-sailsconfig-values-directly-using-environment-variables) will not automatically apply to apps started using `.load()`, nor will options set in [`.sailsrc` files](https://sailsjs.com/documentation/concepts/configuration/using-sailsrc-files). If you wish to use those configuration values, you can retrieve them via `require('sails/accessible/rc')('sails')` and pass them in as the first argument to `.load()`.
================================================
FILE: docs/reference/application/advanced-usage/sails.lower.md
================================================
# sails.lower()
Shut down a lifted Sails app and have it cease listening for or responding to any future requests.
```usage
sails.lower(callback);
```
### Usage
| | Argument | Type | Details
|---| --------------------------- | ------------------- | -----------
| 1 | _`callback`_ | ((function?)) | Optional. A function to call when lowering is complete (or if an error occurs)
##### Callback
| | Argument | Type | Details |
|---|-----------|:------------:|---------|
| 1 | _`err`_ | ((Error?)) | An error instance will be sent as the first argument of the callback if any fatal errors occurred while lowering.
### Example
```javascript
sailsApp.lower(
function (err) {
if (err) {
return console.log("Error occurred lowering Sails app: ", err);
}
console.log("Sails app lowered successfully!");
}
)
```
### Notes
> + The app will emit the `lower` event before shutting down the HTTP and WebSocket services.
> + Lowered apps cannot be lifted again.
================================================
FILE: docs/reference/application/advanced-usage/sails.registerAction.md
================================================
# sails.registerAction()
Register a new Sails [action](https://sailsjs.com/documentation/concepts/actions-and-controllers) that can then be bound to a route.
```usage
sails.registerAction(action, name);
```
While actions are mainly registered automatically when the files in an app’s `api/controllers` folder are loaded, you can use the `registerAction()` method to add a new action programmatically. This is especially useful in custom [hooks](https://sailsjs.com/documentation/concepts/extending-sails/hooks), in situations where you want to provide a new action but let the app developer determine the route to bind the action to, or when you want to ensure that policies and other [action middleware](https://sailsjs.com/documentation/reference/application/sails-register-action-middleware) apply to your action.
### Usage
| | Argument | Type | Details
|---|--------------------------- | ------------------- |:-----------
| 1 | action | ((function)) or ((dictionary)) | Either a [classic action](https://sailsjs.com/documentation/concepts/actions-and-controllers#?classic-actions) (aka `(req, res)`) function or an [actions2](https://sailsjs.com/documentation/concepts/actions-and-controllers#?actions-2) definition.
| 2 | identity | ((string)) | The identifier for the action. This is the string that will be used to reference the action elsewhere in an app, for instance when [binding the action to a route](http://sailsjs.com/documentation/concepts/routes/custom-routes#?standalone-action-target-syntax).
================================================
FILE: docs/reference/application/advanced-usage/sails.registerActionMiddleware.md
================================================
# sails.registerActionMiddleware()
> ##### _**This feature is still experimental.**_
> This method is still under development, and its interface and/or behavior could change at any time.
Register a new action middleware function that will be applied to actions with the specified identities.
```usage
sails.registerActionMiddleware(actionMiddlewareFns, actionIdentities);
```
Action middleware functions are essentially [policies](https://sailsjs.com/documentation/concepts/policies#?writing-your-first-policy) that you declare programmatically (rather than via [sails.config.policies](https://sailsjs.com/documentation/reference/configuration/sails-config-policies)). In fact, policies are implemented under-the-hood using action middleware. The `registerActionMiddleware()` method is mainly useful in [custom hooks](https://sailsjs.com/documentation/concepts/extending-sails/hooks) as a way of adding new policies to an app.
### Usage
| | Argument | Type | Details
|---|--------------------------- | ------------------- |:-----------
| 1 | actionMiddlewareFns | ((function)) or ((array)) | One or more middleware functions to register. Action middleware (like policies) must be functions which accept `req`, `res` and `next` arguments.
| 2 | actionIdentities | ((string)) | An expression that indicates the action or actions that the action middleware should apply to. Use `*` at the end for a wildcard; e.g. `user/*` will apply to any actions whose identities begin with `user/`. Use a ! at the beginning to indicate that the action middleware should NOT apply to the actions specified by the expression, e.g. `!user/foo` or `!user/*`. Multiple identity expressions can be specified by separating with a comma, e.g. `pets/count,user/*,!user/tickle`
> The `actionIdentities` argument expects the identities to be expressed as if they were [standalone actions](https://sailsjs.com/documentation/concepts/actions-and-controllers#?standalone-actions). To apply action middleware to actions inside of a controller file (e.g. `UserController.js`), simply refer to the lower-cased version of the filename _without "Controller"_ (e.g. `user`).
### Example
As an example of action middleware that might be applied in a custom hook, imagine a page view counter (this code might be added to the `initialize` method of the hook):
```javascript
// Declare a local var to hold the number of views for each URL.
var pageViews = {};
// Register middleware to record each page view.
sails.registerActionMiddleware(
// First argument is the middleware to run
function countPage (req, res, next) {
// Initialize the page counter to zero if this is the first time we've seen this URL.
pageViews[req.url] = pageViews[req.url] || 0;
// Increment the page counter.
pageViews[req.url]++;
// Add the current page count to the request, so that it can be used in other middleware / actions.
req.currentPageCount = pageViews[req.url];
// Continue to the next matching middleware / action
next();
},
// Second argument is the actions to apply the middleware to. In this case, we want the
// hook to apply to all actions EXCEPT the `show-page-views` action supplied by this hook.
'*, !page-view-hook/show-page-views'
);
```
================================================
FILE: docs/reference/application/advanced-usage/sails.reloadActions.md
================================================
# sails.reloadActions()
> ##### _**This feature is still experimental.**_
> This method is still under development, and its interface and/or behavior could change at any time.
Flush and reload all Sails [actions](https://sailsjs.com/documentation/concepts/actions-and-controllers)
```usage
sails.reloadActions(cb);
```
_Or:_
+ `sails.reloadActions(options, cb)`
This method causes hooks to run their `registerActions()` methods if they have them. After the hooks are finished reloading / re-registering their actions, actions in the `api/controllers` folder (including those stored in [controller files](https://sailsjs.com/documentation/concepts/actions-and-controllers#?controllers)) are reloaded and merged on top of those loaded via hooks.
This method is useful primarily in development scenarios.
### Usage
| | Argument | Type | Details
|---|--------------------------- | ------------------- |:-----------
| 1 | _options_ | ((dictionary?)) | Currently accepts one key, `hooksToSkip`, which if given should be an array of names of hooks that should _not_ call their `reloadActions` method.
| 2 | _callback_ | ((function)) | A callback to be called with the virtual response.
### Notes
> - Never dynamically replace your Sails.js controller or action files on disk with untrusted code at runtime, regardless of whether you are using `.reloadActions()` in your app or not. Since `reloadActions()` runs the code in your Sails.js app's files, if the files are not safe to run, then using `reloadActions()` would be [a security risk](https://github.com/balderdashy/sails/issues/7209). This risk is only present if your Sails app is deliberately overwriting its own files to replace them with unsafe code.
================================================
FILE: docs/reference/application/advanced-usage/sails.renderView.md
================================================
# sails.renderView()
> ##### _**This feature is still experimental.**_
> This method is still under development, and its interface and/or behavior could change at any time.
Compile a view into an HTML template.
```usage
sails.renderView(pathToView, templateData);
```
### Usage
| | Argument | Type | Details
|---|--------------------------- | ------------------- |:-----------
| 1 | pathToView | ((string)) | The path to the view that will be compiled into HTML.
| 2 | _templateData_ | ((dictionary?)) | The dynamic data to pass into the view.
### Example
To compile an HTML template with a customized greeting for the recipient:
```javascript
var htmlEmailContents = await sails.renderView('emails/signup-welcome', {
fullName: inputs.fullName,
// Don't include the Sails app's default layout in the rendered template.
layout: false
});
```
================================================
FILE: docs/reference/application/advanced-usage/sails.request.md
================================================
# sails.request()
> ##### _**This feature is still experimental.**_
> This method is still under development, and its interface and/or behavior could change at any time.
Make a virtual request to a running Sails instance.
```usage
sails.request(request);
```
_Or:_
+ `sails.request(url, body)`
+ `sails.request(url, callback)`
+ `sails.request(url, body, callback)`
This method can be used on instances that have been started with [`sails.load()`](https://sailsjs.com/documentation/reference/application/sails-load) and that are not actively listening for HTTP requests on a server port. This makes `sails.request()` useful for testing scenarios where running [`sails.lift()`](https://sailsjs.com/documentation/reference/application/sails-lift) is not necessary. However, it should be noted that the data may not be processed in exactly the same way as an HTTP request; in particular, a much simpler body parser will be employed, and Express middleware such as the static asset server will not be used.
### Usage
| | Argument | Type | Details
|---|--------------------------- | ------------------- |:-----------:
| 1 | request (or url) | ((string)) -or- ((dictionary)) | The virtual request to make. If specified as a string, this should be an address containing an optional method and a path, e.g. `/foo` or `PUT /user/friend`. If specified as an object, it should have one or more of the properties described in the "request argument" section below.
| 2 | _body_ | ((json?)) | (optional) A JSON-serializable value to use as the request body. This argument will override the `data` property of the `request` argument, if provided.
| 3 | _callback_ | ((function?)) | (optional) A callback to be called with the virtual response.
#### Request object
If the `request` argument is specified as an object, it can have the following properties:
| Property | Type | Example | Details
|--------------------------- | ------------------- | ------- | :-----------:
| url | ((string)) | `"/foo"`, `"PUT /user/friend"` | (required) The route in the Sails app to make a request to, with an optional HTTP method prefix
| method | ((string)) | `"GET"`, `"POST"` | (optional) The HTTP method to use in the request. This will override any method supplied as part of the `url` property.
| headers | ((dictionary)) | `{'content-type': 'application/json'}` | (optional) Dictionary of headers to use in the virtual request.
| data | ((json)) | `{foo:'bar'}`, `12345` | ((optional)) Data to send along with the request. For `GET`, `HEAD` and `DELETE` requests, the data will be serialized into a querystring and added to the URL. Otherwise, it will be sent as-is as the request body.
#### Callback
| | Argument | Type | Details
|---|--------------------------- | ------------------- |:-----------
| 1 | _err_ | ((Error?)) | If the response was unsuccessful (status code was not in the 200-399 range) this will be an object containing `status` and `body` properties. If the response was successful, this will be `null`.
| 2 | response | ((dictionary)) | If the response was successful, this will be an object containing the full server response.
| 3 | body | ((json)) | If the response was successful, this will be the value of `response.body`.
#### Returns
**Type:** ((stream))
The full virtual request stream object. This is a readable stream.
================================================
FILE: docs/reference/application/application.md
================================================
# Application (`sails`)
The Sails application object contains all relevant runtime state for a Sails application.
By default, it is exposed globally as `sails` and accessible almost anywhere in your code.
> Most users of the framework will only need to know about the `sails` application object in order to access a few basic methods and their custom configuration. Less commonly used methods can be found in the [advanced usage](https://sailsjs.com/documentation/reference/application/advanced-usage) section.
### Properties
The application object has a number of useful methods and properties.
The officially supported methods on the `sails` object are covered by the other
pages in this section. Here are a few of its most useful properties:
##### sails.models
A dictionary of all loaded [Sails models](https://sailsjs.com/documentation/concepts/models-and-orm/models), indexed by their _identity_.
By default, a model's identity is the lowercased version of its filename, without the **.js** extension. For example, the default identity for a model loaded from `api/models/PowerPuff.js` would be `powerpuff`, and the model would be accessible via `sails.models.powerpuff`. A model's identity can be customized by setting an `identity` property in its module file.
##### sails.helpers
A dictionary of all accessible [helpers](https://sailsjs.com/documentation/concepts/helpers), including organics.
##### sails.config
The full set of configuration options for the Sails instance, loaded from a combination of environment variables, `.sailsrc` files, user-configuration files, and defaults. See the [configuration concepts section](https://sailsjs.com/documentation/concepts/configuration) for a full overview of configuring Sails, and the [configuration reference](https://sailsjs.com/documentation/reference/configuration) for details on individual options.
##### sails.sockets
A set of convenience methods for low-level interaction with connected websockets. See the [`sails.sockets.*` reference section](https://sailsjs.com/documentation/reference/web-sockets/sails-sockets) for details.
### Advanced usage
For more options and implementation details (including instructions for programmatic usage) see [Advanced usage](https://sailsjs.com/documentation/reference/application/advanced-usage).
================================================
FILE: docs/reference/application/sails.config.custom.md
================================================
# sails.config.custom
The runtime values of your app's [custom configuration settings](https://sailsjs.com/documentation/reference/configuration/sails-config-custom).
### Usage
```usage
sails.config.custom;
```
### Example
In an action or helper:
```javascript
sails.config.custom.mailgunApiKey;
// -> "key-testkeyb183848139913858e8abd9a3"
```
### Notes
> + For information on how to set custom configuration in the first place, see [Reference > Config > sails.config.custom](https://sailsjs.com/documentation/reference/configuration/sails-config-custom).
================================================
FILE: docs/reference/application/sails.getDatastore.md
================================================
# sails.getDatastore()
Access a particular [datastore](https://sailsjs.com/documentation/concepts/models-and-orm#?datastores), or the default datastore.
```usage
sails.getDatastore(datastoreName);
```
### Usage
| | Argument | Type | Details
|---|---------------------------- | ------------------- |:-----------
| 1 | datastoreName | ((string?)) | If specified, this is the name of the datastore to look up. Otherwise, if you leave this blank, this `getDatastore()` will return the default datastore for your app.
#### Returns
**Type:** ((Dictionary))
A [datastore instance](https://sailsjs.com/documentation/reference/waterline-orm/datastores).
================================================
FILE: docs/reference/application/sails.getUrlFor.md
================================================
# sails.getUrlFor()
Look up the first route pointing at the specified target (e.g. `entrance/view-login`) and return its URL.
```usage
sails.getUrlFor(target);
```
### Usage
| | Argument | Type | Details
|---|---------------------------- | ------------------- |:-----------
| 1 | target | ((string)) | The route target string; e.g. `entrance/view-login` or `PageController.login`
##### Returns
**Type:** ((string))
```javascript
'/login'
```
### Example
In a view...
```ejs
LoginSignup
```
Or, if you're using traditional controllers:
```ejs
LoginSignup
```
### Notes
> - This function searches the Sails app's explicitly configured routes, [`sails.config.routes`](https://sailsjs.com/documentation/reference/configuration/sails-config-routes). Shadow routes bound by hooks (including [blueprint routes](https://sailsjs.com/documentation/reference/blueprint-api#?blueprint-routes)) will not be matched.
> - If a matching target cannot be found, this function throws an `E_NOT_FOUND` error (i.e. if you catch the error and check its `code` property, it will be the string `E_NOT_FOUND`).
> - If more than one route matches the specified target, the first match is returned.
> - The HTTP method (or "verb") from the route address is ignored, if relevant.
================================================
FILE: docs/reference/application/sails.log.md
================================================
# sails.log()
Log a message or some data at the "debug" [log level](https://sailsjs.com/documentation/reference/configuration/sails-config-log) using Sails' [built-in logger](https://sailsjs.com/documentation/concepts/logging).
```usage
sails.log(...);
```
### Usage
This function's usage is purposely very similar to Node's [`console.log()`](https://nodejs.org/api/console.html#console_console_log_data), but with a handful of extra features—namely support for multiple log levels with colorized, prefixed console output.
Note that standard `console.log()` conventions from Node.js apply:
- takes an [unlimited number](https://en.wikipedia.org/wiki/Variadic_function) of arguments, separated by commas
- printf-style parameterization (à la [`util.format()`](https://nodejs.org/api/util.html#util_util_format_format))
- objects, dates, arrays, and most other data types are pretty-printed using the built-in logic in [`util.inspect()`](https://nodejs.org/api/util.html#util_util_inspect_object_options) (e.g. you see `{ pet: { name: 'Hamlet' } }` instead of `[object Object]`.)
- if you log an object with a custom `inspect()` method, that method will run automatically, and the string that it returns will be written to the console.
### Example
```javascript
var sum = +req.param('x') + +req.param('y');
sails.log();
sails.log('Hey %s, did you know that the sum of %d and %d is %d?', req.param('name'), +req.param('x'), +req.param('y'), sum);
sails.log('Bet you didn\'t know robots could do math, huh?');
sails.log();
sails.log('Anyways, here is a dictionary containing all the parameters I received in this request:', req.allParams());
sails.log('Until next time!');
return res.ok();
```
### Notes
> - For a deeper conceptual exploration of logging in Sails, see [concepts/logging](https://sailsjs.com/documentation/concepts/logging).
> - Remember that, in addition to being exposed as an alternative to calling `console.log` directly, the built-in logger in Sails is called internally by the framework. The Sails logger can be configured, or completely overridden, using built-in log configuration settings ([`sails.config.log`](https://sailsjs.com/documentation/reference/configuration/sails-config-log)).
> - Keep in mind that, like any part of Sails, `sails.log` is completely optional. Most—but not all—Sails apps take advantage of the built-in logger: some users prefer to stick with `console.log()`, while others `require()` more feature-rich libraries like [Winston](https://www.npmjs.com/package/winston). If you aren't sure what your app needs yet, start with the built-in logger and go from there.
================================================
FILE: docs/reference/blueprint-api/Add.md
================================================
# Add (blueprint)
Add a foreign record (e.g. a comment) to one of this record's collections (e.g. "comments").
```usage
PUT /:model/:id/:association/:fk
```
This action adds a reference to some other record (the "foreign", or "child" record) onto a particular collection of this record (the "primary", or "parent" record).
+ If the specified `:id` does not correspond with a primary record that exists in the database, this responds using `res.notFound()`.
+ If the specified `:fk` does not correspond with a foreign record that exists in the database, this responds using `res.notFound()`.
+ If the primary record is already associated with this foreign record, this action will not modify any records. (Note that currently, in the case of a many-to-many association, it _will_ add duplicate junction records! To resolve this, add a multi-column index at the database layer, if possible. We are currently working on a friendlier solution/default for users of MongoDB, sails-disk, and other NoSQL databases.)
+ Note that if the association is "2-way" (meaning it has `via`), then the foreign key or collection it points to with that `via` will also be updated on the foreign record.
### Parameters
Parameter | Type | Details
:-----------------------------------| --------------------------------------- |:---------------------------------
model | ((string)) | The [identity](https://sailsjs.com/documentation/concepts/models-and-orm/model-settings#?identity) of the containing model for the parent record.
e.g. `'employee'` (in `/employee/7/involvedinPurchases/47`)
id | ((string)) | The desired parent record's primary key value.
e.g. `'7'` (in `/employee/7/involvedInPurchases/47`)
association | ((string)) | The name of the collection attribute.
e.g. `'involvedInPurchases'`
fk | ((string)) | The primary key value (usually id) of the child record to add to this collection.
e.g. `'47'`
### Example
Add purchase #47 to the list of purchases that Dolly (employee #7) has been involved in:
```
PUT /employee/7/involvedInPurchases/47
```
[](https://www.getpostman.com/run-collection/96217d0d747e536e49a4)
##### Expected response
This returns "Dolly", the parent record. Notice she is now involved in purchase #47:
```json
{
"id": 7,
"name": "Dolly",
"createdAt": 1485462079725,
"updatedAt": 1485476060873,
"involvedInPurchases": [
{
"amount": 10000,
"createdAt": 1485476060873,
"updatedAt": 1485476060873,
"id": 47,
"cashier": 7
}
]
}
```
##### Using jQuery
```javascript
$.put('/employee/7/involvedInPurchases/47', function (purchases) {
console.log(purchases);
});
```
##### Using Angular
```javascript
$http.put('/employee/7/involvedInPurchases/47')
.then(function (purchases) {
console.log(purchases);
});
```
##### Using sails.io.js
```javascript
io.socket.put('/employee/7/involvedInPurchases/47', function (purchases) {
console.log(purchases);
});
```
##### Using [cURL](http://en.wikipedia.org/wiki/CURL)
```bash
curl http://localhost:1337/employee/7/involvedInPurchases/47 -X "PUT"
```
### Socket notifications
If you have WebSockets enabled for your app, then every client [subscribed](https://sailsjs.com/documentation/reference/web-sockets/resourceful-pub-sub) to the primary record will receive a notification in which the notification event name is the primary model identity (e.g. `'employee'`), and the message has the following format:
```usage
id: ,
verb: 'addedTo',
attribute: ,
addedIds:
```
For instance, continuing the example above, all clients subscribed to Dolly, aka employee #7, (_except_ for the client making the request) would receive the following message:
```javascript
{
id: 7,
verb: 'addedTo',
attribute: 'involvedInPurchases',
addedIds: [ 47 ]
}
```
**Clients subscribed to the child record receive an additional notification:**
Assuming `involvedInPurchases` had a `via`, then either `updated` or `addedTo` notifications would also be sent to any clients who were [subscribed](https://sailsjs.com/documentation/reference/web-sockets/resourceful-pub-sub) to purchase #47, the child record we just added.
> If the `via`-linked attribute on the other side is [also plural](https://sailsjs.com/documentation/concepts/models-and-orm/associations/many-to-many) (e.g. `cashiers`), then another `addedTo` notification will be sent. Otherwise, if the `via` [points at a singular attribute](https://sailsjs.com/documentation/concepts/models-and-orm/associations/one-to-many) (e.g. `cashier`) then the [`updated` notification](https://sailsjs.com/documentation/reference/blueprint-api/update#?socket-notifications) will be sent.
**Finally, a third notification might be sent:**
If adding this purchase to Dolly's collection would "steal" it from another employee's `involvedInPurchases`, then any clients subscribed to that other, stolen-from employee record (e.g. Motoki, employee #12) would receive a `removedFrom` notification (see [**Blueprints > remove from**](https://sailsjs.com/documentation/reference/blueprint-api/remove-from#?socket-notifications).
### Notes
> + If you'd like to spend some more time with Dolly, a more detailed walkthrough related to the example above is available [here](https://gist.github.com/mikermcneil/e5a20b03be5aa4e0459b).
> + This action is for dealing with _plural_ ("collection") attributes. If you want to set or unset a _singular_ ("model") attribute, just use [update](https://sailsjs.com/documentation/reference/blueprint-api/update) and set the foreign key to the id of the new foreign record (or `null` to clear the association).
> If you want to completely _replace_ the set of records in the collection with another set, use the [replace](https://sailsjs.com/documentation/reference/blueprint-api/replace) blueprint.
> + The example above assumes "rest" blueprints are enabled, and that your project contains at least an 'Employee' model with attribute: `involvedInPurchases: {collection: 'Purchase', via: 'cashier'}` as well as a `Purchase` model with attribute: `cashier: {model: 'Employee'}`. You can quickly achieve this by running:
>
> ```shell
> $ sails new foo
> $ cd foo
> $ sails generate model purchase
> $ sails generate model employee
> ```
>
> ...then editing `api/models/Purchase.js` and `api/models/Employee.js`.
================================================
FILE: docs/reference/blueprint-api/Create.md
================================================
# Create (blueprint)
Create a new record in your database.
```usage
POST /:model
```
Responds with a JSON dictionary representing the newly created instance. If a validation error occurred, a JSON response with the invalid attributes and a `400` status code will be returned instead.
Additionally, if the [`autoWatch` setting](https://sailsjs.com/documentation/reference/configuration/sails-config-blueprints?properties) is on (which it is by default), then a "created" notification will be published to all client sockets which are _watching_ this model; that is, client sockets who have previously sent a request to the "Find" blueprint action. Those same sockets will also be subscribed to hear about subsequent changes to the new record.
Finally, if this blueprint action is triggered via a socket request, then the requesting socket will ALSO be subscribed to the newly created record. In other words, if the record is subsequently updated or deleted using blueprints, a message will be sent to that client socket informing them of the change. See [`.subscribe()`](https://sailsjs.com/documentation/reference/web-sockets/resourceful-pub-sub/subscribe) for more info.
### Parameters
Parameters should be sent in the [request body](https://www.getpostman.com/docs/requests#body). By default, Sails understands the most common types of encodings for body parameters, including url-encoding, form-encoding, and JSON.
Parameter | Type | Details
-------------- | --------------------------------------------------------- |:---------------------------------
model | ((string)) | The [identity](https://sailsjs.com/documentation/concepts/models-and-orm/model-settings#?identity) of the model in which the new record should be created.
e.g. `'purchase'` (in `POST /purchase`)
_*_ | ((json?)) | Send [body parameters](https://www.getpostman.com/docs/requests#body) with the same names as the attribute defined on your model to set those values on your new record.