tally-simple 1.3.1 → 1.8.2
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/README.md +132 -83
- package/bin/tally-simple.js +2 -7
- package/docs/.nojekyll +1 -0
- package/docs/architecture.html +67 -68
- package/docs/architecture.md +74 -57
- package/docs/execution-pipeline.html +71 -0
- package/docs/execution-pipeline.md +158 -0
- package/docs/index.html +288 -26
- package/docs/queries.html +107 -0
- package/docs/queries.md +122 -0
- package/docs/route-engine.html +57 -0
- package/docs/route-engine.md +141 -0
- package/docs/style.css +137 -0
- package/docs/usage.html +82 -0
- package/docs/usage.md +117 -0
- package/package.json +14 -8
- package/src/index.js +2 -8
- package/src/v5/external-api/api.js +21 -0
- package/src/{v3 → v5}/external-api/api.json +1 -1
- package/src/v5/index.js +1 -0
- package/src/v5/internal-working/execution/buildXmlBody.js +41 -0
- package/src/v5/internal-working/execution/getTdl.js +12 -0
- package/src/v5/internal-working/execution/index.js +30 -0
- package/src/v5/internal-working/execution/postHttp.js +26 -0
- package/src/v5/internal-working/execution/validateCompany.js +11 -0
- package/src/v5/internal-working/route/attachPath.js +25 -0
- package/src/v5/internal-working/route/createLeafHandler.js +17 -0
- package/src/v5/internal-working/route/index.js +24 -0
- package/src/{v3 → v5}/source.json +1 -11
- package/src/v6/external-api/api.js +21 -0
- package/src/v6/external-api/api.json +6 -0
- package/src/v6/index.js +1 -0
- package/src/v6/internal-working/execution/buildXmlBody.js +41 -0
- package/src/v6/internal-working/execution/getTdl.js +12 -0
- package/src/v6/internal-working/execution/index.js +30 -0
- package/src/v6/internal-working/execution/postHttp.js +26 -0
- package/src/v6/internal-working/execution/validateCompany.js +11 -0
- package/src/v6/internal-working/route/attachPath.js +25 -0
- package/src/v6/internal-working/route/createLeafHandler.js +17 -0
- package/src/v6/internal-working/route/index.js +24 -0
- package/src/{v2 → v6}/source.json +8 -10
- package/src/v7/api.json +6 -0
- package/src/v7/index.js +14 -0
- package/src/v7/internal-working/execution/buildXmlBody.js +41 -0
- package/src/v7/internal-working/execution/getTdl.js +12 -0
- package/src/v7/internal-working/execution/index.js +30 -0
- package/src/v7/internal-working/execution/postHttp.js +26 -0
- package/src/v7/internal-working/execution/validateCompany.js +11 -0
- package/src/v7/internal-working/route/attachPath.js +25 -0
- package/src/v7/internal-working/route/createLeafHandler.js +17 -0
- package/src/v7/internal-working/route/index.js +24 -0
- package/src/{v1 → v7}/source.json +8 -10
- package/src/v8/engine/index.js +18 -0
- package/src/v8/engine/parseXml.js +11 -0
- package/src/v8/index.js +21 -0
- package/docs/api.html +0 -41
- package/docs/api.md +0 -20
- package/docs/developer.html +0 -57
- package/docs/developer.md +0 -41
- package/docs/end-user.html +0 -49
- package/docs/end-user.md +0 -34
- package/docs/repo-developer.html +0 -91
- package/docs/repo-developer.md +0 -107
- package/src/index.d.ts +0 -54
- package/src/v1/external-api/api.js +0 -67
- package/src/v1/external-api/api.json +0 -5
- package/src/v1/external-api/index.js +0 -1
- package/src/v1/index.js +0 -1
- package/src/v1/traverse.js +0 -103
- package/src/v1/traverseObject/index.js +0 -39
- package/src/v2/external-api/api.js +0 -67
- package/src/v2/external-api/api.json +0 -5
- package/src/v2/external-api/index.js +0 -1
- package/src/v2/index.js +0 -1
- package/src/v2/traverse.js +0 -103
- package/src/v2/traverseObject/index.js +0 -39
- package/src/v3/external-api/api.js +0 -67
- package/src/v3/external-api/index.js +0 -1
- package/src/v3/index.js +0 -1
- package/src/v3/traverse.js +0 -103
- package/src/v3/traverseObject/index.js +0 -39
package/README.md
CHANGED
|
@@ -1,127 +1,176 @@
|
|
|
1
1
|
# Tally Simple
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/tally-simple)
|
|
4
|
-
[](
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](package.json)
|
|
6
|
+
[](package.json)
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
**A typed JavaScript client and CLI for querying business data from Tally via TDL definitions.**
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
Query Tally using declarative endpoint paths, supply a company name, and receive Tally's exact, raw XML response.
|
|
9
11
|
|
|
10
|
-
**[
|
|
12
|
+
**[Documentation Hub](https://keshavsoft.github.io/tally-simple/)** · **[View on npm](https://www.npmjs.com/package/tally-simple)**
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
---
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
## 📖 The Story of Tally Simple
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
Tally Simple
|
|
21
|
-
│ builds the XML request
|
|
22
|
-
▼
|
|
23
|
-
Tally HTTP endpoint
|
|
24
|
-
│
|
|
25
|
-
▼
|
|
26
|
-
XML response text
|
|
27
|
-
~~~
|
|
18
|
+
Tally ERP and Tally Prime expose an HTTP XML/ODBC interface (defaulting to `http://localhost:9000`), but speaking to it directly is notoriously complex:
|
|
19
|
+
- Requests require heavy, boilerplate `<ENVELOPE>` XML wrappers.
|
|
20
|
+
- Field extraction depends on specific, case-sensitive TDL (Tally Definition Language) collection queries.
|
|
21
|
+
- Developers often end up copy-pasting raw XML string templates throughout their applications.
|
|
28
22
|
|
|
29
|
-
|
|
23
|
+
### The Purpose of `tally-simple`
|
|
24
|
+
`tally-simple` solves this by serving as the **pure transport and query execution engine** for Tally:
|
|
25
|
+
1. It encapsulates complex TDL collection definitions declaratively inside the library.
|
|
26
|
+
2. It provides an intuitive, autocomplete-friendly JavaScript API and matching CLI commands.
|
|
27
|
+
3. It deliberately returns **pure raw XML strings** from Tally.
|
|
30
28
|
|
|
31
|
-
|
|
29
|
+
### Why Raw XML?
|
|
30
|
+
Keeping the response as raw XML follows the **UNIX philosophy**:
|
|
31
|
+
- **Zero Loss**: No information or attributes are lost or warped by premature JSON conversion.
|
|
32
|
+
- **Pipeable & Inspectable**: Output can be redirected directly to files (`> units.xml`) or formatted with standard XML tools (`| xmllint`).
|
|
33
|
+
- **Downstream Decoupling**: Downstream layers (such as `tally-simple-json` or custom parsers) can parse and shape the XML as needed, without coupling transport to data formatting.
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
```mermaid
|
|
36
|
+
flowchart LR
|
|
37
|
+
A[Your App or CLI] -->|Path + Company Name| B[tally-simple<br/>Transport & TDL Engine]
|
|
38
|
+
B -->|TDL XML Request Envelope| C[Tally ERP / Prime<br/>http://localhost:9000]
|
|
39
|
+
C -->|Raw XML Response| B
|
|
40
|
+
B -->|Raw XML String| A
|
|
41
|
+
```
|
|
35
42
|
|
|
36
|
-
|
|
43
|
+
---
|
|
37
44
|
|
|
38
|
-
##
|
|
45
|
+
## ⚡ Quick Start
|
|
39
46
|
|
|
40
|
-
|
|
47
|
+
### Installation
|
|
48
|
+
|
|
49
|
+
```bash
|
|
41
50
|
npm install tally-simple
|
|
42
|
-
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
*Requires Node.js 20.10+ and a running Tally instance with XML server enabled on `http://localhost:9000`.*
|
|
54
|
+
|
|
55
|
+
---
|
|
43
56
|
|
|
44
|
-
|
|
57
|
+
## 💻 JavaScript Usage (ESM)
|
|
45
58
|
|
|
46
|
-
|
|
59
|
+
Import the default `tally` client and call any query path by passing the company name:
|
|
47
60
|
|
|
48
|
-
|
|
61
|
+
```javascript
|
|
49
62
|
import tally from "tally-simple";
|
|
50
63
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
64
|
+
// Fetch units of measurement
|
|
65
|
+
const unitsXml = await tally.masters.units.fetch("Mani9");
|
|
66
|
+
console.log(unitsXml);
|
|
54
67
|
|
|
55
|
-
|
|
68
|
+
// Fetch stock items with batch allocations
|
|
69
|
+
const stockXml = await tally.masters.stockItems.withBatches("Mani9");
|
|
56
70
|
|
|
57
|
-
|
|
58
|
-
|
|
71
|
+
// Fetch ledgers with GST registration details
|
|
72
|
+
const ledgersXml = await tally.masters.ledgers.withGstDetails("Mani9");
|
|
59
73
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
});
|
|
74
|
+
// Fetch stock groups with parent hierarchies
|
|
75
|
+
const groupsXml = await tally.masters.stockGroup.withParent("Mani9");
|
|
76
|
+
```
|
|
64
77
|
|
|
65
|
-
|
|
66
|
-
~~~
|
|
78
|
+
Each query returns a `Promise<string>` resolving to Tally's complete raw XML response body.
|
|
67
79
|
|
|
68
|
-
|
|
80
|
+
---
|
|
69
81
|
|
|
70
|
-
|
|
82
|
+
## ⌨️ Command Line Interface (CLI)
|
|
71
83
|
|
|
72
|
-
|
|
84
|
+
Run any query directly from your terminal using `npx`:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Query units
|
|
73
88
|
npx tally-simple masters.units.fetch --company Mani9
|
|
74
|
-
~~~
|
|
75
89
|
|
|
76
|
-
|
|
90
|
+
# Or include the 'tally.' root prefix
|
|
91
|
+
npx tally-simple tally.masters.stockItems.withBatches --company Mani9
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Piping and Saving Output
|
|
95
|
+
|
|
96
|
+
Because the response is written directly to `stdout`, you can seamlessly pipe or save the raw XML:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Save to file
|
|
100
|
+
npx tally-simple masters.units.fetch --company Mani9 > units.xml
|
|
101
|
+
|
|
102
|
+
# Format output using xmllint
|
|
103
|
+
npx tally-simple masters.ledgers.withGstDetails --company Mani9 | xmllint --format -
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 📋 Available Queries
|
|
109
|
+
|
|
110
|
+
All queries target master records and return Tally's native export collection XML:
|
|
111
|
+
|
|
112
|
+
| Query Path | Target Domain | TDL Collection Query | What it returns |
|
|
113
|
+
| :--- | :--- | :--- | :--- |
|
|
114
|
+
| `masters.units.fetch` | Unit | `<TYPE>Unit</TYPE><FETCH>$$Alias:Name</FETCH>` | Units of measurement and aliases |
|
|
115
|
+
| `masters.stockItems.withBatches` | StockItem | `<TYPE>StockItem</TYPE><FETCH>BaseUnits</FETCH><FETCH>BatchAllocations.*</FETCH>` | Stock items, base units, and batch allocations |
|
|
116
|
+
| `masters.ledgers.withGstDetails` | Ledger | `<TYPE>Ledger</TYPE><FETCH>LEDGSTREGDETAILS.LIST</FETCH>` | Accounting ledgers and GST details |
|
|
117
|
+
| `masters.stockGroup.withParent` | StockGroup | `<TYPE>StockGroup</TYPE><FETCH>Parent</FETCH>` | Stock groups and parent hierarchy |
|
|
77
118
|
|
|
78
|
-
|
|
79
|
-
npx tally-simple tally.masters.stockItems.withBatches \
|
|
80
|
-
--company Mani9 \
|
|
81
|
-
--url http://localhost:9000
|
|
82
|
-
~~~
|
|
119
|
+
---
|
|
83
120
|
|
|
84
|
-
|
|
121
|
+
## 🧠 System Architecture
|
|
85
122
|
|
|
86
|
-
|
|
87
|
-
npx tally-simple masters.ledgers.withGstDetails --company Mani9 > ledgers.xml
|
|
88
|
-
~~~
|
|
123
|
+
`tally-simple` is built on a clean, declarative 3-layer architecture:
|
|
89
124
|
|
|
90
|
-
|
|
125
|
+
```text
|
|
126
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
127
|
+
│ 1. Declarative Specifications │
|
|
128
|
+
│ │
|
|
129
|
+
│ src/v7/api.json src/v7/source.json │
|
|
130
|
+
│ (Public Route Allowlist) (TDL Definition Tree) │
|
|
131
|
+
└──────────────────────────────┬──────────────────────────────┘
|
|
132
|
+
│
|
|
133
|
+
▼
|
|
134
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
135
|
+
│ 2. Public Composition Root │
|
|
136
|
+
│ │
|
|
137
|
+
│ src/v7/index.js │
|
|
138
|
+
│ (Binds Specifications to Engines via Dependency Injection)│
|
|
139
|
+
└──────────────────────────────┬──────────────────────────────┘
|
|
140
|
+
│
|
|
141
|
+
▼
|
|
142
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
143
|
+
│ 3. Internal Working Engines │
|
|
144
|
+
│ │
|
|
145
|
+
│ internal-working/route/ internal-working/execution│
|
|
146
|
+
│ (Builds Callable Object Tree) (4-Step Request Pipeline) │
|
|
147
|
+
└─────────────────────────────────────────────────────────────┘
|
|
148
|
+
```
|
|
91
149
|
|
|
92
|
-
|
|
93
|
-
TALLY_COMPANY=Mani9 TALLY_URL=http://localhost:9000 \
|
|
94
|
-
npx tally-simple masters.units.fetch
|
|
95
|
-
~~~
|
|
150
|
+
### The 4-Step Execution Pipeline
|
|
96
151
|
|
|
97
|
-
|
|
152
|
+
When any query method is called (e.g. `tally.masters.units.fetch("Mani9")`), execution flows through 4 focused steps:
|
|
98
153
|
|
|
99
|
-
|
|
154
|
+
1. **`validateCompany`**: Ensures the company name is a non-empty string and trims whitespace.
|
|
155
|
+
2. **`getTdl`**: Fast $O(1)$ reduction lookup into `source.json` to extract the corresponding TDL definition.
|
|
156
|
+
3. **`buildXmlBody`**: Safely escapes XML special characters and injects the company and TDL into the `<ENVELOPE>` request template.
|
|
157
|
+
4. **`postHttp`**: Sends an HTTP POST request to `http://localhost:9000` with `Content-Type: text/xml` and returns the raw response body.
|
|
100
158
|
|
|
101
|
-
|
|
102
|
-
$env:TALLY_COMPANY = "Mani9"
|
|
103
|
-
$env:TALLY_URL = "http://localhost:9000"
|
|
104
|
-
npx tally-simple masters.units.fetch
|
|
105
|
-
~~~
|
|
159
|
+
---
|
|
106
160
|
|
|
107
|
-
##
|
|
161
|
+
## 📚 Documentation Guides
|
|
108
162
|
|
|
109
|
-
|
|
110
|
-
| --- | --- |
|
|
111
|
-
| masters.units.fetch | Units and their aliases |
|
|
112
|
-
| masters.stockItems.withBatches | Stock items, base units, and batch allocations |
|
|
113
|
-
| masters.ledgers.withGstDetails | Ledgers and GST registration details |
|
|
114
|
-
| masters.stockGroup.withParent | Stock groups and their parent groups |
|
|
163
|
+
Explore the detailed architecture and usage guides:
|
|
115
164
|
|
|
116
|
-
|
|
165
|
+
- **[Documentation Hub](https://keshavsoft.github.io/tally-simple/)**: The interactive documentation portal.
|
|
166
|
+
- **[System Architecture](docs/architecture.md)**: Deep dive into the declarative design and layers.
|
|
167
|
+
- **[Execution Pipeline](docs/execution-pipeline.md)**: Step-by-step walkthrough of the 4-stage request flow.
|
|
168
|
+
- **[Route Assembly Engine](docs/route-engine.md)**: How the callable JavaScript tree is synthesized from `api.json`.
|
|
169
|
+
- **[Available Queries Reference](docs/queries.md)**: Complete TDL definitions and XML structures.
|
|
170
|
+
- **[Usage Guide](docs/usage.md)**: Advanced options, CLI piping, and TypeScript integration.
|
|
117
171
|
|
|
118
|
-
|
|
172
|
+
---
|
|
119
173
|
|
|
120
|
-
|
|
121
|
-
- [CLI reference](docs/cli.md): see options, environment variables, piping, and errors.
|
|
122
|
-
- [Available query paths](docs/api.md): see the public API and the TDL each path requests.
|
|
123
|
-
- [Architecture story](docs/architecture.md): see how one definition drives the client and CLI.
|
|
124
|
-
- [Developer guide](docs/development.md): see versioning, declaration generation, and verification.
|
|
125
|
-
- [Visual guide](docs/index.html): a dependency-free HTML walkthrough of the same flow.
|
|
174
|
+
## 📄 License
|
|
126
175
|
|
|
127
|
-
|
|
176
|
+
MIT © [KeshavSoft](https://github.com/keshavsoft)
|
package/bin/tally-simple.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import packageInfo from "../package.json" with { type: "json" };
|
|
6
|
-
import tally
|
|
6
|
+
import tally from "../src/index.js";
|
|
7
7
|
|
|
8
8
|
const usage = [
|
|
9
9
|
"Usage:",
|
|
@@ -151,12 +151,7 @@ const run = async (args) => {
|
|
|
151
151
|
throw new Error("A company is required. Pass --company or set TALLY_COMPANY.");
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
const
|
|
155
|
-
url: parsed.url ?? process.env.TALLY_URL,
|
|
156
|
-
headers: parsed.headers,
|
|
157
|
-
timeout: parsed.timeout
|
|
158
|
-
});
|
|
159
|
-
const endpoint = findEndpoint(parsed.apiPath, client);
|
|
154
|
+
const endpoint = findEndpoint(parsed.apiPath, tally);
|
|
160
155
|
const response = await endpoint(company);
|
|
161
156
|
|
|
162
157
|
process.stdout.write(response + "\n");
|
package/docs/.nojekyll
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# disable jekyll
|
package/docs/architecture.html
CHANGED
|
@@ -1,74 +1,73 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
|
-
<meta charset="
|
|
5
|
-
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
-
<title>Architecture</title>
|
|
7
|
-
<style>
|
|
8
|
-
body{font-family:system-ui,-apple-system,Segoe UI,Arial,sans-serif;max-width:900px;margin:40px auto;padding:0 24px;line-height:1.65;color:#202124}
|
|
9
|
-
nav{padding:12px 16px;margin-bottom:28px;background:#f5f5f5;border-radius:8px}
|
|
10
|
-
nav a{margin-right:16px;text-decoration:none}
|
|
11
|
-
h1{font-size:30px;margin-top:0}
|
|
12
|
-
h2{font-size:22px;margin-top:32px}
|
|
13
|
-
h3{font-size:18px;margin-top:24px}
|
|
14
|
-
pre{background:#f6f8fa;padding:16px;border-radius:8px;overflow:auto}
|
|
15
|
-
code{background:#f1f3f4;padding:2px 5px;border-radius:4px}
|
|
16
|
-
pre code{background:none;padding:0}
|
|
17
|
-
table{border-collapse:collapse;width:100%;margin:16px 0}
|
|
18
|
-
th,td{border:1px solid #ddd;padding:8px;text-align:left}
|
|
19
|
-
th{background:#f6f6f6}
|
|
20
|
-
a{color:#0969da}
|
|
21
|
-
</style>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>System Architecture — Tally Simple</title>
|
|
7
|
+
<link rel="stylesheet" href="style.css">
|
|
22
8
|
</head>
|
|
23
9
|
<body>
|
|
24
|
-
<
|
|
25
|
-
<
|
|
26
|
-
<a href="
|
|
27
|
-
<a href="
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<
|
|
34
|
-
<pre><code
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
<
|
|
60
|
-
<
|
|
61
|
-
<
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
<
|
|
69
|
-
<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
<
|
|
10
|
+
<div class="container">
|
|
11
|
+
<nav class="doc-nav">
|
|
12
|
+
<a href="index.html">← Documentation Hub</a>
|
|
13
|
+
<a href="architecture.md">View Markdown</a>
|
|
14
|
+
</nav>
|
|
15
|
+
|
|
16
|
+
<h1>System Architecture</h1>
|
|
17
|
+
<p>Tally Simple is designed with strict boundaries separating the public contract from the internal execution engines.</p>
|
|
18
|
+
|
|
19
|
+
<h2>Architectural Overview</h2>
|
|
20
|
+
<pre><code>┌─────────────────────────────────────────────────────────────┐
|
|
21
|
+
│ 1. Declarative Specifications │
|
|
22
|
+
│ │
|
|
23
|
+
│ src/v7/api.json src/v7/source.json │
|
|
24
|
+
│ (Public Route Allowlist) (TDL Definition Tree) │
|
|
25
|
+
└──────────────────────────────┬──────────────────────────────┘
|
|
26
|
+
│
|
|
27
|
+
▼
|
|
28
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
29
|
+
│ 2. Public Composition Root │
|
|
30
|
+
│ │
|
|
31
|
+
│ src/v7/index.js │
|
|
32
|
+
│ (Injects Specifications into Route & Execution Engines) │
|
|
33
|
+
└──────────────────────────────┬──────────────────────────────┘
|
|
34
|
+
│
|
|
35
|
+
▼
|
|
36
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
37
|
+
│ 3. Internal Working Engines │
|
|
38
|
+
│ │
|
|
39
|
+
│ internal-working/route/ internal-working/execution│
|
|
40
|
+
│ (Object Tree Assembly) (4-Step Request Pipeline) │
|
|
41
|
+
└─────────────────────────────────────────────────────────────┘</code></pre>
|
|
42
|
+
|
|
43
|
+
<h2>The Three Layers</h2>
|
|
44
|
+
|
|
45
|
+
<h3>1. The Declarative Specifications (<code>src/v7/</code>)</h3>
|
|
46
|
+
<ul>
|
|
47
|
+
<li><strong><code>api.json</code> (The Allowlist)</strong>: An explicit array of dot-separated string paths that declare the public API boundary (e.g., <code>["tally.masters.units.fetch", "tally.masters.stockItems.withBatches", ...]</code>).</li>
|
|
48
|
+
<li><strong><code>source.json</code> (The Tree of Truth)</strong>: A pure domain tree containing the TDL collection queries (<code><TYPE>Unit</TYPE>...</code>) and actions. It is completely decoupled from transport and contains no connection settings or HTTP logic.</li>
|
|
49
|
+
</ul>
|
|
50
|
+
|
|
51
|
+
<h3>2. The Public Composition Root (<code>src/v7/index.js</code>)</h3>
|
|
52
|
+
<ul>
|
|
53
|
+
<li>Acts as the single entry point for the active version.</li>
|
|
54
|
+
<li>Imports <code>source.json</code> and <code>api.json</code> and injects them directly into the internal route builder via dependency injection.</li>
|
|
55
|
+
<li>Exports a single, ready-to-use default client object.</li>
|
|
56
|
+
</ul>
|
|
57
|
+
|
|
58
|
+
<h3>3. The Internal Working Engines (<code>src/v7/internal-working/</code>)</h3>
|
|
59
|
+
<ul>
|
|
60
|
+
<li><strong><code>route/</code></strong>: Dynamically builds the nested, callable JavaScript object tree based on <code>api.json</code> without hardcoding methods.</li>
|
|
61
|
+
<li><strong><code>execution/</code></strong>: Executes the runtime query: validates the company argument, retrieves the TDL query from <code>source.json</code>, constructs the XML request envelope, and dispatches the HTTP POST request to Tally.</li>
|
|
62
|
+
</ul>
|
|
63
|
+
|
|
64
|
+
<h2>Architectural Principles</h2>
|
|
65
|
+
<ol>
|
|
66
|
+
<li><strong>Single Source of Truth for Domain Only:</strong> <code>source.json</code> is the authority on <em>what queries exist and what TDL they request</em>, not a dumping ground for server URLs or HTTP headers.</li>
|
|
67
|
+
<li><strong>Strictly One Export per File:</strong> Every module in the codebase adheres to a single default export (<code>export default startFunc;</code>).</li>
|
|
68
|
+
<li><strong>Explicit Parameter Unwrapping:</strong> Every function accepts a single object with <code>in</code>-prefixed keys and unwraps them immediately to <code>local</code>-prefixed variables.</li>
|
|
69
|
+
<li><strong>Zero Runtime Dependencies:</strong> Built entirely on standard Node.js built-ins.</li>
|
|
70
|
+
</ol>
|
|
71
|
+
</div>
|
|
73
72
|
</body>
|
|
74
73
|
</html>
|
package/docs/architecture.md
CHANGED
|
@@ -1,65 +1,82 @@
|
|
|
1
|
-
|
|
1
|
+
# System Architecture
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[**View this document as HTML**](./architecture.html) · [**Documentation Hub**](./index.html)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Tally Simple is designed with strict boundaries separating the public contract from the internal execution engines.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
Caller
|
|
9
|
-
│
|
|
10
|
-
│ public path + company
|
|
11
|
-
▼
|
|
12
|
-
external-api
|
|
13
|
-
│
|
|
14
|
-
▼
|
|
15
|
-
traversal
|
|
16
|
-
│
|
|
17
|
-
▼
|
|
18
|
-
source.json
|
|
19
|
-
│
|
|
20
|
-
▼
|
|
21
|
-
request definition
|
|
22
|
-
│
|
|
23
|
-
▼
|
|
24
|
-
Tally HTTP endpoint
|
|
25
|
-
│
|
|
26
|
-
▼
|
|
27
|
-
XML response
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Two JSON roles
|
|
31
|
-
|
|
32
|
-
### `source.json`
|
|
33
|
-
|
|
34
|
-
Internal implementation definition.
|
|
35
|
-
|
|
36
|
-
It contains the information required to construct the Tally request.
|
|
37
|
-
|
|
38
|
-
### `external-api/api.json`
|
|
39
|
-
|
|
40
|
-
Public contract.
|
|
7
|
+
---
|
|
41
8
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
This prevents internal request details from becoming the public API automatically.
|
|
45
|
-
|
|
46
|
-
## Why JSON
|
|
47
|
-
|
|
48
|
-
Adding a new Tally operation should normally be a definition change:
|
|
9
|
+
## Architectural Overview
|
|
49
10
|
|
|
50
11
|
```text
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
12
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
13
|
+
│ 1. Declarative Specifications │
|
|
14
|
+
│ │
|
|
15
|
+
│ src/v7/api.json src/v7/source.json │
|
|
16
|
+
│ (Public Route Allowlist) (TDL Definition Tree) │
|
|
17
|
+
└──────────────────────────────┬──────────────────────────────┘
|
|
18
|
+
│
|
|
19
|
+
▼
|
|
20
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
21
|
+
│ 2. Public Composition Root │
|
|
22
|
+
│ │
|
|
23
|
+
│ src/v7/index.js │
|
|
24
|
+
│ (Injects Specifications into Route & Execution Engines) │
|
|
25
|
+
└──────────────────────────────┬──────────────────────────────┘
|
|
26
|
+
│
|
|
27
|
+
▼
|
|
28
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
29
|
+
│ 3. Internal Working Engines │
|
|
30
|
+
│ │
|
|
31
|
+
│ internal-working/route/ internal-working/execution│
|
|
32
|
+
│ (Object Tree Assembly) (4-Step Request Pipeline) │
|
|
33
|
+
└─────────────────────────────────────────────────────────────┘
|
|
55
34
|
```
|
|
56
35
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
##
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## The Three Layers
|
|
39
|
+
|
|
40
|
+
### 1. The Declarative Specifications (`src/v7/`)
|
|
41
|
+
- **`api.json` (The Allowlist)**: An explicit array of dot-separated string paths that declare the public API boundary (e.g., `["tally.masters.units.fetch", "tally.masters.stockItems.withBatches", ...]`).
|
|
42
|
+
- **`source.json` (The Tree of Truth)**: A pure domain tree containing the TDL collection queries (`<TYPE>Unit</TYPE>...`) and actions. It is completely decoupled from transport and contains **no** connection settings or HTTP logic.
|
|
43
|
+
|
|
44
|
+
### 2. The Public Composition Root (`src/v7/index.js`)
|
|
45
|
+
- Acts as the single entry point for the active version.
|
|
46
|
+
- Imports `source.json` and `api.json` and injects them directly into the internal route builder:
|
|
47
|
+
```javascript
|
|
48
|
+
const tally = createRoute({
|
|
49
|
+
inApiPaths: apiPaths,
|
|
50
|
+
inSource: source,
|
|
51
|
+
inExecutor: execute
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
- Exports a single, ready-to-use default client object.
|
|
55
|
+
|
|
56
|
+
### 3. The Internal Working Engines (`src/v7/internal-working/`)
|
|
57
|
+
- **`route/`**: Dynamically builds the nested, callable JavaScript object tree based on `api.json` without hardcoding methods.
|
|
58
|
+
- **`execution/`**: Executes the runtime query: validates the company argument, retrieves the TDL query from `source.json`, constructs the XML request envelope, and dispatches the HTTP POST request to Tally.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Architectural Principles
|
|
63
|
+
|
|
64
|
+
1. **Single Source of Truth for Domain Only:**
|
|
65
|
+
`source.json` is the sole authority on *what queries exist and what TDL they request*, not a dumping ground for server URLs or HTTP headers.
|
|
66
|
+
|
|
67
|
+
2. **Strictly One Export per File:**
|
|
68
|
+
Every module in the codebase adheres to a single default export (`export default startFunc;`).
|
|
69
|
+
|
|
70
|
+
3. **Explicit Parameter Unwrapping:**
|
|
71
|
+
Every function accepts a single object with `in`-prefixed keys and unwraps them immediately to `local`-prefixed variables:
|
|
72
|
+
```javascript
|
|
73
|
+
const startFunc = ({ inRoutePath, inCompany, inSource }) => {
|
|
74
|
+
const localRoutePath = inRoutePath;
|
|
75
|
+
const localCompany = inCompany;
|
|
76
|
+
const localSource = inSource;
|
|
77
|
+
// ...
|
|
78
|
+
};
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
4. **Zero Runtime Dependencies:**
|
|
82
|
+
Built entirely on standard Node.js built-ins. No intermediate proxy frameworks, no third-party HTTP libraries.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Execution Pipeline — Tally Simple</title>
|
|
7
|
+
<link rel="stylesheet" href="style.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div class="container">
|
|
11
|
+
<nav class="doc-nav">
|
|
12
|
+
<a href="index.html">← Documentation Hub</a>
|
|
13
|
+
<a href="execution-pipeline.md">View Markdown</a>
|
|
14
|
+
</nav>
|
|
15
|
+
|
|
16
|
+
<h1>Execution Pipeline</h1>
|
|
17
|
+
<p>When a consumer invokes an endpoint like <code>tally.masters.units.fetch("Mani9")</code>, the execution engine handles the request through a clean, 4-step pipeline.</p>
|
|
18
|
+
|
|
19
|
+
<h2>The Pipeline Flow</h2>
|
|
20
|
+
<pre><code>Invocation: tally.masters.units.fetch("Mani9")
|
|
21
|
+
│
|
|
22
|
+
▼
|
|
23
|
+
Step 1: validateCompany({ inCompany })
|
|
24
|
+
│ Ensures company is a non-empty string; returns trimmed name
|
|
25
|
+
▼
|
|
26
|
+
Step 2: getTdl({ inSource, inRoutePath })
|
|
27
|
+
│ Direct O(1) path lookup of TDL collection query from source.json
|
|
28
|
+
▼
|
|
29
|
+
Step 3: buildXmlBody({ inCompany, inTdl })
|
|
30
|
+
│ XML-escapes company name and injects into XML envelope template
|
|
31
|
+
▼
|
|
32
|
+
Step 4: postHttp({ inXmlBody })
|
|
33
|
+
│ Sends HTTP POST to Tally (http://localhost:9000) and returns XML text
|
|
34
|
+
▼
|
|
35
|
+
Caller receives raw XML string</code></pre>
|
|
36
|
+
|
|
37
|
+
<h2>The Four Narrative Steps</h2>
|
|
38
|
+
|
|
39
|
+
<h3>Step 1: Validate Company Name (<code>validateCompany.js</code>)</h3>
|
|
40
|
+
<p>Verifies that the supplied company name is a non-empty string. Throws early if invalid.</p>
|
|
41
|
+
|
|
42
|
+
<h3>Step 2: Direct TDL Lookup (<code>getTdl.js</code>)</h3>
|
|
43
|
+
<p>Instead of crawling or traversing the JSON structure, the endpoint is retrieved in a single line using path reduction.</p>
|
|
44
|
+
|
|
45
|
+
<h3>Step 3: XML Body Construction (<code>buildXmlBody.js</code>)</h3>
|
|
46
|
+
<p>Safely escapes XML special characters in the company name and substitutes <code>{company}</code> and <code>{collectionBody}</code> into the envelope template.</p>
|
|
47
|
+
|
|
48
|
+
<h3>Step 4: HTTP Transport (<code>postHttp.js</code>)</h3>
|
|
49
|
+
<p>Performs a standard <code>POST</code> request to <code>http://localhost:9000</code> with <code>Content-Type: text/xml</code>.</p>
|
|
50
|
+
|
|
51
|
+
<h2>The Coordinator (<code>index.js</code>)</h2>
|
|
52
|
+
<p>The main entry point reads like a 4-line story:</p>
|
|
53
|
+
<pre><code>const companyName = validateCompany({ inCompany: localCompany });
|
|
54
|
+
const tdl = getTdl({ inSource: localSource, inRoutePath: localRoutePath });
|
|
55
|
+
const xmlBody = buildXmlBody({ inCompany: companyName, inTdl: tdl });
|
|
56
|
+
|
|
57
|
+
return await postHttp({ inXmlBody: xmlBody });</code></pre>
|
|
58
|
+
|
|
59
|
+
<h2>Architectural Highlights</h2>
|
|
60
|
+
<ul>
|
|
61
|
+
<li><strong>Direct Resolution:</strong> No recursion, no skipping keys, no runtime guessing.</li>
|
|
62
|
+
<li><strong>Single Responsibility:</strong> Each file does exactly one job.</li>
|
|
63
|
+
<li><strong>Strict Single Export:</strong> Every file exports <code>export default startFunc;</code>.</li>
|
|
64
|
+
</ul>
|
|
65
|
+
|
|
66
|
+
<footer>
|
|
67
|
+
<p>© KeshavSoft. Distributed under the MIT License.</p>
|
|
68
|
+
</footer>
|
|
69
|
+
</div>
|
|
70
|
+
</body>
|
|
71
|
+
</html>
|