@projectinvicta/nails 2.0.15 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/README.md +70 -84
  2. package/bin/test/test_init.sh +33 -0
  3. package/index.ts +11 -0
  4. package/lib/Controller.ts +207 -0
  5. package/lib/Nails.ts +210 -0
  6. package/lib/Router.ts +180 -0
  7. package/lib/{application.js → application.ts} +8 -3
  8. package/lib/config.ts +74 -0
  9. package/package.json +14 -11
  10. package/spec/controller.spec.js +5 -51
  11. package/spec/nails.spec.js +1 -0
  12. package/spec/router.spec.js +5 -5
  13. package/spec/services/integration/config/db.ts +7 -0
  14. package/spec/services/integration/config/service.js +8 -8
  15. package/spec/services/integration/server/controllers/classbased_controller.js +2 -2
  16. package/spec/services/integration/server/controllers/default_json_controller.js +19 -7
  17. package/spec/services/integration/server/controllers/error_controller.js +2 -2
  18. package/spec/services/integration/server/controllers/home_controller.js +6 -28
  19. package/spec/services/integration/server/controllers/json_controller.js +2 -2
  20. package/spec/services/integration/server/controllers/manualrenderasync_controller.js +2 -2
  21. package/spec/services/integration/server/controllers/mjs_controller.mjs +2 -6
  22. package/spec/services/integration/server/controllers/modeltest_controller.js +6 -9
  23. package/spec/services/integration/server/controllers/websocket_controller.js +1 -1
  24. package/spec/services/integration/server/models/dog.js +7 -5
  25. package/spec/services/integration/server/models/owner.js +13 -0
  26. package/spec/services/integration/server.js +3 -4
  27. package/spec/services.integration.spec.js +45 -17
  28. package/templates/default/config/db.ts +13 -0
  29. package/{spec/services/integration_sequelize/config/mimes.js → templates/default/config/mimes.ts} +42 -61
  30. package/templates/default/config/routes.ts +22 -0
  31. package/templates/{config/service.js → default/config/service.ts} +2 -2
  32. package/templates/default/package.json +8 -2
  33. package/templates/default/public/README.xml +68 -85
  34. package/templates/default/server/controllers/home_controller.js +2 -2
  35. package/templates/{server/controllers/home_controller.js → default/server/controllers/users_controller.ts} +29 -34
  36. package/templates/default/server/models/Dog.ts +8 -0
  37. package/templates/default/server/models/User.ts +14 -0
  38. package/templates/default/spec/User.test.js +7 -5
  39. package/templates/default/spec/home_controller.test.js +3 -3
  40. package/index.js +0 -6
  41. package/lib/collection.js +0 -6
  42. package/lib/controller.js +0 -182
  43. package/lib/database_connector.js +0 -12
  44. package/lib/firebase_connector.js +0 -94
  45. package/lib/model_v2.js +0 -24
  46. package/lib/mongoose_connector.js +0 -49
  47. package/lib/mongoose_mem_connector.js +0 -21
  48. package/lib/nails.js +0 -244
  49. package/lib/router.js +0 -202
  50. package/lib/sequelize_connector.js +0 -31
  51. package/lib/server.js +0 -1
  52. package/spec/model_v2.spec.js +0 -75
  53. package/spec/mongodb_connector.util.js +0 -30
  54. package/spec/mongoose_connector.util.js +0 -20
  55. package/spec/sequelize_connector.spec.js +0 -91
  56. package/spec/sequelize_connector.util.js +0 -18
  57. package/spec/services/integration/config/db.js +0 -14
  58. package/spec/services/integration_sequelize/README.md +0 -5
  59. package/spec/services/integration_sequelize/client/css/styles.css +0 -0
  60. package/spec/services/integration_sequelize/client/download.jpg +0 -0
  61. package/spec/services/integration_sequelize/client/favicon.ico +0 -0
  62. package/spec/services/integration_sequelize/client/index.html +0 -9
  63. package/spec/services/integration_sequelize/client/js/client.js +0 -0
  64. package/spec/services/integration_sequelize/client/js/components/app.jsx +0 -15
  65. package/spec/services/integration_sequelize/config/db.js +0 -4
  66. package/spec/services/integration_sequelize/config/routes.js +0 -25
  67. package/spec/services/integration_sequelize/config/service.js +0 -48
  68. package/spec/services/integration_sequelize/config/ssl/certificate.pem +0 -22
  69. package/spec/services/integration_sequelize/config/ssl/csr.csr +0 -17
  70. package/spec/services/integration_sequelize/config/ssl/key.pem +0 -28
  71. package/spec/services/integration_sequelize/config/ssl/private_key.pem +0 -30
  72. package/spec/services/integration_sequelize/config/ssl/public_key.pem +0 -9
  73. package/spec/services/integration_sequelize/package.json +0 -23
  74. package/spec/services/integration_sequelize/server/controllers/default_json_controller.js +0 -21
  75. package/spec/services/integration_sequelize/server/controllers/home_controller.js +0 -39
  76. package/spec/services/integration_sequelize/server/models/dog.js +0 -7
  77. package/spec/services/integration_sequelize/server/models/owner.js +0 -10
  78. package/spec/services/integration_sequelize/server/views/defaultjson/testnojson.ejs +0 -1
  79. package/spec/services/integration_sequelize/server/views/testreact/testreact.ejs +0 -15
  80. package/spec/services/integration_sequelize/server.js +0 -9
  81. package/spec/services.integration_sequelize.spec.js +0 -60
  82. package/templates/bin/promote.sh +0 -20
  83. package/templates/bin/rollout.sh +0 -74
  84. package/templates/bin/server.js +0 -6
  85. package/templates/bin/start.sh +0 -16
  86. package/templates/common/readme_fetcher.js +0 -4
  87. package/templates/config/db.js +0 -19
  88. package/templates/config/mimes.js +0 -59
  89. package/templates/config/routes.js +0 -38
  90. package/templates/config/ssl/certificate.pem +0 -22
  91. package/templates/config/ssl/csr.csr +0 -17
  92. package/templates/config/ssl/key.pem +0 -28
  93. package/templates/config/ssl/private_key.pem +0 -30
  94. package/templates/config/ssl/public_key.pem +0 -9
  95. package/templates/default/config/db.js +0 -19
  96. package/templates/default/config/mimes.js +0 -59
  97. package/templates/default/config/routes.js +0 -38
  98. package/templates/default/config/service.js +0 -45
  99. package/templates/default/server/models/User.js +0 -18
  100. package/templates/package-lock.json +0 -9048
  101. package/templates/package.json +0 -43
  102. package/templates/public/README.xml +0 -332
  103. package/templates/public/css/styles.css +0 -17
  104. package/templates/public/download.jpg +0 -0
  105. package/templates/public/favicon.ico +0 -0
  106. package/templates/public/index.html +0 -9
  107. package/templates/public/js/client.js +0 -1
  108. package/templates/server/models/User.js +0 -18
  109. package/templates/server/views/home/index.ejs +0 -14
  110. package/templates/server/views/partials/javascripts.ejs +0 -1
  111. package/templates/server/views/partials/reactapp.ejs +0 -1
  112. package/templates/server/views/partials/styles.ejs +0 -3
  113. package/templates/spec/User.test.js +0 -20
  114. package/templates/spec/home_controller.test.js +0 -28
  115. package/templates/spec/setupTests.js +0 -0
  116. package/templates/src/AboutPage.jsx +0 -9
  117. package/templates/src/HomePage.jsx +0 -9
  118. package/templates/src/Layout.jsx +0 -78
  119. package/templates/src/ReadmePage.jsx +0 -7
  120. package/templates/src/app.jsx +0 -29
  121. package/templates/src/components/ReadmeLoader.jsx +0 -13
  122. package/templates/src/styles/appstyles.css +0 -3
  123. package/templates/vite.config.ts +0 -42
@@ -1,57 +1,48 @@
1
- <h1 id="nailsboilerplateanodewebserviceframework">Nails-Boilerplate: A Node Webservice Framework</h1>
2
- <p>This framework is designed to provide a lightweight, configurable MVC backend
3
- for node developers. With minimal dependencies, Nails offers a greater
4
- syntactical familiarity than php alongside the creative freedom of well developed
5
- server framework solutions like Rails and Django.</p>
6
- <p>This boilerplate offers the basic necessities to get your MVC site off the ground.
7
- The modules used in Nails Boilerplate can be easily extended to produce the custom
8
- functionality to fit your needs, and you are encouraged to do so.</p>
9
- <h2 id="install">Install</h2>
10
- <pre><code>sudo npm install -g nails-boilerplate
1
+ <h1 id="nailsanodewebserviceframework">Nails: A Node Webservice Framework</h1>
2
+ <p>Nails is a lightweight, configurable MVC-inspired backend framework for Node.js. With minimal dependencies, Nails offers a familiar syntax for developers coming from frameworks like Ruby on Rails or Django, while providing the flexibility of JavaScript.</p>
3
+ <p>Nails provides the essential building blocks to get your MVC-style application up and running quickly. The modules used in Nails can be easily extended to produce the custom functionality to fit your needs, and you are encouraged to do so.</p>
4
+ <h2 id="gettingstarted">Getting Started</h2>
5
+ <p>There are two recommended ways to get started with Nails.</p>
6
+ <h3 id="usingnpxrecommended">Using NPX (Recommended)</h3>
7
+ <p>You can create a new Nails project without a global installation using <code>npx</code>:</p>
8
+ <pre><code class="bash language-bash">npx @projectinvicta/nails init &lt;app_name&gt;
9
+ </code></pre>
10
+ <h3 id="usingglobalinstall">Using Global Install</h3>
11
+ <p>Alternatively, you can install the package globally:</p>
12
+ <pre><code class="bash language-bash">npm install -g @projectinvicta/nails
11
13
 
12
14
  nails init &lt;app_name&gt;
13
15
  </code></pre>
14
- <p>This will initialize a barebones app in the directory of the same name. Take a
15
- look at the self-documented config files and example controller and view before
16
- getting started. Additional controllers and views will automatically be imported
17
- into nails. Now just hook the new controllers in with some new routes and you're
18
- off to a good start.</p>
19
- <pre><code>cd app_name
20
-
16
+ <p>After initializing your app, navigate into the new directory and start the server:</p>
17
+ <pre><code class="bash language-bash">cd &lt;app_name&gt;
21
18
  npm install
22
-
23
19
  npm start
24
20
  </code></pre>
25
21
  <h2 id="gettingtoknowyournailsservice">Getting to know your Nails service</h2>
26
22
  <p>For your convenience, here is a quick outline of the main components of a nails service.
27
23
  Remember: each object comes with an example file to use for reference when building your service.</p>
28
- <h3 id="config">Config</h3>
29
- <p>Your configuration files are stored in app_name/config/. There are three default config files:</p>
30
- <pre><code>service.js
31
- routes.js
32
- db.js
24
+ <h3 id="namedexports">Named Exports</h3>
25
+ <p><code>nails</code> now provides a number of useful named exports. You can import them as follows:</p>
26
+ <pre><code class="js language-js">import Nails, { Controller, Model, DataTypes, /* config types */ } from '@projectinvicta/nails';
33
27
  </code></pre>
28
+ <h3 id="config">Config</h3>
29
+ <p>Your configuration files are stored in app_name/config/.</p>
34
30
  <p>Each default config file is annotated with comments documenting each field to
35
31
  help you tailor your service to your needs.</p>
36
32
  <h4 id="servicejs">service.js</h4>
37
33
  <p>service.js contains information necessary to run your server. By default, it
38
- specifies the port and the location of important libraries. To override these
39
- values in different runtime environments, add a child object.</p>
34
+ specifies the port and the location of important libraries.</p>
40
35
  <pre><code class="js language-js">export default {
41
36
  ...
42
- PORT: 3000,
43
- PROD: {
44
- PORT: 80
45
- }
37
+ SERVER_ROOT: "/path/to/my/nails/service",
38
+ PORT: 3333,
39
+ SSL_PORT: 3334,
46
40
  }
47
41
  </code></pre>
48
- <p>Nails checks the NODE<em>ENV environment variable. If a matching child config
49
- object is present, then those values will override the parent config. In the
50
- above example, PORT will be overridden to 80 if NODE</em>ENV is set to PROD.</p>
51
42
  <p>While most of these values don't need to be changed, feel free to add custom
52
43
  fields. The resulting config will be available to your service through the nails
53
44
  module:</p>
54
- <pre><code class="js language-js">import nails from 'nails-boilerplate';
45
+ <pre><code class="js language-js">import Nails from '@projectinvicta/nails';
55
46
 
56
47
  const service_config = nails.config
57
48
  </code></pre>
@@ -66,7 +57,7 @@ const service_config = nails.config
66
57
  <code>'yourCustomValue'</code>.</p>
67
58
  <h4 id="routesjs">routes.js</h4>
68
59
  <p><em>routes.js</em> is a list defining mappings from a url path to a <em>Controller</em> and
69
- <em>Action</em>. Each entry in the list is an array with three elements:
60
+ <em>Action</em>. Routes are now strongly typed (see <code>lib/config.ts</code> and <code>lib/Router.ts</code>). Each entry in the list is an array with three elements:
70
61
  <code>[method, path, options]</code></p>
71
62
  <p><strong>method</strong> is a string defining the HTTP request method of the route. Supported
72
63
  methods are <em>GET</em>, <em>PUT</em>, <em>POST</em>, <em>DELETE</em>, and <em>ALL</em>. All is a special case
@@ -109,24 +100,18 @@ than indices. You can name your regex captures "controller" and/or "action"
109
100
  to dynamically route your request to the appropriate handler.</li>
110
101
  </ul>
111
102
  <h4 id="dbjs">db.js</h4>
112
- <p>Quickly configure your database connection here. Nails comes pre-configured to
113
- use the sequelize connector, giving your models sequelize support. The initial setup
114
- uses a <em>sqlite3</em> database file <code>config/development.db</code> and an in-memory database in the test environment. Change the address to change the location and
115
- version of your desired sql database. Check out <a href="https://sequelize.org">Sequelize</a>
116
- for more info.</p>
117
- <p>Alternatively, you can configure a connection to MongoDB using the mongoose_connector.js.
118
- If enabled, models will accept <a href="https://mongoosejs.com/docs/">Mongoose</a> schemas and will
119
- be backed by the desired MongoDB. Consider using the in-memory DB during development.</p>
103
+ <p>Quickly configure your database connection here. The initial setup uses a <em>sqlite3</em> database file <code>config/development.db</code>
104
+ and an in-memory database in the test environment. Change the address to change the location and
105
+ version of your desired sql database. Check out <a href="https://sequelize.org">Sequelize</a> for more info.</p>
120
106
  <h2 id="controller">Controller</h2>
121
107
  <p>Controllers are defined in app/controllers/. Each controller module should
122
108
  define a Controller subclass. The name will be used to match routes defined in
123
109
  config/routes.js for incoming requests. Methods on the controller can be used as
124
110
  actions, receiving <strong>params</strong>, <strong>request</strong>, and <strong>response</strong> as arguments.</p>
125
111
  <p>For Example:</p>
126
- <pre><code class="js language-js">// const Controller = requre("nails-boilerplate").Controller
127
- import nails from 'nails-boilerplate';
112
+ <pre><code class="js language-js">import { Controller } from '@projectinvicta/nails';
128
113
 
129
- class HomeController extends nails.Controller {
114
+ class HomeController extends Controller {
130
115
  index(params, request, response) {
131
116
  // default action
132
117
  }
@@ -154,7 +139,9 @@ object returned by the getData function. If the route is changed to:</p>
154
139
  <p><code>["get", "/data", {action: 'getData', json: true}],</code></p>
155
140
  <p>it will accept GET requests to /data instead. All local routes are
156
141
  implicitly routed to their respective parent controllers.</p>
157
- <pre><code class="js language-js">export default class UsersController extends nails.Controller {
142
+ <pre><code class="js language-js">import { Controller } from '@projectinvicta/nails';
143
+
144
+ export default class UsersController extends Controller {
158
145
  routes = [
159
146
  // Routes requests to /absolute/path
160
147
  ['get', '/absolute/path', {action: 'actionA'}],
@@ -226,8 +213,11 @@ overridden to allow for the rendering of views by name.</p>
226
213
  <pre><code class="js language-js">['get', '/your/json/route', {json: true}],
227
214
  </code></pre>
228
215
  <h5 id="apicontrollers">API Controllers</h5>
229
- <p>By setting <code>json</code> to <code>true</code>, all actions in a controller will respond with JSON.</p>
230
- <pre><code class="js language-js">class YourApiController extends nails.Controller {
216
+ <p>By setting <code>json</code> to <code>true</code>, all actions in a controller will respond with JSON by default.
217
+ This can be overridden for individual routes by setting <code>{json: false}</code> in the route options.</p>
218
+ <pre><code class="js language-js">import { Controller } from '@projectinvicta/nails';
219
+
220
+ class YourApiController extends Controller {
231
221
  json = true;
232
222
 
233
223
  action(params, request, response) {
@@ -236,23 +226,24 @@ overridden to allow for the rendering of views by name.</p>
236
226
  }
237
227
  </code></pre>
238
228
  <h2 id="model">Model</h2>
239
- <p>Models are programmatic representations of data you wish to persist in a
240
- database. The constructor for Model accepts two arguments: the <code>modelName</code> and an
241
- <code>options</code> object which is passed to the database connector module.</p>
229
+ <p>Models are programmatic representations of data you wish to persist in a database. Nails connects to
230
+ your database of choice using the Sequelize ORM.</p>
242
231
  <h3 id="sequelizemodels">Sequelize Models</h3>
243
232
  <p>Sequelize models are subclasses of
244
233
  <a href="https://sequelize.org/docs/v6/core-concepts/model-basics/">Sequelize Models</a>, and come with the <code>count()</code>, <code>findAll()</code>,
245
234
  and <code>create()</code> methods, to name a few. You can define your own models by
246
- extending an instance of the <code>Model</code> class provided by Nails:</p>
247
- <pre><code class="js language-js">// const Model = require("nails-boilerplate").Model;
248
- import nails from 'nails-boilerplate';
249
- import {DataTypes} from 'sequelize';
250
- schema = {
235
+ extending an instance of the <code>Model</code> class provided by Nails. Model files must export the Model subclass as a default export and a named <code>schema</code> export.
236
+ They can also export an <code>options</code> object to provide ModelInitializationOptions as well as <code>defer</code>, <code>finalize</code>, and <code>migrate</code> functions.</p>
237
+ <pre><code class="js language-js">import { Model, DataTypes } from '@projectinvicta/nails';
238
+
239
+ // REQUIRED
240
+ export const schema = {
251
241
  name: {type: DataTypes.STRING, allowNull: false},
252
242
  email: {type: DataTypes.STRING, allowNull: false}
253
243
  };
254
244
 
255
- options = {
245
+ // Optional
246
+ export const options = {
256
247
  indexes: [
257
248
  {
258
249
  unique: true,
@@ -261,30 +252,34 @@ options = {
261
252
  ],
262
253
  };
263
254
 
264
- export default class User extends new Model("User", {schema, options}) {
255
+ // REQUIRED
256
+ export default class User extends Model {
265
257
  someHelperMethod() {
266
258
  // This method will be available on all instances of User and is
267
259
  // an ideal way to simplify data manipulation.
268
260
  }
269
261
  };
262
+
263
+ // Optional
264
+ export async function defer(models) {
265
+ // define associations here
266
+ }
267
+
268
+ // Optional
269
+ export async function finalize(models) {
270
+ // any final model setup
271
+ }
272
+
273
+ // Optional
274
+ export async function migrate(queryInterface) {
275
+ // migration logic
276
+ }
270
277
  </code></pre>
271
- <h3 id="mongoosemodels">Mongoose Models</h3>
272
- <p>Mongoose models are subclasses of
273
- <a href="https://mongoosejs.com/docs/api/model.html">Mongoose Models</a>, and come with the <code>save()</code>, <code>find()</code>,
274
- and <code>where()</code> methods, to name a few. You can define your own models by
275
- extending an instance of the <code>Model</code> class provided by Nails:</p>
276
- <pre><code class="js language-js">// const Model = require("nails-boilerplate").Model;
277
- import nails from 'nails-boilerplate';
278
- const userSchema = {name: String, email: String};
279
- export default class User extends new Model("User", {schema: userSchema}) {
280
- // Define your helper methods here
281
- };
282
- </code></pre>
283
- <p>The <code>schema</code> option for Mongoose Models accepts a schema field that is used
284
- to define how documents are stored in MongoDB.</p>
285
278
  <h3 id="modellibrary">Model Library</h3>
286
279
  <p>Nails will store all instantialized models in a single object called <code>MODELS</code>. By accessing these models via the library, you can avoid circular dependencies and ensure all models have been fully initialized.</p>
287
- <pre><code class="js language-js">class User extends nails.Model("User", {schema, options}) {
280
+ <pre><code class="js language-js">import Nails, { Model } from '@projectinvicta/nails';
281
+ // ...
282
+ class User extends Model {
288
283
  // A helper method which depends on anoher model using the
289
284
  // Nails Model Library rather than directly importing the model.
290
285
  async findFriends() {
@@ -293,18 +288,6 @@ to define how documents are stored in MongoDB.</p>
293
288
  }
294
289
  </code></pre>
295
290
  <p>This design pattern is not always necessary, but will help avoid circular dependencies.</p>
296
- <h3 id="databaseconnectors">Database Connectors</h3>
297
- <p>Database connectors are intermediaries which define how a Model interacts with
298
- a database. Database connector modules need to export two methods:</p>
299
- <ul>
300
- <li><em>connect(db</em>config)_ uses the db config defined in <em>db.js</em> to connect to
301
- a database. This function will be called once by Nails.</li>
302
- <li><em>generateModelSuperclass(name, options)</em> uses the provided Model name and
303
- options to generate a Model prototype for use as an interface. A Model
304
- interface is generated for each of your models, allowing them to interact with
305
- a database. Ideally, interfaces will define save() and find() methods, but
306
- these methods and their implementations are up to the individual connector.</li>
307
- </ul>
308
291
  <h2 id="view">View</h2>
309
292
  <p>Views are dynamic templates used to render an html response for a browser.
310
293
  Nails comes prepackaged with EJS templates.
@@ -1,6 +1,6 @@
1
- import nails from "nails-boilerplate";
1
+ import {Controller} from "@projectinvicta/nails";
2
2
 
3
- export default class HomeController extends nails.Controller {
3
+ export default class HomeController extends Controller {
4
4
  /**
5
5
  * You can define a local routing table directly in the controller.
6
6
  * Local routes take precidence over global routes. All local routes
@@ -1,34 +1,29 @@
1
- import nails from "nails-boilerplate";
2
-
3
- export default class HomeController extends nails.Controller {
4
- /**
5
- * You can define a local routing table directly in the controller.
6
- * Local routes take precidence over global routes. All local routes
7
- * are prefixed with the controller name unless they start with '/'.
8
- * For example, in HomeController the following route:
9
- *
10
- * ["get", "data", {action: 'getData', json: true}],
11
- *
12
- * will accept GET requests to /home/data and respond with the json
13
- * object returned by the getData function. If the route is changed to:
14
- *
15
- * ["get", "/data", {action: 'getData', json: true}],
16
- *
17
- * it will accept GET requests to /data instead. All local routes are
18
- * implicitly routed to their respective parent controllers.
19
- */
20
- routes = [
21
- ["get", "data", {action: 'getData', json: true}],
22
- ];
23
-
24
- index(params, request, response) {
25
- return {
26
- title: "My first Nails Service",
27
- welcome_message: "Welcome to Nails"
28
- };
29
- }
30
-
31
- getData(params, request, response) {
32
- return {testData: Math.floor(Math.random() * 10000000)}
33
- }
34
- };
1
+ import {Controller} from "@projectinvicta/nails";
2
+ import User from "../models/User";
3
+
4
+ export default class UsersController extends Controller {
5
+ /**
6
+ * You can define a local routing table directly in the controller.
7
+ * Local routes take precidence over global routes. All local routes
8
+ * are prefixed with the controller name unless they start with '/'.
9
+ * For example, in HomeController the following route:
10
+ *
11
+ * ["get", "data", {action: 'getData', json: true}],
12
+ *
13
+ * will accept GET requests to /home/data and respond with the json
14
+ * object returned by the getData function. If the route is changed to:
15
+ *
16
+ * ["get", "/data", {action: 'getData', json: true}],
17
+ *
18
+ * it will accept GET requests to /data instead. All local routes are
19
+ * implicitly routed to their respective parent controllers.
20
+ */
21
+ routes = [
22
+ ["get", "./list"],
23
+ ];
24
+
25
+ async list(params, request, response) {
26
+ return await User.findAll();
27
+ }
28
+
29
+ };
@@ -0,0 +1,8 @@
1
+ import {Model, DataTypes} from "@projectinvicta/nails";
2
+
3
+ export const schema = {
4
+ good: DataTypes.BOOLEAN,
5
+ name: DataTypes.STRING,
6
+ };
7
+
8
+ export default class Dog extends Model {};
@@ -0,0 +1,14 @@
1
+ import {Model, DataTypes} from "@projectinvicta/nails";
2
+ import Dog from "./Dog";
3
+
4
+ export const schema = {
5
+ name: DataTypes.STRING,
6
+ verified: DataTypes.BOOLEAN,
7
+ email: DataTypes.STRING,
8
+ }
9
+
10
+ export default class User extends Model {};
11
+
12
+ export async function defer() {
13
+ await User.hasMany(Dog);
14
+ }
@@ -1,19 +1,21 @@
1
- import nails from "nails-boilerplate";
2
- import service_config from '../config/service.js';
1
+ import Nails from "@projectinvicta/nails";
2
+ import User from "#models/User";
3
+ import service_config from '#config/service.js';
3
4
  import { beforeAll, test, expect } from "vitest";
4
5
 
5
6
  const TEST_USER_EMAIL = "test@test.com";
6
7
  const TEST_USER_NAME = "JohnDoe";
7
8
  beforeAll(async () => {
8
9
  // Only initialize the Models.
9
- await nails.MODELS.init( service_config );
10
+ await new Nails(service_config).configure();
11
+ // await nails.MODELS.init( service_config );
10
12
  });
11
13
 
12
14
  test("Can create a User", async () => {
13
- const user = await nails.MODELS.User.create({name: TEST_USER_NAME, email: TEST_USER_EMAIL});
15
+ const user = await User.create({name: TEST_USER_NAME, email: TEST_USER_EMAIL});
14
16
 
15
17
  expect(user.id).toBeDefined();
16
- const retrievedUser = await nails.MODELS.User.findByPk(user.id);
18
+ const retrievedUser = await User.findByPk(user.id);
17
19
  expect(retrievedUser.id).toBeDefined();
18
20
  expect(retrievedUser.name).toEqual(TEST_USER_NAME);
19
21
  expect(retrievedUser.email).toEqual(TEST_USER_EMAIL);
@@ -1,4 +1,4 @@
1
- import nails from 'nails-boilerplate';
1
+ import Nails from "@projectinvicta/nails";
2
2
  // import chai from 'chai';
3
3
  import {default as chaiHttp, request} from 'chai-http';
4
4
  import service_config from '../config/service.js';
@@ -8,8 +8,8 @@ let express_app;
8
8
 
9
9
  beforeAll(async () => {
10
10
  // Initialize the application and start the server
11
- (await nails( service_config )).startServer();
12
- express_app = nails.application;
11
+ await new Nails( service_config ).startServer();
12
+ express_app = Nails.application;
13
13
  chai.use(chaiHttp);
14
14
  chai.should();
15
15
  })
package/index.js DELETED
@@ -1,6 +0,0 @@
1
- // Sets the Nails global object
2
- import nails from './lib/nails.js';
3
-
4
- export default nails;
5
-
6
- // set up Nails here
package/lib/collection.js DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * The collection is an object descending from the array class.
3
- * It comes with methods for persising groups of models to the database.
4
- */
5
- export default function Collection() {
6
- }
package/lib/controller.js DELETED
@@ -1,182 +0,0 @@
1
- // const fs = require('fs');
2
- import fs from 'node:fs';
3
- import events from 'node:events';
4
- // const events = require('events');
5
- import application from './application.js';
6
- // const application = require('./application');
7
-
8
- var router;
9
- var controller_proto;
10
- var models;
11
-
12
- // TODO: refractor error generation
13
- var NAME_REQUIRED_ERROR = function () {
14
- return new Error(
15
- 'FATAL ERROR::: Named function required for Controller constructor method');
16
- }
17
-
18
- const DISABLE_AUTORENDER = new (class DisableAutorender {});
19
-
20
- // The base controller definition
21
- class Controller {
22
- constructor() {
23
- var subclassName = this.constructor.name;
24
- var controllerName = this._getControllerName();
25
- // subclassName.toLowerCase().replace(/controller$/, '');
26
- router.removeAllListeners('dispatchTo:' + controllerName);
27
- router.on('dispatchTo:' + controllerName, this._do.bind(this));
28
- }
29
-
30
- static get DISABLE_AUTORENDER() {
31
- return DISABLE_AUTORENDER;
32
- }
33
-
34
- static setRouter (router_singleton) {
35
- Controller.router = router = router_singleton;
36
- }
37
-
38
- static setModels (models) {
39
- Controller.prototype.models = models;
40
- }
41
-
42
- static extend (constructor) {
43
- console.log('extending', constructor.name);
44
- if (!constructor.name) throw NAME_REQUIRED_ERROR();
45
- controller_proto = controller_proto || new Controller();
46
- constructor.prototype.__proto__ = controller_proto;
47
- var constructed = new constructor();
48
-
49
- // configure event listeners on router.
50
- var controller_name =
51
- constructor.name.toLowerCase().replace(/controller$/, '');
52
- router.removeAllListeners('dispatchTo:' + controller_name);
53
- router.on('dispatchTo:' + controller_name, constructed._do.bind(constructed));
54
-
55
- return constructed;
56
- }
57
-
58
- _getControllerName() {
59
- return this.constructor.name.toLowerCase().replace(/controller$/, '');
60
- }
61
-
62
- /** Initializes local and global routes defined on the Controller subclass */
63
- _registerControllerRoutes() {
64
- const defaultToJson = !!this.json;
65
- const controllerName = this._getControllerName();
66
- if (this.routes && this.routes.length) {
67
- const localizedRoutes = this.routes.map(route => {
68
- // TODO: throw an error if :controller is present in local routes
69
- // TODO: also account for other malformed local routes
70
- const routePrefix = `/${controllerName}/`;
71
- const modifiedDestination = route[1][0] == '/'
72
- ? route[1]
73
- : route[1].startsWith('./') ? route[1].replace('./', routePrefix) : routePrefix + route[1];
74
- const modifiedOptions = {...route[2]};
75
- // TODO: introduce a shorthand so action doesn't have to be redefined everywhere
76
- if (!('json' in modifiedOptions)) modifiedOptions.json = defaultToJson;
77
- if (!('action' in modifiedOptions)
78
- && !modifiedDestination.includes(":action")
79
- && !Object.values(modifiedOptions).includes('action')) {
80
- const destinationParts = modifiedDestination.split("/");
81
- modifiedOptions.action = destinationParts[destinationParts.length - 1];
82
- }
83
- modifiedOptions.controller = controllerName;
84
- return [route[0], modifiedDestination, modifiedOptions];
85
- });
86
- router.addRoutes(localizedRoutes);
87
- }
88
- }
89
-
90
- /**** Network Methods *****/
91
- /**
92
- * The main entry function of the controller.
93
- *
94
- * @param {string} action The action called for this controller
95
- * @param {object} params The parameter hash for this action
96
- * @param {object} request The http request object from the http server
97
- * @param {object} response The http response object from the http server
98
- * @param {object} ws The WebSocket instance
99
- */
100
- _do (action, params, request, response, ws) {
101
- request.handled_by_controller = true;
102
- var doAction = this[action];
103
- console.log(this.constructor.name, 'doing', action);
104
- // TODO: let express handle errors
105
- if (typeof doAction != 'function') {
106
- //return this['404'](params, request, response);
107
- var error = new Error('Action Not Available: #' + action);
108
- if (response) {
109
- return response.status(404).send({
110
- error: error.stack
111
- });
112
- }
113
- return ws.close(1003, "Action Not available: #" + action);
114
- }
115
- if (ws && !response) {
116
- return doAction.call(this, params, ws, request);
117
- }
118
- // Override async with Controller definition.
119
- if (doAction.async != undefined) params._async = !!doAction.async;
120
- let actionResponse = doAction.call(this, params, request, response);
121
- let controller = params._controller.toString();
122
- //let viewAction = params._action ? params._action.toString() : "index";
123
- let viewPath = `${controller}/${action}`;
124
- function renderView(templateVars) {
125
- if (response.headersSent) {
126
- return;
127
- }
128
- if (!!params._json) {
129
- response.json(templateVars == undefined ? params : templateVars);
130
- return;
131
- }
132
- response.render(
133
- viewPath,
134
- templateVars == undefined ? params : templateVars,
135
- function(err, html) {
136
- if (err && err.message.match(/Failed to lookup view/)) {
137
- response.render(viewPath + ".ejs", params);
138
- } else if (err) {
139
- console.error(err);
140
- response.sendStatus(400, err);
141
- } else {
142
- response.send(html);
143
- }
144
- });
145
- }
146
- // Default to the jsx engine. If that doesn't work, try the configured view engine.
147
- if (!response.headersSent
148
- && !params._async
149
- && actionResponse != DISABLE_AUTORENDER) {
150
- if (actionResponse instanceof Promise) {
151
- // TODO: add a timeout so an unresolved promise doesn't preserve the
152
- // connection indefinitely.
153
- actionResponse
154
- .then(renderView)
155
- .catch(error => {
156
- // TODO: only do one of these
157
- console.error(error);
158
- console.log(error);
159
- response.sendStatus(500, error);
160
- });
161
- } else renderView(actionResponse);
162
- }
163
- }
164
- }
165
-
166
- const error_codes = [404, 500];
167
- error_codes.forEach((ec) => {
168
- Controller.prototype[ec] = function (params, request, response) {
169
- //this._render('404');
170
- console.error(ec.toString() + ' error with params', params);
171
- var error = params['error'] || {};
172
- var message = error.message || 'Error';
173
- var stack_trace = error.stack || error || '';
174
- response.setHeader('content-type', 'text/plain');
175
- response.statusCode = ec;
176
- response.end(message + '\n\n' + stack_trace);
177
- };
178
- Controller.prototype[ec.toString()] = Controller.prototype[ec];
179
-
180
- });
181
-
182
- export default Controller;
@@ -1,12 +0,0 @@
1
- export default class DbConnector {
2
- async connect() {
3
- throw 'DbConnector#connect not implemented'
4
- }
5
- generateModelSuperclass() {
6
- throw 'GenerateModelSuperclass not implemented'
7
- }
8
-
9
- async afterInitialization() {
10
- console.warn("DbConnector#afterInitialization not implemented");
11
- }
12
- }