retold 4.0.1 → 4.0.3

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 (78) hide show
  1. package/.claude/settings.local.json +38 -1
  2. package/README.md +92 -2
  3. package/docs/README.md +7 -6
  4. package/docs/_sidebar.md +36 -21
  5. package/docs/_topbar.md +2 -2
  6. package/docs/architecture/comprehensions.md +282 -0
  7. package/docs/architecture/fluid-models.md +355 -0
  8. package/docs/architecture/module-architecture.md +234 -0
  9. package/docs/{modules.md → architecture/modules.md} +25 -22
  10. package/docs/cover.md +2 -2
  11. package/docs/css/docuserve.css +6 -6
  12. package/docs/examples/examples.md +71 -0
  13. package/docs/examples/todolist/todo-list-cli-client.md +178 -0
  14. package/docs/examples/todolist/todo-list-console-client.md +152 -0
  15. package/docs/examples/todolist/todo-list-model.md +114 -0
  16. package/docs/examples/todolist/todo-list-server.md +128 -0
  17. package/docs/examples/todolist/todo-list-web-client.md +177 -0
  18. package/docs/examples/todolist/todo-list.md +162 -0
  19. package/docs/getting-started.md +8 -7
  20. package/docs/index.html +4 -4
  21. package/docs/{meadow.md → modules/meadow.md} +4 -6
  22. package/docs/{orator.md → modules/orator.md} +1 -0
  23. package/docs/{pict.md → modules/pict.md} +30 -8
  24. package/docs/{utility.md → modules/utility.md} +0 -9
  25. package/docs/retold-catalog.json +1792 -231
  26. package/docs/retold-keyword-index.json +136439 -64616
  27. package/examples/todo-list/Dockerfile +45 -0
  28. package/examples/todo-list/README.md +394 -0
  29. package/examples/todo-list/cli-client/package-lock.json +418 -0
  30. package/examples/todo-list/cli-client/package.json +19 -0
  31. package/examples/todo-list/cli-client/source/TodoCLI-CLIProgram.js +30 -0
  32. package/examples/todo-list/cli-client/source/TodoCLI-Run.js +3 -0
  33. package/examples/todo-list/cli-client/source/commands/add/TodoCLI-Command-Add.js +74 -0
  34. package/examples/todo-list/cli-client/source/commands/complete/TodoCLI-Command-Complete.js +84 -0
  35. package/examples/todo-list/cli-client/source/commands/list/TodoCLI-Command-List.js +110 -0
  36. package/examples/todo-list/cli-client/source/commands/remove/TodoCLI-Command-Remove.js +49 -0
  37. package/examples/todo-list/cli-client/source/services/TodoCLI-Service-API.js +92 -0
  38. package/examples/todo-list/console-client/console-client.cjs +913 -0
  39. package/examples/todo-list/console-client/package-lock.json +426 -0
  40. package/examples/todo-list/console-client/package.json +19 -0
  41. package/examples/todo-list/console-client/views/PictView-TUI-Header.cjs +43 -0
  42. package/examples/todo-list/console-client/views/PictView-TUI-Layout.cjs +58 -0
  43. package/examples/todo-list/console-client/views/PictView-TUI-StatusBar.cjs +41 -0
  44. package/examples/todo-list/console-client/views/PictView-TUI-TaskList.cjs +104 -0
  45. package/examples/todo-list/docker-motd.sh +36 -0
  46. package/examples/todo-list/docker-run.sh +2 -0
  47. package/examples/todo-list/docker-shell.sh +2 -0
  48. package/examples/todo-list/model/MeadowSchema-Task.json +152 -0
  49. package/examples/todo-list/model/Task-Compiled.json +25 -0
  50. package/examples/todo-list/model/Task.mddl +15 -0
  51. package/examples/todo-list/model/data/seeded_todo_events.csv +1001 -0
  52. package/examples/todo-list/server/database-initialization-service.cjs +273 -0
  53. package/examples/todo-list/server/package-lock.json +6113 -0
  54. package/examples/todo-list/server/package.json +19 -0
  55. package/examples/todo-list/server/server.cjs +138 -0
  56. package/examples/todo-list/web-client/css/todolist-theme.css +235 -0
  57. package/examples/todo-list/web-client/generate-build-config.cjs +18 -0
  58. package/examples/todo-list/web-client/html/index.html +18 -0
  59. package/examples/todo-list/web-client/package-lock.json +12030 -0
  60. package/examples/todo-list/web-client/package.json +43 -0
  61. package/examples/todo-list/web-client/source/TodoList-Application-Config.json +12 -0
  62. package/examples/todo-list/web-client/source/TodoList-Application.cjs +383 -0
  63. package/examples/todo-list/web-client/source/providers/Provider-TaskData.cjs +243 -0
  64. package/examples/todo-list/web-client/source/providers/Router-Config.json +32 -0
  65. package/examples/todo-list/web-client/source/views/View-Layout.cjs +75 -0
  66. package/examples/todo-list/web-client/source/views/View-TaskForm.cjs +87 -0
  67. package/examples/todo-list/web-client/source/views/View-TaskList.cjs +127 -0
  68. package/examples/todo-list/web-client/source/views/calendar/View-MonthView.cjs +293 -0
  69. package/examples/todo-list/web-client/source/views/calendar/View-WeekView.cjs +149 -0
  70. package/examples/todo-list/web-client/source/views/calendar/View-YearView.cjs +226 -0
  71. package/modules/Include-Retold-Module-List.sh +2 -2
  72. package/package.json +5 -5
  73. package/docs/js/pict.min.js +0 -12
  74. package/docs/js/pict.min.js.map +0 -1
  75. package/docs/pict-docuserve.min.js +0 -58
  76. package/docs/pict-docuserve.min.js.map +0 -1
  77. /package/docs/{architecture.md → architecture/architecture.md} +0 -0
  78. /package/docs/{fable.md → modules/fable.md} +0 -0
@@ -52,7 +52,44 @@
52
52
  "Bash(kill:*)",
53
53
  "Bash(wait)",
54
54
  "Bash(while read d)",
55
- "Bash(do echo \"Cleaning: $d\")"
55
+ "Bash(do echo \"Cleaning: $d\")",
56
+ "Bash(git pull:*)",
57
+ "Bash(git push:*)",
58
+ "Bash(git add:*)",
59
+ "Bash(git rebase:*)",
60
+ "Bash(git commit:*)",
61
+ "Bash(cd:*)",
62
+ "Bash(node source/cli/Meadow-Integration-CLI-Run.js:*)",
63
+ "Bash(bash:*)",
64
+ "Bash(npm test)",
65
+ "WebFetch(domain:stevenvelozo.github.io)",
66
+ "Bash(git ls-tree:*)",
67
+ "Bash(npx mocha:*)",
68
+ "Bash(pkill:*)",
69
+ "Bash(ln:*)",
70
+ "Bash(timeout 10 node:*)",
71
+ "Bash(npm ls:*)",
72
+ "Bash(node -e \"\nconst proc = require\\(''child_process''\\).spawn\\(''node'', [''server.cjs''], { cwd: ''/Users/stevenvelozo/Code/retold/examples/todo-list/server'', stdio: ''pipe'' }\\);\nlet output = '''';\nproc.stdout.on\\(''data'', \\(d\\) => { output += d.toString\\(\\); }\\);\nproc.stderr.on\\(''data'', \\(d\\) => { output += d.toString\\(\\); }\\);\nsetTimeout\\(\\(\\) => {\n const http = require\\(''http''\\);\n\n // Test 1: Static HTML serving\n http.get\\(''http://localhost:8086/'', \\(res\\) => {\n let data = '''';\n res.on\\(''data'', \\(c\\) => { data += c; }\\);\n res.on\\(''end'', \\(\\) => {\n console.log\\(''=== Test 1: Static HTML ===''\\);\n console.log\\(''Status:'', res.statusCode\\);\n console.log\\(''Contains RetoldExampleTodoWebClient:'', data.includes\\(''RetoldExampleTodoWebClient''\\)\\);\n\n // Test 2: API list\n http.get\\(''http://localhost:8086/1.0/Tasks'', \\(res2\\) => {\n let data2 = '''';\n res2.on\\(''data'', \\(c\\) => { data2 += c; }\\);\n res2.on\\(''end'', \\(\\) => {\n let tasks = JSON.parse\\(data2\\);\n console.log\\(''''\\);\n console.log\\(''=== Test 2: API Reads ===''\\);\n console.log\\(''Tasks returned:'', tasks.length\\);\n\n // Test 3: Create\n let postData = JSON.stringify\\({Name:''CJS test'',Status:''Pending'',LengthInHours:1}\\);\n let req = http.request\\({hostname:''localhost'',port:8086,path:''/1.0/Task'',method:''POST'',headers:{''Content-Type'':''application/json''}}, \\(res3\\) => {\n let data3 = '''';\n res3.on\\(''data'', \\(c\\) => { data3 += c; }\\);\n res3.on\\(''end'', \\(\\) => {\n let created = JSON.parse\\(data3\\);\n console.log\\(''''\\);\n console.log\\(''=== Test 3: Create ===''\\);\n console.log\\(''Created ID:'', created.IDTask, ''Name:'', created.Name\\);\n\n // Test 4: Update\n let putData = JSON.stringify\\({IDTask:created.IDTask, Name:''CJS test \\(updated\\)'', Status:''Complete''}\\);\n let req2 = http.request\\({hostname:''localhost'',port:8086,path:''/1.0/Task'',method:''PUT'',headers:{''Content-Type'':''application/json''}}, \\(res4\\) => {\n let data4 = '''';\n res4.on\\(''data'', \\(c\\) => { data4 += c; }\\);\n res4.on\\(''end'', \\(\\) => {\n let updated = JSON.parse\\(data4\\);\n console.log\\(''''\\);\n console.log\\(''=== Test 4: Update ===''\\);\n console.log\\(''Updated:'', updated.Name, updated.Status\\);\n\n // Test 5: Delete\n let req3 = http.request\\({hostname:''localhost'',port:8086,path:''/1.0/Task/''+created.IDTask,method:''DELETE''}, \\(res5\\) => {\n let data5 = '''';\n res5.on\\(''data'', \\(c\\) => { data5 += c; }\\);\n res5.on\\(''end'', \\(\\) => {\n let del = JSON.parse\\(data5\\);\n console.log\\(''''\\);\n console.log\\(''=== Test 5: Delete ===''\\);\n console.log\\(''Deleted count:'', del.Count\\);\n console.log\\(''''\\);\n console.log\\(''=== ALL TESTS PASSED ===''\\);\n proc.kill\\(\\);\n process.exit\\(0\\);\n }\\);\n }\\);\n req3.end\\(\\);\n }\\);\n }\\);\n req2.write\\(putData\\);\n req2.end\\(\\);\n }\\);\n }\\);\n req.write\\(postData\\);\n req.end\\(\\);\n }\\);\n }\\);\n }\\);\n }\\);\n}, 3000\\);\n\")",
73
+ "Bash(node -e \" const _origStderrWrite = process.stderr.write; process.stderr.write = function \\(pChunk\\) { if \\(typeof pChunk === ''string'' && pChunk.indexOf\\(''Setulc''\\) !== -1\\) { return true; } return _origStderrWrite.apply\\(process.stderr, arguments\\); }; const blessed = require\\(''blessed''\\); const libPict = require\\(''pict''\\); const libPictApplication = require\\(''pict-application''\\); const libPictTerminalUI = require\\(''pict-terminalui''\\); const libViewLayout = require\\(''/Users/stevenvelozo/Code/retold/examples/todo-list/console-client/views/PictView-TUI-Layout.cjs''\\); const libViewHeader = require\\(''/Users/stevenvelozo/Code/retold/examples/todo-list/console-client/views/PictView-TUI-Header.cjs''\\); const libViewTaskList = require\\(''/Users/stevenvelozo/Code/retold/examples/todo-list/console-client/views/PictView-TUI-TaskList.cjs''\\); const libViewStatusBar = require\\(''/Users/stevenvelozo/Code/retold/examples/todo-list/console-client/views/PictView-TUI-StatusBar.cjs''\\); console.log\\(''All console-client .cjs modules loaded OK''\\); console.log\\(''Views:'', [libViewLayout, libViewHeader, libViewTaskList, libViewStatusBar].map\\(v => v.default_configuration.ViewIdentifier\\).join\\('', ''\\)\\); process.exit\\(0\\); \")",
74
+ "Bash(node Stricture.js:*)",
75
+ "Bash(timeout 15 node:*)",
76
+ "Bash(npm update:*)",
77
+ "Bash(awk:*)",
78
+ "Bash(/Users/stevenvelozo/Code/retold/examples/todo-list/model/data/fix_csv.py << 'PYEOF'\nimport re\n\nINPUT_FILE = '/Users/stevenvelozo/Code/retold/examples/todo-list/model/data/seeded_todo_events.csv'\n\nwith open\\(INPUT_FILE, 'r'\\) as f:\n lines = f.readlines\\(\\)\n\nheader = lines[0].strip\\(\\)\noutput_lines = [header]\n\n# Pattern for the last 3 fields: date, number, status\n# DueDate is YYYY-MM-DD, LengthInHours is a number \\(int or float\\), Status is one of three values\ntail_pattern = re.compile\\(r',\\(\\\\d{4}-\\\\d{2}-\\\\d{2}\\),\\([\\\\d.]+\\),\\(Pending|In Progress|Complete\\)\\\\s*\\)\n\nfor i, line in enumerate\\(lines[1:], start=2\\):\n line = line.strip\\(\\)\n if not line:\n continue\n\n # Find the tail \\(DueDate, LengthInHours, Status\\) from the right\n match = tail_pattern.search\\(line\\)\n if not match:\n print\\(f\"WARNING: Line {i} does not match expected tail pattern: {line[:80]}\"\\)\n output_lines.append\\(line\\)\n continue\n\n tail_start = match.start\\(\\)\n due_date = match.group\\(1\\)\n length = match.group\\(2\\)\n status = match.group\\(3\\)\n\n # Everything before the tail is \"Name,Description\" \\(with possible extra commas in Description\\)\n front = line[:tail_start]\n\n # Split front into Name and Description at the first comma\n first_comma = front.index\\(','\\)\n name = front[:first_comma]\n description = front[first_comma + 1:]\n\n # Strip any existing surrounding quotes from the description\n if description.startswith\\('\"'\\) and description.endswith\\('\"'\\):\n description = description[1:-1]\n\n # Escape any double quotes inside the description \\(double them per CSV standard\\)\n description = description.replace\\('\"', '\"\"'\\)\n\n # Reconstruct the line with the description properly quoted\n fixed_line = f'{name},\"{description}\",{due_date},{length},{status}'\n output_lines.append\\(fixed_line\\)\n\nwith open\\(INPUT_FILE, 'w'\\) as f:\n f.write\\('\\\\n'.join\\(output_lines\\) + '\\\\n'\\)\n\nprint\\(f\"Processed {len\\(output_lines\\) - 1} data rows \\(plus header\\).\"\\)\nprint\\(\"File written successfully.\"\\)\nPYEOF)",
79
+ "Bash(for f in architecture.md fable.md meadow.md orator.md pict.md utility.md modules.md examples.md todo-list.md todo-list-model.md todo-list-server.md todo-list-web-client.md todo-list-console-client.md todo-list-cli-client.md)",
80
+ "Bash(do [ -f \"/Users/stevenvelozo/Code/retold/docs/$f\" ])",
81
+ "WebFetch(domain:registry.npmjs.org)",
82
+ "WebFetch(domain:data.jsdelivr.com)",
83
+ "WebFetch(domain:purge.jsdelivr.net)",
84
+ "WebFetch(domain:raw.githubusercontent.com)",
85
+ "Bash(npx quack prepare-docs:*)",
86
+ "Bash(xargs kill)",
87
+ "WebFetch(domain:cdn.jsdelivr.net)",
88
+ "Bash(git stash:*)",
89
+ "Bash(npx indoctrinate:*)",
90
+ "Bash(npm link)",
91
+ "Bash(npm link:*)",
92
+ "Bash(indoctrinate --version:*)"
56
93
  ]
57
94
  }
58
95
  }
package/README.md CHANGED
@@ -1,2 +1,92 @@
1
- # retold
2
- A story-obsessed application suite.
1
+ # Retold
2
+
3
+ > A story-obsessed application suite.
4
+
5
+ Retold is a collection of ~50 JavaScript/Node.js modules for building web applications and APIs. The modules span five groups — from core dependency injection up through data access, API serving, and full MVC — all designed to compose together through a shared service provider pattern. Plain JavaScript, no TypeScript. MIT licensed.
6
+
7
+ ## Module Groups
8
+
9
+ | Group | Purpose |
10
+ |-------|---------|
11
+ | **Fable** | Core ecosystem: dependency injection, configuration, logging, UUID generation, expression parsing, REST client, template engine |
12
+ | **Meadow** | Data access layer: provider-agnostic ORM, query generation (FoxHound), schema definitions (Stricture), database connectors (MySQL, MSSQL, SQLite), auto-generated REST endpoints |
13
+ | **Orator** | API server: HTTP server abstraction over Restify, static file serving, reverse proxy, WebSocket reporting |
14
+ | **Pict** | MVC tools: views, templates, providers, application lifecycle — for browser, terminal, or any text-based UI |
15
+ | **Utility** | Build tools (Quackage), manifest management (Manyfest), documentation generation (Indoctrinate), process supervision (Ultravisor) |
16
+
17
+ ## The Service Provider Pattern
18
+
19
+ Every Retold module extends `fable-serviceproviderbase` and registers with a Fable instance. That instance provides dependency injection, logging, UUID generation, and shared configuration. Any registered service can reach any other through `this.fable`, so modules are loosely coupled — you can swap database providers, change server implementations, or add custom services without modifying existing code.
20
+
21
+ ```javascript
22
+ const libFable = require('fable');
23
+ const libMeadow = require('meadow');
24
+ const libOrator = require('orator');
25
+
26
+ let _Fable = new libFable({ Product: 'MyApp', LogLevel: 3 });
27
+
28
+ // Services register with the Fable instance
29
+ let _Meadow = _Fable.instantiateServiceProvider('Meadow');
30
+ let _Orator = _Fable.instantiateServiceProvider('Orator');
31
+
32
+ // Every service can reach every other service
33
+ // _Meadow.fable.Orator, _Orator.fable.Meadow, etc.
34
+ ```
35
+
36
+ ## Quick Start
37
+
38
+ ```bash
39
+ # Core foundation
40
+ npm install fable
41
+
42
+ # Data access
43
+ npm install meadow foxhound stricture
44
+
45
+ # API server
46
+ npm install orator orator-serviceserver-restify meadow-endpoints
47
+
48
+ # Browser MVC
49
+ npm install pict
50
+ ```
51
+
52
+ ```javascript
53
+ const libFable = require('fable');
54
+
55
+ let _Fable = new libFable({
56
+ Product: 'MyApp',
57
+ ProductVersion: '1.0.0',
58
+ LogLevel: 3
59
+ });
60
+
61
+ _Fable.log.info('Retold application started.');
62
+ ```
63
+
64
+ ## Repository Structure
65
+
66
+ Each module is its own git repo, cloned into a category folder under `modules/`. The root repo tracks module organization — individual module code lives in their respective repos.
67
+
68
+ ```
69
+ retold/
70
+ ├── source/Retold.cjs
71
+ ├── test/
72
+ ├── docs/ # Documentation site (pict-docuserve)
73
+ └── modules/
74
+ ├── fable/ # Core ecosystem (~6 modules)
75
+ ├── meadow/ # Data access (~13 modules)
76
+ ├── orator/ # API server (~7 modules)
77
+ ├── pict/ # MVC tools (~15 modules)
78
+ └── utility/ # Build & docs (~10 modules)
79
+ ```
80
+
81
+ ## Documentation
82
+
83
+ Full documentation lives in the [`docs/`](docs/) folder and is served by pict-docuserve.
84
+
85
+ - [Architecture](docs/architecture/architecture.md) — Layer model, service provider pattern, component breakdown
86
+ - [Getting Started](docs/getting-started.md) — Building your first Retold application step by step
87
+ - [Examples](docs/examples/examples.md) — Complete runnable applications including a full-stack Todo List
88
+ - [All Modules](docs/architecture/modules.md) — Every repository in the suite with descriptions and links
89
+
90
+ ## License
91
+
92
+ MIT
package/docs/README.md CHANGED
@@ -148,13 +148,14 @@ _Fable.log.info('Retold application started.');
148
148
 
149
149
  ## Learn More
150
150
 
151
- - **[Architecture](architecture.md)** — Detailed layer-by-layer breakdown of the module stack
151
+ - **[Architecture](architecture/architecture.md)** — Detailed layer-by-layer breakdown of the module stack
152
152
  - **[Getting Started](getting-started.md)** — Building your first Retold application
153
- - **[Fable In Depth](fable.md)** — The core ecosystem and service provider pattern
154
- - **[Meadow In Depth](meadow.md)** — Data access, schemas, and query generation
155
- - **[Orator In Depth](orator.md)** — API servers and endpoint generation
156
- - **[Pict In Depth](pict.md)** — MVC tools for browser and console UIs
157
- - **[All Modules](modules.md)** — Exhaustive list of every Retold repository
153
+ - **[Examples](examples/examples.md)** — Complete runnable applications including the Todo List full-stack example
154
+ - **[Fable In Depth](modules/fable.md)** — The core ecosystem and service provider pattern
155
+ - **[Meadow In Depth](modules/meadow.md)** — Data access, schemas, and query generation
156
+ - **[Orator In Depth](modules/orator.md)** — API servers and endpoint generation
157
+ - **[Pict In Depth](modules/pict.md)** — MVC tools for browser and console UIs
158
+ - **[All Modules](modules/modules.md)** — Exhaustive list of every Retold repository
158
159
 
159
160
  ## License
160
161
 
package/docs/_sidebar.md CHANGED
@@ -1,10 +1,22 @@
1
1
  - Getting Started
2
2
 
3
- - [Architecture](architecture.md)
4
3
  - [Getting Started](getting-started.md)
5
- - [All Modules](modules.md)
4
+ - [Architecture](architecture/architecture.md)
5
+ - [Ecosystem Architecture](architecture/module-architecture.md)
6
+ - [Fluid Models](architecture/fluid-models.md)
7
+ - [Comprehensions](architecture/comprehensions.md)
8
+ - [All Modules](architecture/modules.md)
6
9
 
7
- - [Fable — Core Ecosystem](fable.md)
10
+ - [Examples](examples/examples.md)
11
+
12
+ - [Todo List Application](examples/todolist/todo-list.md)
13
+ - [Todo List: System Model](examples/todolist/todo-list-model.md)
14
+ - [Todo List: API Server](examples/todolist/todo-list-server.md)
15
+ - [Todo List: Web Client](examples/todolist/todo-list-web-client.md)
16
+ - [Todo List: Console Client](examples/todolist/todo-list-console-client.md)
17
+ - [Todo List: CLI Client](examples/todolist/todo-list-cli-client.md)
18
+
19
+ - [Fable — Core Ecosystem](modules/fable.md)
8
20
 
9
21
  - [fable](/fable/fable/)
10
22
  - [fable-serviceproviderbase](/fable/fable-serviceproviderbase/)
@@ -13,23 +25,22 @@
13
25
  - [fable-uuid](/fable/fable-uuid/)
14
26
  - [fable-log-logger-bunyan](/fable/fable-log-logger-bunyan/)
15
27
 
16
- - [Meadow — Data Access](meadow.md)
28
+ - [Meadow — Data Access](modules/meadow.md)
17
29
 
18
- - [meadow](/meadow/meadow/)
19
- - [foxhound](/meadow/foxhound/)
20
30
  - [stricture](/meadow/stricture/)
31
+ - [foxhound](/meadow/foxhound/)
32
+ - [bibliograph](/meadow/bibliograph/)
33
+ - [meadow](/meadow/meadow/)
34
+ - [parime](/meadow/parime/)
21
35
  - [meadow-endpoints](/meadow/meadow-endpoints/)
22
- - [retold-data-service](/meadow/retold-data-service/)
23
36
  - [meadow-connection-mysql](/meadow/meadow-connection-mysql/)
24
37
  - [meadow-connection-mssql](/meadow/meadow-connection-mssql/)
25
38
  - [meadow-connection-sqlite](/meadow/meadow-connection-sqlite/)
39
+ - [retold-data-service](/meadow/retold-data-service/)
26
40
  - [retold-harness](/meadow/retold-harness/)
27
- - [bibliograph](/meadow/bibliograph/)
28
- - [parime](/meadow/parime/)
29
41
  - [meadow-integration](/meadow/meadow-integration/)
30
- - [meadow-graph-client](/meadow/meadow-graph-client/)
31
42
 
32
- - [Orator — API Server](orator.md)
43
+ - [Orator — API Server](modules/orator.md)
33
44
 
34
45
  - [orator](/orator/orator/)
35
46
  - [orator-serviceserver-restify](/orator/orator-serviceserver-restify/)
@@ -37,29 +48,33 @@
37
48
  - [orator-http-proxy](/orator/orator-http-proxy/)
38
49
  - [tidings](/orator/tidings/)
39
50
  - [orator-endpoint](/orator/orator-endpoint/)
51
+ - [orator-conversion](/orator/orator-conversion/)
40
52
 
41
- - [Pict — MVC Tools](pict.md)
53
+ - [Pict — MVC Tools](modules/pict.md)
42
54
 
43
55
  - [pict](/pict/pict/)
44
- - [pict-view](/pict/pict-view/)
45
56
  - [pict-template](/pict/pict-template/)
57
+ - [pict-view](/pict/pict-view/)
46
58
  - [pict-provider](/pict/pict-provider/)
47
59
  - [pict-application](/pict/pict-application/)
48
- - [pict-section-form](/pict/pict-section-form/)
60
+ - [pict-panel](/pict/pict-panel/)
61
+ - [pict-nonlinearconfig](/pict/pict-nonlinearconfig/)
62
+ - [pict-section-flow](/pict/pict-section-flow/)
63
+ - [pict-docuserve](/pict/pict-docuserve/)
64
+ - [cryptbrau](/pict/cryptbrau/)
65
+ - [informary](/pict/informary/)
66
+ - [pict-service-commandlineutility](/pict/pict-service-commandlineutility/)
49
67
  - [pict-section-recordset](/pict/pict-section-recordset/)
50
- - [pict-section-tuigrid](/pict/pict-section-tuigrid/)
51
68
  - [pict-section-content](/pict/pict-section-content/)
52
- - [pict-panel](/pict/pict-panel/)
69
+ - [pict-section-form](/pict/pict-section-form/)
70
+ - [pict-section-tuigrid](/pict/pict-section-tuigrid/)
53
71
  - [pict-router](/pict/pict-router/)
54
- - [informary](/pict/informary/)
55
- - [cryptbrau](/pict/cryptbrau/)
56
72
  - [pict-serviceproviderbase](/pict/pict-serviceproviderbase/)
57
- - [pict-service-commandlineutility](/pict/pict-service-commandlineutility/)
73
+ - [pict-terminalui](/pict/pict-terminalui/)
58
74
 
59
- - [Utility — Build Tools](utility.md)
75
+ - [Utility — Build Tools](modules/utility.md)
60
76
 
61
77
  - [indoctrinate](/utility/indoctrinate/)
62
78
  - [manyfest](/utility/manyfest/)
63
79
  - [quackage](/utility/quackage/)
64
- - [choreographic](/utility/choreographic/)
65
80
  - [ultravisor](/utility/ultravisor/)
package/docs/_topbar.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Retold
2
2
 
3
3
  - [Getting Started](getting-started.md)
4
- - [Architecture](architecture.md)
5
- - [All Modules](modules.md)
4
+ - [Architecture](architecture/architecture.md)
5
+ - [All Modules](architecture/modules.md)
6
6
  - [GitHub](https://github.com/stevenvelozo/retold)
@@ -0,0 +1,282 @@
1
+ # Comprehensions
2
+
3
+ Comprehensions are the intermediate data format that Retold uses for data integration pipelines. When you need to ingest records from external systems — CSV files, JSON feeds, other databases — comprehensions provide a consistent structure for staging, deduplicating, merging, and cross-referencing that data before it reaches Meadow.
4
+
5
+ The modules [bibliograph](/meadow/bibliograph/) and [meadow-integration](/meadow/meadow-integration/) both work with comprehensions. Bibliograph provides key-value record comprehension for change tracking. Meadow-integration provides the full transformation and integration pipeline — mapping source data into comprehensions and pushing them into Meadow entities through the integration adapter.
6
+
7
+ ## The Object Format
8
+
9
+ A comprehension is traditionally a JSON object where entity records are keyed by their GUID. This is the primary format and the one the integration pipeline works with internally.
10
+
11
+ ```json
12
+ {
13
+ "Book": {
14
+ "Book_1": { "GUIDBook": "Book_1", "Title": "The Hunger Games", "ISBN": "9780439023481" },
15
+ "Book_2": { "GUIDBook": "Book_2", "Title": "Dune", "ISBN": "9780441172719" }
16
+ },
17
+ "Author": {
18
+ "Author_SuzanneCollins": { "GUIDAuthor": "Author_SuzanneCollins", "Name": "Suzanne Collins" },
19
+ "Author_FrankHerbert": { "GUIDAuthor": "Author_FrankHerbert", "Name": "Frank Herbert" }
20
+ }
21
+ }
22
+ ```
23
+
24
+ Each top-level key is an entity name. Within each entity, records are stored as properties keyed by their GUID value. This gives you:
25
+
26
+ - **O(1) lookup** — find any record by GUID without scanning
27
+ - **Natural deduplication** — writing the same GUID twice merges rather than duplicates
28
+ - **Easy merging** — `Object.assign()` combines records from multiple sources
29
+ - **Multi-entity support** — a single comprehension can hold Books, Authors, and join records together
30
+
31
+ ## The Array Format
32
+
33
+ Comprehensions can also be arrays of records. This format is useful for export, for consumption by tools that expect flat record lists, or for feeding data to systems and softwares that do not benefit from GUID-keyed lookup.
34
+
35
+ ```json
36
+ [
37
+ { "GUIDBook": "Book_1", "Title": "The Hunger Games", "ISBN": "9780439023481" },
38
+ { "GUIDBook": "Book_2", "Title": "Dune", "ISBN": "9780441172719" }
39
+ ]
40
+ ```
41
+
42
+ The array format loses the O(1) lookup performance and the automatic deduplication of the object format. You convert between the two formats using the `comprehensionarray` command or the `/1.0/Comprehension/ToArray` endpoint.
43
+
44
+ ## How Data Flows Through Comprehensions
45
+
46
+ Source data enters the integration pipeline through mapping files, gets staged as a comprehension, and then flows through the integration adapter into Meadow entities.
47
+
48
+ ```mermaid
49
+ graph LR
50
+ source["Source Data<br/><i>CSV, JSON, TSV</i>"]
51
+ mapping["Mapping File<br/><i>GUIDTemplate,<br/>field mappings,<br/>solvers</i>"]
52
+ comp["Comprehension<br/><i>GUID-keyed<br/>entity records</i>"]
53
+ adapter["Integration<br/>Adapter<br/><i>Marshal, upsert</i>"]
54
+ meadow["Meadow<br/>Entities<br/><i>Database records</i>"]
55
+
56
+ source --> mapping
57
+ mapping --> comp
58
+ comp --> adapter
59
+ adapter --> meadow
60
+
61
+ style source fill:#f5f5f5,stroke:#bdbdbd,color:#333
62
+ style mapping fill:#fff3e0,stroke:#ffa726,color:#333
63
+ style comp fill:#fff3e0,stroke:#ffa726,color:#333
64
+ style adapter fill:#fff3e0,stroke:#ffa726,color:#333
65
+ style meadow fill:#fff3e0,stroke:#ff9800,color:#333
66
+ ```
67
+
68
+ Mapping files control the transformation from source columns to comprehension fields. They define the entity name, the GUID template, and the field-by-field mappings using Pict template expressions.
69
+
70
+ ## GUID Design
71
+
72
+ GUIDs are the primary key for comprehension records. Good GUID design ensures three things:
73
+
74
+ - **Uniqueness** — each record gets a distinct key
75
+ - **Determinism** — the same source data always generates the same GUID
76
+ - **Mergeability** — related data from different sources can be matched by GUID
77
+
78
+ GUID templates use Pict's jellyfish template syntax (`{~D:...~}`) to pull values from the source record:
79
+
80
+ ```json
81
+ {
82
+ "Entity": "Book",
83
+ "GUIDTemplate": "Book_{~D:Record.id~}",
84
+ "Mappings": {
85
+ "Title": "{~D:Record.title~}",
86
+ "ISBN": "{~D:Record.isbn~}"
87
+ }
88
+ }
89
+ ```
90
+
91
+ This produces records keyed by `Book_1`, `Book_2`, etc. When the same GUID template is used across multiple transform runs on different source files, records with matching GUIDs merge automatically in the comprehension.
92
+
93
+ ## Combinatorial Keys
94
+
95
+ When no single source column provides a natural unique key, you build a combinatorial GUID from multiple columns.
96
+
97
+ ```json
98
+ {
99
+ "Entity": "Transaction",
100
+ "GUIDTemplate": "TXN_{~D:Record.date~}_{~D:Record.account_id~}_{~D:Record.seq~}",
101
+ "Mappings": {
102
+ "Amount": "{~D:Record.amount~}",
103
+ "AccountID": "{~D:Record.account_id~}",
104
+ "TransactionDate": "{~D:Record.date~}"
105
+ }
106
+ }
107
+ ```
108
+
109
+ This produces GUIDs like `TXN_2025-02-17_12345_001` — unique across the combination of date, account, and sequence number. The composite key ensures that two transactions on the same day for the same account are distinguishable, while the determinism means re-running the transform on the same source data produces the same GUIDs (merging cleanly rather than creating duplicates).
110
+
111
+ Format modifiers like `{~PascalCaseIdentifier:Record.name~}` are useful in combinatorial keys when the source values contain spaces or special characters that would make messy GUIDs.
112
+
113
+ ## The `_GUID` Prefix — Bypassing Magic Marshaling
114
+
115
+ When the integration adapter pushes comprehension records into Meadow, places a prefix on GUID fields based on the integration being run. This can signify the source system, data set or anything else the developer wants to connote in the GUID string itself. The underscore prefix controls which code path a GUID field takes.
116
+
117
+ **`GUIDBook`** — a field starting with `GUID` is treated as an **external system GUID**. The adapter runs it through the full marshaling pipeline: it looks up the external GUID in the mapping table to find the corresponding Meadow numeric ID, and writes that ID into the output record as `IDBook`.
118
+
119
+ **`_GUIDBook`** — a field starting with `_GUID` is treated as a **Meadow GUID** that already exists in the system. The adapter skips the external-to-internal translation and does a direct lookup from Meadow GUID to numeric ID. No prefix magic is applied.
120
+
121
+ ```json
122
+ {
123
+ "BookReview": {
124
+ "Review_1": {
125
+ "GUIDBookReview": "Review_1",
126
+ "GUIDBook": "Book_1",
127
+ "_GUIDUser": "0x01234567"
128
+ }
129
+ }
130
+ }
131
+ ```
132
+
133
+ In this example, `GUIDBook` with value `Book_1` is an external key from the comprehension — the adapter will look up what Meadow ID corresponds to external GUID `Book_1`. But `_GUIDUser` with value `0x01234567` is already a Meadow GUID — the adapter looks it up directly without applying the integration prefix.
134
+
135
+ The distinction matters when you are integrating data that references both external records (from the same import batch) and existing Meadow records (already in the database). Use `GUID` for references within the comprehension. Use `_GUID` when pointing at records that already exist in Meadow.
136
+
137
+ ## Cross-Connecting Recordsets
138
+
139
+ Comprehensions handle relationships between entities through GUID cross-references. A record in one entity can reference records in other entities by including `GUID`-prefixed fields that match the target entity's GUID values.
140
+
141
+ ### Join Tables from a Single Source
142
+
143
+ A common pattern is generating join table records from a single source that contains embedded relationships. For example, a books CSV where the `authors` column contains comma-separated names:
144
+
145
+ ```
146
+ id,title,authors
147
+ 1,The Hunger Games,"Suzanne Collins"
148
+ 2,Dune,"Frank Herbert"
149
+ 3,Good Omens,"Terry Pratchett,Neil Gaiman"
150
+ ```
151
+
152
+ Three mapping files transform this one CSV into three related entity sets:
153
+
154
+ **Books:**
155
+ ```json
156
+ {
157
+ "Entity": "Book",
158
+ "GUIDTemplate": "Book_{~D:Record.id~}",
159
+ "Mappings": { "Title": "{~D:Record.title~}" }
160
+ }
161
+ ```
162
+
163
+ **Authors** (one source row can produce multiple records):
164
+ ```json
165
+ {
166
+ "Entity": "Author",
167
+ "MultipleGUIDUniqueness": true,
168
+ "Solvers": [
169
+ "NewRecordsGUIDUniqueness = STRINGGETSEGMENTS(IncomingRecord.authors,\",\")"
170
+ ],
171
+ "GUIDTemplate": "Author_{~PascalCaseIdentifier:Record._GUIDUniqueness~}",
172
+ "Mappings": { "Name": "{~D:Record._GUIDUniqueness~}" }
173
+ }
174
+ ```
175
+
176
+ **BookAuthorJoin** (cross-references both entities):
177
+ ```json
178
+ {
179
+ "Entity": "BookAuthorJoin",
180
+ "MultipleGUIDUniqueness": true,
181
+ "Solvers": [
182
+ "NewRecordsGUIDUniqueness = STRINGGETSEGMENTS(IncomingRecord.authors,\",\")"
183
+ ],
184
+ "GUIDTemplate": "BAJ_A_{~PascalCaseIdentifier:Record._GUIDUniqueness~}_B_{~D:Record.id~}",
185
+ "Mappings": {
186
+ "GUIDBook": "Book_{~D:Record.id~}",
187
+ "GUIDAuthor": "Author_{~PascalCaseIdentifier:Record._GUIDUniqueness~}"
188
+ }
189
+ }
190
+ ```
191
+
192
+ The `MultipleGUIDUniqueness` flag combined with a Solver expression splits the comma-separated authors into individual entries. For each entry, the system creates a separate record with `_GUIDUniqueness` set to that entry's value. The GUID template and mappings use `_GUIDUniqueness` to build unique keys and cross-references.
193
+
194
+ For "Good Omens" with two authors, this produces:
195
+
196
+ ```mermaid
197
+ graph TB
198
+ subgraph Comprehension["Resulting Comprehension"]
199
+ direction TB
200
+ subgraph Books["Book"]
201
+ b3["<b>Book_3</b><br/>Title: Good Omens"]
202
+ end
203
+ subgraph Authors["Author"]
204
+ a1["<b>Author_TerryPratchett</b><br/>Name: Terry Pratchett"]
205
+ a2["<b>Author_NeilGaiman</b><br/>Name: Neil Gaiman"]
206
+ end
207
+ subgraph Joins["BookAuthorJoin"]
208
+ j1["<b>BAJ_A_TerryPratchett_B_3</b>"]
209
+ j2["<b>BAJ_A_NeilGaiman_B_3</b>"]
210
+ end
211
+ end
212
+
213
+ j1 -. "GUIDBook" .-> b3
214
+ j1 -. "GUIDAuthor" .-> a1
215
+ j2 -. "GUIDBook" .-> b3
216
+ j2 -. "GUIDAuthor" .-> a2
217
+
218
+ style Comprehension fill:#fff8e1,stroke:#ffcc80,color:#333
219
+ style Books fill:#fff3e0,stroke:#ffa726,color:#333
220
+ style Authors fill:#fff3e0,stroke:#ffa726,color:#333
221
+ style Joins fill:#fff3e0,stroke:#ffa726,color:#333
222
+ style b3 fill:#fff,stroke:#ffcc80,color:#333
223
+ style a1 fill:#fff,stroke:#ffcc80,color:#333
224
+ style a2 fill:#fff,stroke:#ffcc80,color:#333
225
+ style j1 fill:#fff,stroke:#ffcc80,color:#333
226
+ style j2 fill:#fff,stroke:#ffcc80,color:#333
227
+ ```
228
+
229
+ The join records contain `GUIDBook` and `GUIDAuthor` fields whose values match the GUIDs of the Book and Author entities. When the integration adapter pushes these records to Meadow, it resolves each GUID cross-reference to the corresponding numeric ID, producing proper foreign key relationships in the database.
230
+
231
+ ### Merging Across Sources
232
+
233
+ When the same entities have data spread across multiple source files, comprehension merging combines them by GUID. The `comprehensionintersect` command (or `/1.0/Comprehension/Intersect` endpoint) takes two comprehensions and merges records with matching GUIDs:
234
+
235
+ ```json
236
+ // Primary: population data
237
+ {
238
+ "Neighborhood": {
239
+ "SEATTLE_BALLARD": { "GUIDNeighborhood": "SEATTLE_BALLARD", "Name": "Ballard", "Population": 50000 }
240
+ }
241
+ }
242
+
243
+ // Secondary: housing data
244
+ {
245
+ "Neighborhood": {
246
+ "SEATTLE_BALLARD": { "GUIDNeighborhood": "SEATTLE_BALLARD", "MedianHomePrice": 750000 }
247
+ }
248
+ }
249
+
250
+ // Merged result
251
+ {
252
+ "Neighborhood": {
253
+ "SEATTLE_BALLARD": { "GUIDNeighborhood": "SEATTLE_BALLARD", "Name": "Ballard", "Population": 50000, "MedianHomePrice": 750000 }
254
+ }
255
+ }
256
+ ```
257
+
258
+ This is why deterministic GUID design matters — when two sources use the same GUID template for the same logical entity, their data merges cleanly.
259
+
260
+ ## The Integration Adapter: GUID to Database ID
261
+
262
+ When comprehension records are pushed into Meadow through the integration adapter, a three-layer GUID transformation maps external identifiers to database IDs:
263
+
264
+ ```mermaid
265
+ graph LR
266
+ ext["External GUID<br/><code>Book_1</code><br/><i>from comprehension</i>"]
267
+ mguid["Meadow GUID<br/><code>INTG-DEF-E-Book-Book_1</code><br/><i>prefixed, unique</i>"]
268
+ mid["Meadow ID<br/><code>42</code><br/><i>database primary key</i>"]
269
+
270
+ ext -- "adapter prefixing" --> mguid
271
+ mguid -- "upsert returns ID" --> mid
272
+
273
+ style ext fill:#f5f5f5,stroke:#bdbdbd,color:#333
274
+ style mguid fill:#fff3e0,stroke:#ffa726,color:#333
275
+ style mid fill:#fff3e0,stroke:#ff9800,color:#333
276
+ ```
277
+
278
+ 1. The external GUID from the comprehension (e.g. `Book_1`) gets a configurable prefix applied by the adapter, producing a Meadow GUID (e.g. `INTG-DEF-E-Book-Book_1`)
279
+ 2. The adapter upserts the record to the Meadow API. The server returns the numeric database ID
280
+ 3. The GUIDMap service tracks the bidirectional mapping: external GUID to Meadow GUID to database ID
281
+
282
+ This mapping persists across the entire integration run. When later entities reference `GUIDBook: "Book_1"`, the adapter looks up the mapping and resolves it to the correct numeric `IDBook` value. Entity integration order matters — referenced entities must be pushed before the entities that reference them.