-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathsails.express.txt
526 lines (466 loc) · 34.1 KB
/
sails.express.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
┏━━━━━━━━━━━┓
┃ SAILS ┃
┗━━━━━━━━━━━┛
VERSION ==> #0.10.1
GOAL ==> #MVC web framework on top of Express. Provides:
# - simpler routing declaration, and blueprints routes
# - MVC architecture helper (directory hierarchy)
# - easy integration of Waterline
EXPRESS 4 ==> #Based on Express 3.4.3. Support for Express 4 will come later.
#Careful:
# - redefine all SAILS_VAR.config.middleware, because it relies on EXPRESS.*
# Try not to modify "router" nor "404|500"
# - REQ.is():
# - a bit different. Use TYPE-IS to get Express 4 behavior
# - can also use REQ.wantsJSON() BOOL that checks Accepts [C] but also Content-Type [C] and
# X-Requested-With [C]
# - RES.sendFile -> RES.sendfile
#Careful but might not be needed:
# - APP.use() can't use PARAM
# - APP.mountpath -> APP.route
# - no APP.route()
# - APPVAR "query parser"
┌──────────────┐
│ STARTING │
└──────────────┘
sails new PROJECT #Creates ./PROJECT/ and populates it.
#Some stuff to change/remove:
# - package.json dependencies, except sails
# - Gruntfile.js + tasks, assets/*, api/policies/sessionAuth.js: remove
# - views/*: replace by Handlebars
# - app.js: main file
SAILS.lift #Starts. OBJ is SAILS_VAR.config (should use RC("sails")), which will also be populated by
(OBJ[,FUNC(ERROR, SAILS_VAR)])#config/ (see below)
#SAILS_VAR is also available globally as sails
SAILS.on("lifted", FUNC()) #Ready event
SAILS.lower([FUNC()]) #Closes SAILS_VAR
SAILS.on
("lowering|lower", FUNC()) #
SAILS_VAR.isLifted #BOOL
TESTING ==> #Should do SAILS_VAR.lift() in before() and SAILS_VAR.lower() in after()
#Can test separately: controllers, models, e2e routing, responses, services
SAILS_VAR.hooks.http.server #Underlying HTTP.SERVER
SAILSVAR.router._privateRouter#Underlying Express APP
SAILS_VAR.config.local #Used for settings that should not be comitted (using .gitignore):
# - explicitHost (def: "localhost")
# - port (def: ENVVAR PORT or 1337)
# - proxyHost|Port: make sure returned base URL is the one from proxy not localhost
# - environment (def: ENVVAR NODE_ENV (def: "development")): don't forget to set it correctly
# - any other, e.g. credentials
SAILS_VAR.config.ssl #If HTTPS, OBJ passed to HTTPS.createServer()
┌────────────┐
│ CONFIG │
└────────────┘
SAILS_VAR.config #Loaded by RC but also merges any Node module in config/:
# - e.g. config/http.js, with module.exports.http = OBJ2 -> SAILS_VAR.config.http = OBJ2
SAILS_VAR.config.paths #Configure usual paths with:
# - config: config/
# - views: views/
# - controllers: api/controllers/
# - policies: api/policies/
# - responses : api/responses/
# - services: api/services/
# - hooks: api/hooks/
# - tmp: .tmp/
# - public: .tmp/public/
#All prepended by SAILS_VAR.config.appPath
┌────────────┐
│ MODELS │
└────────────┘
api/models/MODEL.js #Node module exporting TABLEOBJ
#Waterline will:
# - WATERLINE_VAR.loadCollection(WATERLINE.Collection.extend(TABLEOBJ))
# - WATERLINE_VAR.initialize
# ({ connections: SAILS_VAR.config.connections, defaults: SAILS_VAR.config.models })
# - ADAPTER_STR is automatically require(ADAPTER_STR)
#Models are then available at:
# - global variable MODEL (same case) (or TABLEOBJ.globalId if exists)
# - SAILS_VAR.models.MODEL (lowercase)
┌─────────────┐
│ ROUTING │
└─────────────┘
SAILS_VAR.config.routes #Defines a route (like APP.METHOD())
["[METHOD ]PATH"] #PATH is like Express but can also be "r|REGEXP|[PARAM...]" where PARAM... are replaced by
#parenthesis groups in REGEXP
#Value can be:
# - URL: redirection. Can be with protocol (absolute) or without (relative to current app)
# - ROUTE_OBJ:
# - controller [DIR.../]CONTROLLER_STR and action ACTION_STR,
# or directly "[DIR.../]CONTROLLER_STR.ACTION_STR" STR:
# - fires api/controllers/[DIR.../]CONTROLLERController.js,
# which is module.exports = { ACTION(REQ, RES) ... }
# - view PATH and locals OBJ2:
# - fires RES.view(PATH, OBJ2[, FUNC(ERROR, STR)]), which is like RES.render(...) except:
# - uses "views/PATH.EXT" based on:
# - SAILS_VAR.config.views.engine.fn (should use CONSOLIDATE.FUNC)
# - and SAILS_VAR.config.views.engine.ext (e.g. ".hdb")
# - APP.locals is SAILS_VAR.config.views.locals
# - careful: OBJ2 is not only locals, can also include cache, partials, helpers
# (see CONSOLIDATE)
# - response FUNC: RES.FUNC() (see below)
# - skipRegex REGEXP:
# - if matches REGEXP (partial match), do no take that route
# - goal is to avoid matching paths that were targetting something else (e.g. static
# assets), e.g. with catch-all paths like "/:PARAM/:PARAM2"
# - skipAssets true: like skipRegex /\./
# - ROUTE_OBJ is passed to REQ.options, including any other member
┌────────────────┐
│ BLUEPRINTS │
└────────────────┘
DEFAULT ==> #Create default routes and ACTION for each api/controllers/[DIR.../]CONTROLLERController.js
DEFAULT ROUTES ==> #Enabled by SAILS_VAR.config.blueprints.actions|rest|shortcuts true
#(def, but only rest should be used)
#Be:
# - APIPATH: [/PREFIX]/[DIR.../]CONTROLLER, where PREFIX is SAILS_VAR.config.blueprints.prefix
# (def: "")
# - CONTPATH: same without PREFIX
#Types of routes:
# - actions:
# - "/APIPATH/[ACTION]": "CONTPATH.ACTION" (def ACTION: "index")
# - rest:
# - "get /APIPATH/": "CONTPATH.find"
# - with ROUTE_OBJ.populate true
# - "get /APIPATH/:id": "CONTPATH.findOne"
# - with ROUTE_OBJ.populate true
# - "post /APIPATH/": "CONTPATH.create"
# - "post /APIPATH/:id": "CONTPATH.update"
# - "delete /APIPATH/:id?": "CONTPATH.destroy"
# - "get /APIPATH/:parentid/CONTROLLER2_VAR/:id?": "CONTPATH.populate"
# - ROUTE_OBJ.alias CONTROLLER2
# - "put /APIPATH/:parentid/CONTROLLER2_VAR/:id?": "CONTPATH.add"
# - ROUTE_OBJ.alias CONTROLLER2
# - "delete /APIPATH/:parentid/CONTROLLER2_VAR/:id?": "CONTPATH.remove"
# - ROUTE_OBJ.alias CONTROLLER2
# - shortcuts:
# - same as RESTful routes except:
# - uses CONTROLLER/verb/ instead of HTTP method:
# "find|find|create|update|destroy|add|remove"
# - no populate
DEFAULT ACTION ==> #Notes:
# - api/models/CONTROLLER.js must exist
# - 400 errors if wrong QUERY_OBJ, 404 if wrong ID
#Be:
# - MODEL is CONTROLLER
# - REQ.params: query variables, request body variables or route params
# - ALL_OBJ: REQ.params or ROUTE_OBJ
# - ID: REQ.params.id or ROUTE_OBJ.where.id
# - "first check": findOne() first operation to check that a record exist
# - "last return": findOne() last operation to check that a record is updated, and returns it
#ACTION of MODELController.js:
# - find: MODEL.find(OBJ):
# - OBJ:
# - where|limit|skip|sort in ALL_OBJ (not others)
# - can be OBJ2 instead of where: OBJ2, but in REQ.params only
# - limit: defaults to SAILS_VAR.config.blueprints.defaultLimit (def: 30)
# - does populate(STR[_ARR], { limit: UINT }):
# - if ROUTE_OBJ.populate true, all
# - or REQ.params.populate STR[_ARR]
# - UINT is by lowest priority:
# - same as limit above
# - ROUTE_OBJ.populate_limit
# - ROUTE_OBJ.populate_STR_limit
# - if ID -> findOne() instead of find()
# - findOne: MODEL.findOne(ID), then populate(...) (like find())
# - create: MODEL.create(REQ.params):
# - can forbid some with ROUTE_OBJ.values.blacklist STR_ARR
# - status code 201
# - calls MODEL.toJSON()
# - update: MODEL.update(ID, REQ.params):
# - first check: findOne(ID), last return: findOne(ID)
# - destroy: MODEL.destroy(ID):
# - first check: findOne(ID)
# - populate: MODEL.findOne(REQ.params.parentid).populate(ROUTE_OBJ.alias, OBJ):
# - OBJ like find()
# - add: ROW_OBJ[ROUTE_OBJ.alias].add(OBJ) then ROW_OBJ.save():
# - OBJ:
# - if ID, new empty record if not exist, existing one returned otherwise
# - otherwise, OBJ = REQ.params
# - last return: findOne(REQ.params.parentid).populate(ROUTE_OBJ.alias)
# - remove: ROW_OBJ[ROUTE_OBJ.alias].remove(ID) then ROW_OBJ.save():
# - first check: findOne(REQ.params.parentid)
# - last return: findOne(REQ.params.parentid).populate(ROUTE_OBJ.alias)
┌─────────────────┐
│ MIDDLEWARES │
└─────────────────┘
SAILS_VAR.config.http. #MIDWR. Can be custom one, or redefine already existing one.
middleware.MIDWR_STR #Must be registered in SAILS_VAR.config.http.middleware.order
SAILS_VAR.config. #MIDWR_STR_ARR applied to every HTTP request.
http.middleware.order #Default MIDWR_STR_ARR:
# - "startRequestTimer": REQ._startTime = new Date() (not if APPVAR "env" "production")
# - "cookieParser":
# - COOKIE-PARSER(SAILS_VAR.config.session.secret)
# - secret is automatically generated by sails new PROJECT
# - "session": EXPRESS-SESSION(SAILS_VAR.config.session)
# - "bodyParser": SKIPPER():
# - like MULTIPARTY() + BODY-PARSER.urlencoded() but:
# - uses file adapters, a bit like Waterline adapters but for file uploads (on disk, on
# S3, etc.)
# - does lazy loading: does not load a file if not specified as argument, and does not
# save on tmp dir unless specified
# - still in beta, so prefer not to use it
# - "compress": COMPRESSION()
# - "methodOverride": METHOD-OVERRIDE()
# - "poweredBy": adds X-Powered-By: Sails [C]
# - "$custom": for backward compatibility
# - "router": APP.router (Express 3)
# - "www": EXPRESS.static("./tmp/public/", { maxAge: SAILS_VAR.config.cache.maxAge })
# (def: 1 if "development", 1 year if "production")
# - "favicon": SERVE-FAVICON() for .tmp/public/favicon.ico
# - "404": uses RES.notFound()
# - "500": uses RES.negotiate()
api/policies/POLICY_STR.js #Middleware fired on specific controllers|routes.
#Is module.exports = MIDWR(REQ,RES,NEXT)
#Fired just before "router" on:
# - controllers: SAILS_VAR.config.policies.CONTROLLER.ACTION POLICY_STR[_ARR]
# - ACTION or CONTROLLER.ACTION can be '*':
# - Only one set of policies always taken with priority (lowest to highest):
# - "*": MIDWR_STR[_ARR]
# - CONTROLLER: { "*": POLICY_STR[_ARR] }
# - CONTROLLER: { ACTION: POLICY_STR[_ARR] }
# - can use false instead of POLICY_STR[_ARR], firing RES.forbidden().
# Used with '*' to only allow specified ACTION
# - routes:
# - in SAILS_VAR.config.routes["[METHOD ]PATH"], use OBJ_ARR instead of ROUTE_OBJ:
# - { policy: POLICY_STR }... ROUTE_OBJ
# - fires POLICY_STR MIDWR before proceeding to ROUTE_OBJ
┌───────────┐
│ HOOKS │
└───────────┘
SAILS_VAR.config.bootstrap #Fired before SAILS_VAR.lift()
(FUNC()) #Good for middlewares that need to be initialized.
api/hooks/FILE.js #module.exports = FUNC(SAILS_VAR)-> OBJ, with members:
# - configure()|initialize(FUNC2()):
# - fired at SAILS_VAR.lift()
# - FUNC2() is for async, and must be returned too
# - configure is fired before, and is usually reading SAILS_VAR.config
# - routes:
# - before|after:
# - PATH_STR: MIDWR(REQ,RES,NEXT), added to underlying EXPRESS routing
#Not useful (can use SAILS_VAR.config.bootstrap or POLICY_STR)
┌───────────────┐
│ RESPONSES │
└───────────────┘
api/responses/FUNC.js #Function that sends a standard response:
# - is module.exports = FUNC(...)
# - can use this.req|res REQ|RES
# - can be called as RES.FUNC(...)
#403|404|500.ejs are default views available at views/, but uses .ejs and indicates server is
#Sails-based (bad for sniffing). Should redefine them as Handlebars.
#RES.notFound() and RES.negotiate() are called by error handler middlewares in standard stack.
RES.notFound([OBJ[, STR]]) #Uses RES.view(STR (def: "404"), { data: OBJ }) or, if REQ.wantsJSON, RES.json(OBJ).
#OBJ is cleared if APPVAR "env" "production"
#OBJ is usually ERROR.
#Sets 404 status code
RES.ok|badRequest|forbidden| #Same but with 200|400|403|500
serverError(...) #200|400 does not have a default "200|400" view (must provide STR), unless sending JSON
RES.negotiate(ERROR) #Calls RES.forbidden|notFound|badRequest|serverError(ERROR) according to ERROR.status
┌──────────────┐
│ SERVICES │
└──────────────┘
api/services/OBJ_VAR.js #Becomes available globally as OBJ_VAR
#For functions shared accross controllers.
_ #Link to lo-dash (can also use SAILS_VAR.utils._)
async #Link to ASYNC
SAILS_VAR.__ #Link to I18N.__
#I18N is automatically loaded:
# - can use REQ.__[n], RES.locals.*, but not I18N.__n() nor I18N.getLocale()
# - uses SAILS_VAR.config.i18n as OPT_OBJ with defaults:
# - directory: "./" + SAILS_VAR.config.i18n.localesDirectory (def: "config/locales")
# - defaultLocale "en"
# - locales [ "en", "es", "fr", "de" ]
# - ext: ".json"
# - updateFiles: false
# - cookie: null
SAILS_VAR.config.globals #Can be:
# - OBJ:
# - "sails|_|async|adapters|models|services": false, to disable a specific global var
# - false: to disable all globals
┌──────────────┐
│ SECURITY │
└──────────────┘
SAILS_VAR.config.cors #CORS support:
# - allRoutes BOOL: if false (def), needs to do ROUTE_OBJ.cors:
# - OBJ2: same members as SAILS_VAR.config.cors
# - BOOL: true uses SAILS_VAR.config.cors, false disallows
# - origin (def: "*")
# - methods (def: "GET,POST,PUT,DELETE,OPTIONS,HEAD")
# - headers "HEADER,...": exposed headers
# - credentials BOOL (def: true)
#As opposed to CORS, does not have support for preflight requests caching.
SAILS_VAR.config.csrf #If SAILS_VAR.config.csrf.protectionEnabled true (def), uses CONNECT.csrf() (similar to CSURF).
#TOKEN can be sent:
# - as { _csrf: TOKEN } when visiting "/csrfToken", if SAILS_VAR.config.csrf.grantTokenViaAjax
# true (def)
# - SAILS_VAR.config.csrf.origin "DOMAIN,..." (def: ""): allowed to access "/csrfToken"
# - using RES.locals._csrf (put in <input type="hidden" name="_csrf" value="{{_csrf}}">)
#If SAILS_VAR.config.csrf BOOL, use default accept|reject values.
┌────────────────┐
│ WEBSOCKETS │
└────────────────┘
SERVER-SIDE ==> #Uses version 0.9.*
#Otherwise, the whole thing is still unstable.
SAILS.io #Underlying SIO, automatically created with path /socket.io/1/websocket
SAILS.sockets #Wrapper around SAILS.io (prefer)
SAILS.sockets.id(REQ|SV_WS) #Returns SOCKETID (SV_WS.id)
SAILS.sockets.emit
(SOCKETID[_ARR][, EVENT_STR],
VAL) #Def. EVENT_STR is "message"
SAILS.sockets.broadcast(ROOM #Like to(ROOM).broadcast.emit()
[, EVENT_STR], VAL[, SV_WS]) #SV_WS is omitted from broadcast.
SAILS.sockets.blast #Like broadcast.emit()
([EVENT_STR, ]VAL[, SV_WS]) #SV_WS is omitted from broadcast.
SAILS.sockets.join|leave
(SV_WS[.id][_ARR], ROOM) #
SAILS.sockets.rooms() #All ROOM_ARR
SAILS.sockets.socketRooms
(SV_WS) #ROOM_ARR
SAILS.sockets.subscribers
(ROOM[, BOOL]) #If true, returns ARR of SV_WS instead of SOCKETID
SAILS.config.sockets # - on[Dis]Connect(REQ.session, SV_WS) event handlers
# - other options used by SOCKET.IO 0.9:
# - adapter
# - transports
# - origins
# - hearbeats, etc. (ping timeout)
# - logs
# - resource: SOCKET.IO path (def: "/socket.io")
# - authorization BOOL|FUNC(REQ, FUNC2(ERROR, BOOL)):
# - handshake authorization (def: false)
# - if true, checks for "sails.sid=SESSIONID" in query variable cookie or header
# cookie [C], and check SESSIONID is a signed cookie.
# - can set up to disable Websockets alltogether: FUNC(REQ, FUNC2(null, false))
CLIENT-SIDE ==> #
sails.io.js #Client web script. Similar to IO client for SOCKET.IO (actually includes it)
#Must (client-side):
# - specify io.sails.url = DOMAIN
# - specify io.sails.environment = "production" to disable logs if production.
# Automatically done if sails.io.js is ending with .min.js or #production
#Must (server-side)
# - enable CORS on DOMAIN/__getcookie (does not seem to actually do anything)
IO #Underlying SOCKET.IO IO
IO.socket #Underlying CL_WS.
IO.socket.on
(EVENT_STR, FUNC(VAL)) #
IO.socket.request(URL, OBJ2, #Send binary packet OBJ:
[,FUNC(OBJ5, OBJ4)], METHOD) # - name METHOD (must be uppercase)
# - args OBJ_ARR:
# - method METHOD
# - url URL
# - data VAL
# - headers OBJ
#This will be routed like a HTTP request by Sails server, but:
# - response is sent as callback packet OBJ5 (OBJ4.toPOJO()), where OBJ4:
# - statusCode UINT
# - headers OBJ
# - body STR
# - toPOJO()->OBJ4 without methods
# - toString()->"[ResponseFromSails] --Status: UINT --Headers: OBJ --Body: STR"
# - use OBJ2 as query variables or request body -> params.all()
# - use fake|limited versions of REQ|RES:
# - REQ:
# - like HTTP:
# - param(STR), params.all()
# - protocol (always "ws"), method, url
# - ip (uses X-Forwarded-For), port
# - session
# - wantsJSON
# - unlike HTTP:
# - socket SV_WS
# - isSocket true
# - RES:
# - like HTTP:
# - redirect(): simulate another request
# - send(), json()
# - charset
# - get|set()
# - status()
# - unlike HTTP:
# - socket SV_WS
# - broadcast(ROOM, VAL): like socket.broadcast.to(ROOM).json.send(VAL)
# - To allow both HTTP and Websockets: use common REQ|RES methods only.
# - HTTP middlewares don't apply
IO.socket.get|post|put|delete
(...) #Same as IO.socket.request(..., "GET|etc.")
ANGULAR-SAILS ==> #Changes sails.io.js (must be loaded) for Angular:
# - MODULE "ngSails"
# - SERVICE $sails.get:
# - like IO.socket (only for get|put|post|delete|on())
# - but returns Q PROMISE instead of callback
# - $sailsProvider.url: like io.sails.url
CSRF ==> #Works for websocket routing too
MODEL EVENTS ==> #Can broadcast events when a MODEL rows are modified (NEW_ROW_OBJ)
#Event is "MODEL". It is fired by:
# - MODEL.publishCreate(NEW_ROW_OBJ[, REQ]):
# - if REQ, event does not target REQ.socket
# - message: { id ID, verb "created", data NEW_ROW_OBJ }
# - MODEL.publishUpdate(ID[, NEW_ROW_OBJ][, REQ][, OBJ])
# - OBJ:
# - previous OLD_ROW_OBJ
# - message: { id ID, verb "updated", data NEW_ROW_OBJ, previous OLD_ROW_OBJ }
# - MODEL.publishDestroy(ID[, REQ][, OBJ])
# - OBJ: previous OLD_ROW_OBJ
# - message: { id ID, verb "destroyed", previous OLD_ROW_OBJ }
# - MODEL.publishAdd|Remove(ID, CONTROLLER2_VAR, ID2[, REQ])
# - message:
# { id ID, verb "addedTo|removedFrom", attribute CONTROLLER2_VAR, removed|addedId ID2 }
# - MODEL.message(NEW_ROW_OBJ, OBJ[, REQ]):
# - custom message
# - message: { id ID, verb "messaged", data OBJ }
#It is only broadcasted to the SV_WS that are in room:
# - "sails_model_MODEL_ROWID:ACTION":
# - must MODEL.[un]subscribe(REQ|SV_WS, [NEW_]ROW_OBJ[_ARR][, ACTION[_ARR]])
# - ACTION is "update|destroy" or "add|remove:ID2"
# - def: MODEL.autosubcribe (i.e. TABLEOBJ.autosubcribe)
# - if MODEL.autosubcribe true, all
# - "sails_model_create_MODEL":
# - special case for create (since there are no rows yet)
# - muse MODEL.[un]watch(REQ|SV_WS)
SAILS.sockets. #All MODEL.publish* also send event "firehose" with same message but:
[un]subscribeToFirehose() # - property model MODEL
# - verb is without final d
#Only sent if:
# - APPVAR "env" is "development"
# - in ROOM "sails_firehose" (using subscribeToFirehose())
# Can make a Websocket GET request to /firehose to call subscribeToFirehose()
BLUEPRINTS ==> #The blueprints default actions automatically publish model events of modified rows:
# - only when modifying using Websockets routing
# - not publish to modifying client itself (unless SAILS.config.blueprints.mirror true)
# - automatically do publish* on blueprints events
# - also subscribe (including foreign keys):
# - all but destroy -> subscribe(REQ, ROW_OBJ[_ARR])
# - find -> watch(REQ) (unless SAILS.config.blueprints.autoWatch false)
# - create -> subscribe(REQ, ROW_OBJ[_ARR]), for current REQ but also all clients that called
# MODEL.watch()
# - destroy -> unsubscribe(REQ, ROW_OBJ[_ARR]), for current REQ but also all clients that
# called MODEL.watch()
┌──────────┐
│ LOGS │
└──────────┘
SAILS_VAR.log #Points to CAPTAINS-LOG (0.11.11), a small module used as this:
# - LOGGER = CAPTAINS-LOG({ custom: OBJ }) //Any OBJ with OBJ.LEVEL(...), e.g. Winston LOGGER
# - LOGGER.LEVEL(...)
#Uses SAILS_VAR.config.log:
# - level STR (def: "info")
# - custom OBJ
┌──────────────┐
│ NOT USED │
└──────────────┘
assets/ #Processed by Grunt and served by EXPRESS.static().
#Since I don't want either, I can still use this directory with Gulp + ST
GRUNT ==> #GRUNT:
# - fires all files in assets/ with module.exports = FUNC(GRUNT) in:
# - "tasks/config/TASK.js": should setup plugin, including GRUNT.task.loadTasks()
# - "tasks/register/TASK.js": should GRUNT.task.registerTask()
#Run TASK:
# - sails lift: "default"
# - sails lift --prod: "prod"
# - sails www: "build"
# - sails www --prod: "buildProd"
#Prefer using Gulp (remove "tasks/" and Gruntfile.js)
sails lift #Command line. Does npm start.
#Default main file does SAILS_VAR.lift(RC("sails")), so can pass command line args.
--prod #Changes ENVVAR NODE_ENV
--port PORT #Changes ENVVAR PORT
--verbose|silly #
sails console #Does sails lift then starts REPL
sails debug #Like sails lift but does npm debug which by def. does node --debug