retold 1.0.6 → 4.0.1
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.
- package/.claude/settings.local.json +58 -0
- package/CLAUDE.md +52 -0
- package/docs/.nojekyll +0 -0
- package/docs/README.md +161 -0
- package/docs/_sidebar.md +65 -0
- package/docs/_topbar.md +6 -0
- package/docs/architecture.md +312 -0
- package/docs/cover.md +15 -0
- package/docs/css/docuserve.css +73 -0
- package/docs/fable.md +198 -0
- package/docs/getting-started.md +272 -0
- package/docs/index.html +39 -0
- package/docs/js/pict.min.js +12 -0
- package/docs/js/pict.min.js.map +1 -0
- package/docs/meadow.md +211 -0
- package/docs/modules.md +96 -0
- package/docs/orator.md +164 -0
- package/docs/pict-docuserve.min.js +58 -0
- package/docs/pict-docuserve.min.js.map +1 -0
- package/docs/pict.md +213 -0
- package/docs/retold-building-documentation.md +33 -0
- package/docs/retold-catalog.json +2826 -0
- package/docs/retold-keyword-index.json +161289 -0
- package/docs/utility.md +63 -0
- package/examples/quickstart/README.md +47 -0
- package/examples/quickstart/layer1/README.md +21 -0
- package/examples/quickstart/layer1/index.js +49 -0
- package/examples/quickstart/layer1/package-lock.json +344 -0
- package/examples/quickstart/layer1/package.json +12 -0
- package/examples/quickstart/layer2/README.md +34 -0
- package/examples/quickstart/layer2/index.js +251 -0
- package/examples/quickstart/layer2/package-lock.json +4468 -0
- package/examples/quickstart/layer2/package.json +17 -0
- package/examples/quickstart/layer2/setup-database.js +61 -0
- package/examples/quickstart/layer3/README.md +39 -0
- package/examples/quickstart/layer3/index.js +91 -0
- package/examples/quickstart/layer3/package-lock.json +1936 -0
- package/examples/quickstart/layer3/package.json +14 -0
- package/examples/quickstart/layer4/README.md +47 -0
- package/examples/quickstart/layer4/generate-build-config.js +18 -0
- package/examples/quickstart/layer4/html/index.html +17 -0
- package/examples/quickstart/layer4/package-lock.json +13206 -0
- package/examples/quickstart/layer4/package.json +38 -0
- package/examples/quickstart/layer4/server.js +28 -0
- package/examples/quickstart/layer4/source/BookStore-Application-Config.json +15 -0
- package/examples/quickstart/layer4/source/BookStore-Application.js +54 -0
- package/examples/quickstart/layer4/source/providers/Router-Config.json +18 -0
- package/examples/quickstart/layer4/source/views/View-About.js +38 -0
- package/examples/quickstart/layer4/source/views/View-Home.js +50 -0
- package/examples/quickstart/layer4/source/views/View-Layout.js +60 -0
- package/examples/quickstart/layer5/README.md +26 -0
- package/examples/quickstart/layer5/index.js +121 -0
- package/examples/quickstart/layer5/package-lock.json +345 -0
- package/examples/quickstart/layer5/package.json +13 -0
- package/modules/.claude/settings.local.json +52 -0
- package/modules/CLAUDE.md +60 -0
- package/modules/Checkout.sh +42 -0
- package/modules/Include-Retold-Module-List.sh +15 -0
- package/modules/Retold-Modules.md +24 -0
- package/modules/Status.sh +59 -0
- package/modules/Update.sh +45 -0
- package/modules/fable/Fable.md +2 -0
- package/modules/meadow/Meadow.md +1 -0
- package/modules/orator/Orator.md +1 -0
- package/modules/pict/Pict.md +1 -0
- package/package.json +30 -35
- package/source/Retold.cjs +2 -0
- package/test/Retold_tests.js +23 -41
- package/.travis.yml +0 -13
- package/source/Retold-Meadow-Macros.js +0 -269
- package/source/Retold.js +0 -48
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
Pict Docuserve - Base Styles
|
|
3
|
+
============================================================================ */
|
|
4
|
+
|
|
5
|
+
/* Reset and base */
|
|
6
|
+
*, *::before, *::after {
|
|
7
|
+
box-sizing: border-box;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
html, body {
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 0;
|
|
13
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
14
|
+
font-size: 16px;
|
|
15
|
+
line-height: 1.5;
|
|
16
|
+
color: #333;
|
|
17
|
+
background-color: #fff;
|
|
18
|
+
-webkit-font-smoothing: antialiased;
|
|
19
|
+
-moz-osx-font-smoothing: grayscale;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Typography */
|
|
23
|
+
h1, h2, h3, h4, h5, h6 {
|
|
24
|
+
margin-top: 0;
|
|
25
|
+
line-height: 1.3;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
a {
|
|
29
|
+
color: #42b983;
|
|
30
|
+
text-decoration: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
a:hover {
|
|
34
|
+
color: #38a373;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Application container */
|
|
38
|
+
#Docuserve-Application-Container {
|
|
39
|
+
min-height: 100vh;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Utility: scrollbar styling */
|
|
43
|
+
::-webkit-scrollbar {
|
|
44
|
+
width: 8px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
::-webkit-scrollbar-track {
|
|
48
|
+
background: #f1f1f1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
::-webkit-scrollbar-thumb {
|
|
52
|
+
background: #bdc3c7;
|
|
53
|
+
border-radius: 4px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
::-webkit-scrollbar-thumb:hover {
|
|
57
|
+
background: #95a5a6;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* Responsive adjustments */
|
|
61
|
+
@media (max-width: 768px) {
|
|
62
|
+
html {
|
|
63
|
+
font-size: 14px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
#Docuserve-Sidebar-Container {
|
|
67
|
+
display: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.docuserve-body {
|
|
71
|
+
flex-direction: column;
|
|
72
|
+
}
|
|
73
|
+
}
|
package/docs/fable.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Fable — Core Ecosystem
|
|
2
|
+
|
|
3
|
+
Fable is the foundation of every Retold application. It provides dependency injection, configuration management, logging, UUID generation, and a collection of utility services. Every other Retold module depends on Fable.
|
|
4
|
+
|
|
5
|
+
## What Fable Provides
|
|
6
|
+
|
|
7
|
+
When you create a Fable instance, you get:
|
|
8
|
+
|
|
9
|
+
- **Service provider registry** — Register, discover, and inject services by type
|
|
10
|
+
- **Configuration** — Merge settings from files, defaults, and runtime overrides
|
|
11
|
+
- **Logging** — Six log levels with extensible output streams
|
|
12
|
+
- **UUID generation** — RFC 4122 v4 UUIDs or configurable random strings
|
|
13
|
+
- **Expression parser** — Evaluate mathematical and logical expressions with 80+ built-in functions
|
|
14
|
+
- **REST client** — Make HTTP requests from Node.js or the browser
|
|
15
|
+
- **Template engine** — Render templates with data binding
|
|
16
|
+
- **Date utilities** — Date parsing and formatting
|
|
17
|
+
- **Data format helpers** — Clean numbers, pad strings, format values
|
|
18
|
+
|
|
19
|
+
## Core Service Modules
|
|
20
|
+
|
|
21
|
+
### [Fable](/fable/fable/)
|
|
22
|
+
|
|
23
|
+
The main module. Creates the service container and bundles all core services.
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
const libFable = require('fable');
|
|
27
|
+
|
|
28
|
+
let _Fable = new libFable({
|
|
29
|
+
Product: 'MyApp',
|
|
30
|
+
ProductVersion: '1.0.0',
|
|
31
|
+
LogLevel: 3
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// All services are immediately available
|
|
35
|
+
_Fable.log.info('Started');
|
|
36
|
+
_Fable.log.trace(`UUID: ${_Fable.getUUID()}`);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**npm:** `fable` · **Version:** 3.1.x
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
### [Fable-ServiceProviderBase](/fable/fable-serviceproviderbase/)
|
|
44
|
+
|
|
45
|
+
The base class that all Retold services extend. Provides the registration and dependency injection mechanics.
|
|
46
|
+
|
|
47
|
+
Every service gets:
|
|
48
|
+
- `this.fable` — Reference to the Fable instance
|
|
49
|
+
- `this.log` — Shortcut to logging
|
|
50
|
+
- `this.options` — Service-specific options
|
|
51
|
+
- `this.serviceType` — The registered service type name
|
|
52
|
+
- `this.Hash` — Unique identifier for this service instance
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
const libServiceProviderBase = require('fable-serviceproviderbase');
|
|
56
|
+
|
|
57
|
+
class MyService extends libServiceProviderBase
|
|
58
|
+
{
|
|
59
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
60
|
+
{
|
|
61
|
+
super(pFable, pOptions, pServiceHash);
|
|
62
|
+
this.serviceType = 'MyService';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
doSomething()
|
|
66
|
+
{
|
|
67
|
+
this.log.info('MyService is doing something');
|
|
68
|
+
let tmpUUID = this.fable.getUUID();
|
|
69
|
+
return tmpUUID;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Register with Fable
|
|
74
|
+
_Fable.addAndInstantiateServiceType('MyService', MyService);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**npm:** `fable-serviceproviderbase` · **Version:** 3.0.x
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### [Fable-Settings](/fable/fable-settings/)
|
|
82
|
+
|
|
83
|
+
A tolerant configuration chain. Loads settings from files, merges with defaults, and allows runtime overrides.
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
// Settings merge in order: defaults → file → constructor → runtime
|
|
87
|
+
let _Fable = new libFable({
|
|
88
|
+
Product: 'MyApp',
|
|
89
|
+
MySQL: {
|
|
90
|
+
Server: 'localhost',
|
|
91
|
+
User: 'root',
|
|
92
|
+
Database: 'mydb'
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Access settings
|
|
97
|
+
let tmpServer = _Fable.settings.MySQL.Server;
|
|
98
|
+
|
|
99
|
+
// Override at runtime
|
|
100
|
+
_Fable.settings.MySQL.Server = 'production-host';
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**npm:** `fable-settings` · **Version:** 3.0.x
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### [Fable-Log](/fable/fable-log/)
|
|
108
|
+
|
|
109
|
+
Flexible logging with six levels and extensible output streams.
|
|
110
|
+
|
|
111
|
+
| Level | Method | Use |
|
|
112
|
+
|-------|--------|-----|
|
|
113
|
+
| 0 | `log.trace()` | Granular debugging |
|
|
114
|
+
| 1 | `log.debug()` | Development debugging |
|
|
115
|
+
| 2 | `log.info()` | Normal operation |
|
|
116
|
+
| 3 | `log.warn()` | Potential issues |
|
|
117
|
+
| 4 | `log.error()` | Errors |
|
|
118
|
+
| 5 | `log.fatal()` | Critical failures |
|
|
119
|
+
|
|
120
|
+
Set `LogLevel` in configuration to control which messages appear. Messages at the configured level and above are shown.
|
|
121
|
+
|
|
122
|
+
```javascript
|
|
123
|
+
let _Fable = new libFable({ LogLevel: 2 }); // info and above
|
|
124
|
+
|
|
125
|
+
_Fable.log.trace('Not shown');
|
|
126
|
+
_Fable.log.info('Shown');
|
|
127
|
+
_Fable.log.error('Shown');
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**npm:** `fable-log` · **Version:** 3.0.x
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
### [Fable-UUID](/fable/fable-uuid/)
|
|
135
|
+
|
|
136
|
+
UUID generation for identity and uniqueness.
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
// RFC 4122 v4 UUID
|
|
140
|
+
let tmpUUID = _Fable.getUUID();
|
|
141
|
+
// → '83853f9c-732c-4225-9a20-abcde47c6ddb'
|
|
142
|
+
|
|
143
|
+
// Random string (configurable length and character set)
|
|
144
|
+
let tmpRandom = _Fable.fable.UUID.getUUID({ length: 12 });
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**npm:** `fable-uuid` · **Version:** 3.0.x
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### [Fable-Log-Logger-Bunyan](/fable/fable-log-logger-bunyan/)
|
|
152
|
+
|
|
153
|
+
A structured logging provider that routes Fable-Log output to Bunyan for production environments with JSON-formatted, machine-parseable log streams.
|
|
154
|
+
|
|
155
|
+
**npm:** `fable-log-logger-bunyan` · **Version:** 1.0.x
|
|
156
|
+
|
|
157
|
+
## The Service Provider Pattern
|
|
158
|
+
|
|
159
|
+
Fable's core design pattern: modules register as services and discover each other through the Fable instance.
|
|
160
|
+
|
|
161
|
+
```mermaid
|
|
162
|
+
graph LR
|
|
163
|
+
reg["Register Service"] --> fable
|
|
164
|
+
|
|
165
|
+
subgraph fable["Fable Instance"]
|
|
166
|
+
direction TB
|
|
167
|
+
core[".settings .log .getUUID()"]
|
|
168
|
+
subgraph registry["Service Registry"]
|
|
169
|
+
meadow["Meadow"]
|
|
170
|
+
orator["Orator"]
|
|
171
|
+
custom["MyCustomService"]
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
fable --> a1["_Fable.Meadow"]
|
|
176
|
+
fable --> a2["_Fable.Orator"]
|
|
177
|
+
fable --> a3["_Fable.MyCustomService"]
|
|
178
|
+
|
|
179
|
+
style fable fill:#fce4ec,stroke:#ef5350,color:#333
|
|
180
|
+
style registry fill:#fff,stroke:#ef9a9a,color:#333
|
|
181
|
+
style core fill:#fce4ec,stroke:none,color:#333
|
|
182
|
+
style a1 fill:#fff3e0,stroke:#ffa726,color:#333
|
|
183
|
+
style a2 fill:#e3f2fd,stroke:#42a5f5,color:#333
|
|
184
|
+
style a3 fill:#e8f5e9,stroke:#66bb6a,color:#333
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Services can be registered by type (`addServiceType`) or instantiated on registration (`addAndInstantiateServiceType`). Multiple instances of the same type can coexist with different hashes.
|
|
188
|
+
|
|
189
|
+
## Related Modules
|
|
190
|
+
|
|
191
|
+
| Module | Description |
|
|
192
|
+
|--------|-------------|
|
|
193
|
+
| [fable](/fable/fable/) | Core module with all services |
|
|
194
|
+
| [fable-serviceproviderbase](/fable/fable-serviceproviderbase/) | Base class for all services |
|
|
195
|
+
| [fable-settings](/fable/fable-settings/) | Configuration management |
|
|
196
|
+
| [fable-log](/fable/fable-log/) | Logging library |
|
|
197
|
+
| [fable-uuid](/fable/fable-uuid/) | UUID generation |
|
|
198
|
+
| [fable-log-logger-bunyan](/fable/fable-log-logger-bunyan/) | Bunyan log provider |
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
This guide walks through building a Retold application step by step, adding one layer at a time. See the [Architecture](architecture.md) page for a full description of the layer model.
|
|
4
|
+
|
|
5
|
+
> **Working examples:** Each step below has a corresponding runnable example in
|
|
6
|
+
> [`examples/quickstart/`](../examples/quickstart/). Clone the repo and follow
|
|
7
|
+
> along with real code.
|
|
8
|
+
|
|
9
|
+
## Step 1: Fable — The Foundation
|
|
10
|
+
|
|
11
|
+
> **Layer 1 — Fable (Core Ecosystem):** DI, configuration, logging, UUID, expressions
|
|
12
|
+
>
|
|
13
|
+
> Working example: [`examples/quickstart/layer1/`](../examples/quickstart/layer1/)
|
|
14
|
+
|
|
15
|
+
Every Retold application starts with a Fable instance. Fable gives you dependency injection, configuration, and logging.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install fable
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
const libFable = require('fable');
|
|
23
|
+
|
|
24
|
+
let _Fable = new libFable({
|
|
25
|
+
Product: 'BookStore',
|
|
26
|
+
ProductVersion: '1.0.0',
|
|
27
|
+
LogLevel: 2 // info and above
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
_Fable.log.info('BookStore starting up...');
|
|
31
|
+
_Fable.log.trace(`Instance UUID: ${_Fable.getUUID()}`);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Configuration can come from the constructor, a `.fable.config.json` file, or a combination:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"Product": "BookStore",
|
|
39
|
+
"LogLevel": 2,
|
|
40
|
+
"MySQL": {
|
|
41
|
+
"Server": "localhost",
|
|
42
|
+
"User": "root",
|
|
43
|
+
"Password": "",
|
|
44
|
+
"Database": "bookstore",
|
|
45
|
+
"ConnectionPoolLimit": 20
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Step 2: Meadow — Define Your Data
|
|
51
|
+
|
|
52
|
+
> **Layer 2 — Meadow + FoxHound + Stricture:** Data broker, SQL generation, schema definitions
|
|
53
|
+
>
|
|
54
|
+
> Working example: [`examples/quickstart/layer2/`](../examples/quickstart/layer2/)
|
|
55
|
+
|
|
56
|
+
Add Meadow to define data entities and connect to a database.
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm install meadow foxhound stricture meadow-connection-mysql
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Define a schema for your entity. Stricture's MicroDDL is the simplest approach, but you can also write JSON directly:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"title": "Book",
|
|
67
|
+
"description": "A book in the bookstore",
|
|
68
|
+
"defaultIdentifier": "IDBook",
|
|
69
|
+
"defaultGUIDIdentifier": "GUIDBook",
|
|
70
|
+
"columns": [
|
|
71
|
+
{ "Column": "IDBook", "Type": "AutoIdentity" },
|
|
72
|
+
{ "Column": "GUIDBook", "Type": "AutoGUID" },
|
|
73
|
+
{ "Column": "Title", "Size": 200, "Type": "String" },
|
|
74
|
+
{ "Column": "Author", "Size": 200, "Type": "String" },
|
|
75
|
+
{ "Column": "YearPublished", "Type": "Integer" },
|
|
76
|
+
{ "Column": "CreateDate", "Type": "DateTime" },
|
|
77
|
+
{ "Column": "CreatingIDUser", "Type": "Integer" },
|
|
78
|
+
{ "Column": "UpdateDate", "Type": "DateTime" },
|
|
79
|
+
{ "Column": "UpdatingIDUser", "Type": "Integer" },
|
|
80
|
+
{ "Column": "Deleted", "Type": "Boolean" },
|
|
81
|
+
{ "Column": "DeleteDate", "Type": "DateTime" },
|
|
82
|
+
{ "Column": "DeletingIDUser", "Type": "Integer" }
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Create the Meadow entity:
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
const libMeadow = require('meadow');
|
|
91
|
+
const BookSchema = require('./Book-Schema.json');
|
|
92
|
+
|
|
93
|
+
let _BookMeadow = _Fable.instantiateServiceProvider('Meadow',
|
|
94
|
+
{
|
|
95
|
+
Scope: 'Book',
|
|
96
|
+
DefaultSchema: BookSchema
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Perform data operations
|
|
100
|
+
_BookMeadow.doCreate({ Title: 'The Hobbit', Author: 'Tolkien', YearPublished: 1937 },
|
|
101
|
+
function(pError, pQuery, pRecord)
|
|
102
|
+
{
|
|
103
|
+
_Fable.log.info(`Created book with ID ${pRecord.IDBook}`);
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Step 3: Meadow-Endpoints — Auto-Generate Your API
|
|
108
|
+
|
|
109
|
+
> **Layer 3 — Meadow-Endpoints:** Auto-generated CRUD routes, behavior hooks
|
|
110
|
+
|
|
111
|
+
Add Meadow-Endpoints to automatically create RESTful routes from your entity.
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
npm install meadow-endpoints
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```javascript
|
|
118
|
+
const libMeadowEndpoints = require('meadow-endpoints');
|
|
119
|
+
|
|
120
|
+
let _BookEndpoints = _Fable.instantiateServiceProvider('MeadowEndpoints',
|
|
121
|
+
{
|
|
122
|
+
Entity: _BookMeadow
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Add authentication behavior
|
|
126
|
+
_BookEndpoints.BehaviorModifications.setBehavior('Create-Authorize',
|
|
127
|
+
function(pRequest, fCallback)
|
|
128
|
+
{
|
|
129
|
+
// Only authenticated users can create books
|
|
130
|
+
if (!pRequest.UserSession || !pRequest.UserSession.LoggedIn)
|
|
131
|
+
{
|
|
132
|
+
pRequest.CommonServices.log.warn('Unauthorized create attempt');
|
|
133
|
+
return fCallback('Unauthorized');
|
|
134
|
+
}
|
|
135
|
+
return fCallback();
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
This generates endpoints for: `GET /Books`, `GET /Book/:id`, `POST /Book`, `PUT /Book`, `DEL /Book/:id`, `GET /Books/Count`, `GET /Book/Schema`, and `DEL /Book/:id/Undelete`.
|
|
140
|
+
|
|
141
|
+
## Step 4: Orator — Serve Your API
|
|
142
|
+
|
|
143
|
+
> **Layer 4 — Orator (API Server):** HTTP lifecycle, middleware, static files, proxy
|
|
144
|
+
>
|
|
145
|
+
> Working example: [`examples/quickstart/layer3/`](../examples/quickstart/layer3/)
|
|
146
|
+
|
|
147
|
+
Add Orator to host everything over HTTP.
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npm install orator orator-serviceserver-restify
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
const libOrator = require('orator');
|
|
155
|
+
require('orator-serviceserver-restify');
|
|
156
|
+
|
|
157
|
+
let _Orator = _Fable.instantiateServiceProvider('Orator');
|
|
158
|
+
|
|
159
|
+
// Wire the auto-generated endpoints to the HTTP server
|
|
160
|
+
_BookEndpoints.connectRoutes(_Orator);
|
|
161
|
+
|
|
162
|
+
// Add a custom health check route
|
|
163
|
+
_Orator.addRoute('GET', '/health', function(pRequest, pResponse, fNext)
|
|
164
|
+
{
|
|
165
|
+
pResponse.send({ status: 'ok', product: _Fable.settings.Product });
|
|
166
|
+
return fNext();
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Start the server
|
|
170
|
+
_Orator.startService(function(pError)
|
|
171
|
+
{
|
|
172
|
+
if (pError)
|
|
173
|
+
{
|
|
174
|
+
_Fable.log.error(`Failed to start: ${pError}`);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
_Fable.log.info(`${_Fable.settings.Product} running on port ${_Fable.settings.APIServerPort}`);
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Your API is now running. Test it:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Create a book
|
|
185
|
+
curl -X POST http://localhost:8086/Book \
|
|
186
|
+
-H "Content-Type: application/json" \
|
|
187
|
+
-d '{"Title": "The Hobbit", "Author": "Tolkien", "YearPublished": 1937}'
|
|
188
|
+
|
|
189
|
+
# List all books
|
|
190
|
+
curl http://localhost:8086/Books
|
|
191
|
+
|
|
192
|
+
# Get a specific book
|
|
193
|
+
curl http://localhost:8086/Book/1
|
|
194
|
+
|
|
195
|
+
# Get the count
|
|
196
|
+
curl http://localhost:8086/Books/Count
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Step 5: Pict — Add a Browser UI (Optional)
|
|
200
|
+
|
|
201
|
+
> **Pict (MVC Tools):** Views, templates, providers, application lifecycle — sits alongside the server stack
|
|
202
|
+
>
|
|
203
|
+
> Working example: [`examples/quickstart/layer4/`](../examples/quickstart/layer4/)
|
|
204
|
+
|
|
205
|
+
If your application has a browser interface, add Pict for MVC.
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
npm install pict pict-view pict-application
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
```javascript
|
|
212
|
+
const libPict = require('pict');
|
|
213
|
+
|
|
214
|
+
let _Pict = new libPict({
|
|
215
|
+
Product: 'BookStoreUI'
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Register templates
|
|
219
|
+
_Pict.TemplateProvider.addTemplate('BookList',
|
|
220
|
+
'<ul>{~Each:AppData.Books:BookItem~}</ul>');
|
|
221
|
+
_Pict.TemplateProvider.addTemplate('BookItem',
|
|
222
|
+
'<li>{~Data:Record.Title~} by {~Data:Record.Author~} ({~Data:Record.YearPublished~})</li>');
|
|
223
|
+
|
|
224
|
+
// Load data from your API
|
|
225
|
+
fetch('/Books')
|
|
226
|
+
.then(r => r.json())
|
|
227
|
+
.then(books =>
|
|
228
|
+
{
|
|
229
|
+
_Pict.AppData.Books = books;
|
|
230
|
+
// Render into the page
|
|
231
|
+
document.getElementById('book-list').innerHTML =
|
|
232
|
+
_Pict.parseTemplate('BookList', {});
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## The Shortcut: Retold-Data-Service
|
|
237
|
+
|
|
238
|
+
For the common case of "schema → full REST API", **retold-data-service** wraps Layers 2–3 (Meadow + Meadow-Endpoints) into a single call:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
npm install retold-data-service
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
const libRetoldDataService = require('retold-data-service');
|
|
246
|
+
|
|
247
|
+
let _BookService = _Fable.instantiateServiceProvider('RetoldDataService',
|
|
248
|
+
{
|
|
249
|
+
Scope: 'Book',
|
|
250
|
+
Schema: BookSchema
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Full CRUD endpoints ready — wire to Orator and go
|
|
254
|
+
_BookService.connectRoutes(_Orator);
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Utility Modules
|
|
258
|
+
|
|
259
|
+
> **Utility Layer:** Build tools, manifest management, documentation, process supervision
|
|
260
|
+
>
|
|
261
|
+
> Working example: [`examples/quickstart/layer5/`](../examples/quickstart/layer5/) (Manyfest)
|
|
262
|
+
|
|
263
|
+
Supporting the application stack are utility modules like **Manyfest** (schema-driven object navigation), **Quackage** (browser bundling), **Indoctrinate** (documentation generation), and **Ultravisor** (process supervision). These are used throughout the stack but don't live in the numbered layer model.
|
|
264
|
+
|
|
265
|
+
## Next Steps
|
|
266
|
+
|
|
267
|
+
- **[Architecture](architecture.md)** — Understand the layer model in depth
|
|
268
|
+
- **[Fable](fable.md)** — Deep dive into the core ecosystem and service provider pattern
|
|
269
|
+
- **[Meadow](meadow.md)** — Data access, FoxHound queries, and Stricture schemas
|
|
270
|
+
- **[Orator](orator.md)** — Server configuration, lifecycle hooks, and middleware
|
|
271
|
+
- **[Pict](pict.md)** — Views, templates, providers, and application lifecycle
|
|
272
|
+
- **[All Modules](modules.md)** — Every repository in the Retold suite
|
package/docs/index.html
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
7
|
+
<meta name="description" content="Documentation powered by pict-docuserve">
|
|
8
|
+
|
|
9
|
+
<title>Documentation</title>
|
|
10
|
+
|
|
11
|
+
<!-- Application Stylesheet -->
|
|
12
|
+
<link href="css/docuserve.css" rel="stylesheet">
|
|
13
|
+
<!-- KaTeX stylesheet for LaTeX equation rendering -->
|
|
14
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.css">
|
|
15
|
+
<!-- PICT Dynamic View CSS Container -->
|
|
16
|
+
<style id="PICT-CSS"></style>
|
|
17
|
+
|
|
18
|
+
<!-- Load the PICT library -->
|
|
19
|
+
<script src="./js/pict.min.js" type="text/javascript"></script>
|
|
20
|
+
<!-- Bootstrap the Application -->
|
|
21
|
+
<script type="text/javascript">
|
|
22
|
+
//<![CDATA[
|
|
23
|
+
Pict.safeOnDocumentReady(() => { Pict.safeLoadPictApplication(PictDocuserve, 2)});
|
|
24
|
+
//]]>
|
|
25
|
+
</script>
|
|
26
|
+
</head>
|
|
27
|
+
<body>
|
|
28
|
+
<!-- The root container for the Pict application -->
|
|
29
|
+
<div id="Docuserve-Application-Container"></div>
|
|
30
|
+
|
|
31
|
+
<!-- Mermaid diagram rendering -->
|
|
32
|
+
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
|
|
33
|
+
<script>mermaid.initialize({ startOnLoad: false, theme: 'default' });</script>
|
|
34
|
+
<!-- KaTeX for LaTeX equation rendering -->
|
|
35
|
+
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.js"></script>
|
|
36
|
+
<!-- Load the Docuserve PICT Application Bundle -->
|
|
37
|
+
<script src="./pict-docuserve.min.js" type="text/javascript"></script>
|
|
38
|
+
</body>
|
|
39
|
+
</html>
|