tally-simple 0.0.0-stage → 1.3.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/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/README.md +127 -3
- package/bin/tally-simple.js +175 -0
- package/docs/api.html +41 -0
- package/docs/api.md +20 -0
- package/docs/architecture.html +74 -0
- package/docs/architecture.md +65 -0
- package/docs/developer.html +57 -0
- package/docs/developer.md +41 -0
- package/docs/end-user.html +49 -0
- package/docs/end-user.md +34 -0
- package/docs/index.html +32 -0
- package/docs/repo-developer.html +91 -0
- package/docs/repo-developer.md +107 -0
- package/package.json +55 -6
- package/src/index.d.ts +54 -0
- package/src/index.js +8 -0
- package/src/v1/external-api/api.js +67 -0
- package/src/v1/external-api/api.json +5 -0
- package/src/v1/external-api/index.js +1 -0
- package/src/v1/index.js +1 -0
- package/src/v1/source.json +40 -0
- package/src/v1/traverse.js +103 -0
- package/src/v1/traverseObject/index.js +39 -0
- package/src/v2/external-api/api.js +67 -0
- package/src/v2/external-api/api.json +5 -0
- package/src/v2/external-api/index.js +1 -0
- package/src/v2/index.js +1 -0
- package/src/v2/source.json +40 -0
- package/src/v2/traverse.js +103 -0
- package/src/v2/traverseObject/index.js +39 -0
- package/src/v3/external-api/api.js +67 -0
- package/src/v3/external-api/api.json +6 -0
- package/src/v3/external-api/index.js +1 -0
- package/src/v3/index.js +1 -0
- package/src/v3/source.json +48 -0
- package/src/v3/traverse.js +103 -0
- package/src/v3/traverseObject/index.js +39 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
- Expose the Tally query API as an installable ESM package.
|
|
6
|
+
- Add `createTallyClient()` for endpoint, header, timeout, and fetch configuration.
|
|
7
|
+
- Add the `tally-simple` command for querying a published API path from a shell.
|
|
8
|
+
- Keep the default import as a ready-to-use client for backwards compatibility.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 KeshavSoft
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,127 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# Tally Simple
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/tally-simple)
|
|
4
|
+
[](https://github.com/keshavsoft/tally-simple/blob/main/LICENSE)
|
|
5
|
+
|
|
6
|
+
Tally Simple is a small, typed JavaScript client and CLI for asking Tally for business data.
|
|
7
|
+
|
|
8
|
+
Choose a supported query, provide the company name, and receive Tally's response as XML. The same query paths work in an application and from a shell, so a quick experiment can grow into an automated job without changing the request model.
|
|
9
|
+
|
|
10
|
+
**[View the package on npm](https://www.npmjs.com/package/tally-simple)** · **[Open the visual guide](docs/index.html)**
|
|
11
|
+
|
|
12
|
+
## The story in one minute
|
|
13
|
+
|
|
14
|
+
Tally Simple sits between your code or shell and a Tally HTTP endpoint:
|
|
15
|
+
|
|
16
|
+
~~~text
|
|
17
|
+
your app / shell command
|
|
18
|
+
│ choose a public query + company
|
|
19
|
+
▼
|
|
20
|
+
Tally Simple
|
|
21
|
+
│ builds the XML request
|
|
22
|
+
▼
|
|
23
|
+
Tally HTTP endpoint
|
|
24
|
+
│
|
|
25
|
+
▼
|
|
26
|
+
XML response text
|
|
27
|
+
~~~
|
|
28
|
+
|
|
29
|
+
It deliberately keeps the response raw. You can inspect it, save it, pipe it to another tool, or parse it with the XML library your application already uses.
|
|
30
|
+
|
|
31
|
+
## Requirements
|
|
32
|
+
|
|
33
|
+
- Node.js 20.10 or newer
|
|
34
|
+
- A Tally HTTP endpoint that accepts the request, usually http://localhost:9000
|
|
35
|
+
|
|
36
|
+
Tally Simple returns Tally's response body as XML text.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
~~~bash
|
|
41
|
+
npm install tally-simple
|
|
42
|
+
~~~
|
|
43
|
+
|
|
44
|
+
The package has no runtime dependencies and requires Node.js 20.10 or newer.
|
|
45
|
+
|
|
46
|
+
## Use it in JavaScript
|
|
47
|
+
|
|
48
|
+
~~~js
|
|
49
|
+
import tally from "tally-simple";
|
|
50
|
+
|
|
51
|
+
const xml = await tally.masters.units.fetch("Mani9");
|
|
52
|
+
console.log(xml);
|
|
53
|
+
~~~
|
|
54
|
+
|
|
55
|
+
The default import is a ready-to-use client. For a different endpoint, headers, timeout, or fetch implementation, use `createTallyClient()`:
|
|
56
|
+
|
|
57
|
+
~~~js
|
|
58
|
+
import { createTallyClient } from "tally-simple";
|
|
59
|
+
|
|
60
|
+
const tally = createTallyClient({
|
|
61
|
+
url: "http://localhost:9000",
|
|
62
|
+
timeout: 15_000
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const xml = await tally.masters.ledgers.withGstDetails("Mani9");
|
|
66
|
+
~~~
|
|
67
|
+
|
|
68
|
+
## Use it from the command line
|
|
69
|
+
|
|
70
|
+
Run a query with npm's command runner:
|
|
71
|
+
|
|
72
|
+
~~~bash
|
|
73
|
+
npx tally-simple masters.units.fetch --company Mani9
|
|
74
|
+
~~~
|
|
75
|
+
|
|
76
|
+
You can also include the root name:
|
|
77
|
+
|
|
78
|
+
~~~bash
|
|
79
|
+
npx tally-simple tally.masters.stockItems.withBatches \
|
|
80
|
+
--company Mani9 \
|
|
81
|
+
--url http://localhost:9000
|
|
82
|
+
~~~
|
|
83
|
+
|
|
84
|
+
The response is written to stdout, so it can be saved or piped:
|
|
85
|
+
|
|
86
|
+
~~~bash
|
|
87
|
+
npx tally-simple masters.ledgers.withGstDetails --company Mani9 > ledgers.xml
|
|
88
|
+
~~~
|
|
89
|
+
|
|
90
|
+
For environment-based use:
|
|
91
|
+
|
|
92
|
+
~~~bash
|
|
93
|
+
TALLY_COMPANY=Mani9 TALLY_URL=http://localhost:9000 \
|
|
94
|
+
npx tally-simple masters.units.fetch
|
|
95
|
+
~~~
|
|
96
|
+
|
|
97
|
+
Run npx tally-simple --help to see all CLI options.
|
|
98
|
+
|
|
99
|
+
In PowerShell, environment variables use this form:
|
|
100
|
+
|
|
101
|
+
~~~powershell
|
|
102
|
+
$env:TALLY_COMPANY = "Mani9"
|
|
103
|
+
$env:TALLY_URL = "http://localhost:9000"
|
|
104
|
+
npx tally-simple masters.units.fetch
|
|
105
|
+
~~~
|
|
106
|
+
|
|
107
|
+
## Available queries
|
|
108
|
+
|
|
109
|
+
| Query | Returns |
|
|
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 |
|
|
115
|
+
|
|
116
|
+
Every query accepts one company name. Blank company names are rejected before a request is sent. HTTP errors include the status and response body.
|
|
117
|
+
|
|
118
|
+
## Choose your next step
|
|
119
|
+
|
|
120
|
+
- [JavaScript usage](docs/usage.md): configure the client, test without Tally, and use TypeScript.
|
|
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.
|
|
126
|
+
|
|
127
|
+
The source code is on [GitHub](https://github.com/keshavsoft/tally-simple), and the published package is on [npm](https://www.npmjs.com/package/tally-simple).
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import packageInfo from "../package.json" with { type: "json" };
|
|
6
|
+
import tally, { createTallyClient } from "../src/index.js";
|
|
7
|
+
|
|
8
|
+
const usage = [
|
|
9
|
+
"Usage:",
|
|
10
|
+
" tally-simple <api-path> --company <company> [options]",
|
|
11
|
+
"",
|
|
12
|
+
"Examples:",
|
|
13
|
+
" tally-simple masters.units.fetch --company Mani9",
|
|
14
|
+
" tally-simple tally.masters.ledgers.withGstDetails --company Mani9 --url http://localhost:9000",
|
|
15
|
+
"",
|
|
16
|
+
"Options:",
|
|
17
|
+
" -c, --company <name> Tally company name (or TALLY_COMPANY)",
|
|
18
|
+
" -u, --url <url> Tally HTTP endpoint (or TALLY_URL)",
|
|
19
|
+
" --header <k:v> Add a request header; may be repeated",
|
|
20
|
+
" --timeout <ms> Abort a request after the given number of milliseconds",
|
|
21
|
+
" -h, --help Show this help",
|
|
22
|
+
" -v, --version Show the package version",
|
|
23
|
+
"",
|
|
24
|
+
"The API path is one of the paths listed in docs/api.md. The response body is",
|
|
25
|
+
"written to stdout with a trailing newline, so it can be piped to another command.",
|
|
26
|
+
""
|
|
27
|
+
].join("\n");
|
|
28
|
+
|
|
29
|
+
const readValue = (args, index, option) => {
|
|
30
|
+
const value = args[index + 1];
|
|
31
|
+
|
|
32
|
+
if (!value || value.startsWith("-")) {
|
|
33
|
+
throw new Error(option + " requires a value.");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return value;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const parseHeader = (value) => {
|
|
40
|
+
const separator = value.indexOf(":");
|
|
41
|
+
|
|
42
|
+
if (separator < 1) {
|
|
43
|
+
throw new Error("Invalid header \"" + value + "\". Use the form name:value.");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return [
|
|
47
|
+
value.slice(0, separator).trim(),
|
|
48
|
+
value.slice(separator + 1).trim()
|
|
49
|
+
];
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const parseArgs = (args) => {
|
|
53
|
+
const options = { headers: {} };
|
|
54
|
+
let apiPath;
|
|
55
|
+
|
|
56
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
57
|
+
const argument = args[index];
|
|
58
|
+
|
|
59
|
+
if (argument === "--help" || argument === "-h") {
|
|
60
|
+
return { help: true };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (argument === "--version" || argument === "-v") {
|
|
64
|
+
return { version: true };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (argument === "--company" || argument === "-c") {
|
|
68
|
+
options.company = readValue(args, index, argument);
|
|
69
|
+
index += 1;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (argument === "--url" || argument === "-u") {
|
|
74
|
+
options.url = readValue(args, index, argument);
|
|
75
|
+
index += 1;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (argument === "--timeout") {
|
|
80
|
+
const value = readValue(args, index, argument);
|
|
81
|
+
options.timeout = Number(value);
|
|
82
|
+
|
|
83
|
+
if (!Number.isFinite(options.timeout) || options.timeout <= 0) {
|
|
84
|
+
throw new Error("--timeout must be a positive number of milliseconds.");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
index += 1;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (argument === "--header") {
|
|
92
|
+
const [name, value] = parseHeader(readValue(args, index, argument));
|
|
93
|
+
options.headers[name] = value;
|
|
94
|
+
index += 1;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (argument.startsWith("-")) {
|
|
99
|
+
throw new Error("Unknown option: " + argument);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (apiPath) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
"Only one API path may be supplied; received \"" + argument + "\" too."
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
apiPath = argument;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return { ...options, apiPath };
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const normalizePath = (apiPath) => apiPath.startsWith("tally.")
|
|
115
|
+
? apiPath.slice("tally.".length)
|
|
116
|
+
: apiPath;
|
|
117
|
+
|
|
118
|
+
const findEndpoint = (apiPath, client = tally) => {
|
|
119
|
+
const endpoint = normalizePath(apiPath).split(".").reduce(
|
|
120
|
+
(current, part) => current?.[part],
|
|
121
|
+
client
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
if (typeof endpoint !== "function") {
|
|
125
|
+
throw new Error("Unknown API path: " + apiPath);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return endpoint;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const run = async (args) => {
|
|
132
|
+
const parsed = parseArgs(args);
|
|
133
|
+
|
|
134
|
+
if (parsed.help) {
|
|
135
|
+
process.stdout.write(usage);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (parsed.version) {
|
|
140
|
+
process.stdout.write(packageInfo.version + "\n");
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!parsed.apiPath) {
|
|
145
|
+
throw new Error("An API path is required. Use --help to see examples.");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const company = parsed.company ?? process.env.TALLY_COMPANY;
|
|
149
|
+
|
|
150
|
+
if (!company) {
|
|
151
|
+
throw new Error("A company is required. Pass --company or set TALLY_COMPANY.");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const client = createTallyClient({
|
|
155
|
+
url: parsed.url ?? process.env.TALLY_URL,
|
|
156
|
+
headers: parsed.headers,
|
|
157
|
+
timeout: parsed.timeout
|
|
158
|
+
});
|
|
159
|
+
const endpoint = findEndpoint(parsed.apiPath, client);
|
|
160
|
+
const response = await endpoint(company);
|
|
161
|
+
|
|
162
|
+
process.stdout.write(response + "\n");
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const isMain = process.argv[1]
|
|
166
|
+
&& path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
167
|
+
|
|
168
|
+
if (isMain) {
|
|
169
|
+
run(process.argv.slice(2)).catch((error) => {
|
|
170
|
+
process.stderr.write("Error: " + error.message + "\n\n" + usage);
|
|
171
|
+
process.exitCode = 1;
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export { findEndpoint, parseArgs, run };
|
package/docs/api.html
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
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">
|
|
6
|
+
<title>Api</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>
|
|
22
|
+
</head>
|
|
23
|
+
<body>
|
|
24
|
+
<nav>
|
|
25
|
+
<a href="../README.html">README</a>
|
|
26
|
+
<a href="end-user.html">End User</a>
|
|
27
|
+
<a href="developer.html">Application Developer</a>
|
|
28
|
+
<a href="repo-developer.html">Repository Developer</a>
|
|
29
|
+
<a href="api.html">API</a>
|
|
30
|
+
<a href="architecture.html">Architecture</a>
|
|
31
|
+
</nav>
|
|
32
|
+
<h1>API Reference</h1>
|
|
33
|
+
<p>The public API is generated from <code>src/v1/external-api/api.json</code>.</p>
|
|
34
|
+
<p>Current public paths:</p>
|
|
35
|
+
<pre><code>tally.masters.units.fetch
|
|
36
|
+
tally.masters.stockItems.withBatches</code></pre>
|
|
37
|
+
<p>Example:</p>
|
|
38
|
+
<pre><code>await tally.masters.units.fetch("Mani9");</code></pre>
|
|
39
|
+
<p>The exact public surface should be changed through <code>external-api/api.json</code>, followed by declaration generation.</p>
|
|
40
|
+
</body>
|
|
41
|
+
</html>
|
package/docs/api.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[**View this document as HTML**](./api.html)
|
|
2
|
+
|
|
3
|
+
# API Reference
|
|
4
|
+
|
|
5
|
+
The public API is generated from `src/v1/external-api/api.json`.
|
|
6
|
+
|
|
7
|
+
Current public paths:
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
tally.masters.units.fetch
|
|
11
|
+
tally.masters.stockItems.withBatches
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Example:
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
await tally.masters.units.fetch("Mani9");
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The exact public surface should be changed through `external-api/api.json`, followed by declaration generation.
|
|
@@ -0,0 +1,74 @@
|
|
|
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">
|
|
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>
|
|
22
|
+
</head>
|
|
23
|
+
<body>
|
|
24
|
+
<nav>
|
|
25
|
+
<a href="../README.html">README</a>
|
|
26
|
+
<a href="end-user.html">End User</a>
|
|
27
|
+
<a href="developer.html">Application Developer</a>
|
|
28
|
+
<a href="repo-developer.html">Repository Developer</a>
|
|
29
|
+
<a href="api.html">API</a>
|
|
30
|
+
<a href="architecture.html">Architecture</a>
|
|
31
|
+
</nav>
|
|
32
|
+
<h1>Architecture</h1>
|
|
33
|
+
<p>The package is intentionally small.</p>
|
|
34
|
+
<pre><code>Caller
|
|
35
|
+
│
|
|
36
|
+
│ public path + company
|
|
37
|
+
▼
|
|
38
|
+
external-api
|
|
39
|
+
│
|
|
40
|
+
▼
|
|
41
|
+
traversal
|
|
42
|
+
│
|
|
43
|
+
▼
|
|
44
|
+
source.json
|
|
45
|
+
│
|
|
46
|
+
▼
|
|
47
|
+
request definition
|
|
48
|
+
│
|
|
49
|
+
▼
|
|
50
|
+
Tally HTTP endpoint
|
|
51
|
+
│
|
|
52
|
+
▼
|
|
53
|
+
XML response</code></pre>
|
|
54
|
+
<h2>Two JSON roles</h2>
|
|
55
|
+
<h3><code>source.json</code></h3>
|
|
56
|
+
<p>Internal implementation definition.</p>
|
|
57
|
+
<p>It contains the information required to construct the Tally request.</p>
|
|
58
|
+
<h3><code>external-api/api.json</code></h3>
|
|
59
|
+
<p>Public contract.</p>
|
|
60
|
+
<p>It contains only the paths that should be exposed to consumers.</p>
|
|
61
|
+
<p>This prevents internal request details from becoming the public API automatically.</p>
|
|
62
|
+
<h2>Why JSON</h2>
|
|
63
|
+
<p>Adding a new Tally operation should normally be a definition change:</p>
|
|
64
|
+
<pre><code>add definition
|
|
65
|
+
→ expose path
|
|
66
|
+
→ regenerate declarations
|
|
67
|
+
→ test</code></pre>
|
|
68
|
+
<p>The execution engine remains unchanged.</p>
|
|
69
|
+
<h2>Company</h2>
|
|
70
|
+
<p>Company is runtime data supplied by the caller, not a fixed value in the public API.</p>
|
|
71
|
+
<h2>XML</h2>
|
|
72
|
+
<p>The package creates and sends Tally XML. It does not require the response to be converted to JSON as part of this layer.</p>
|
|
73
|
+
</body>
|
|
74
|
+
</html>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
[**View this document as HTML**](./architecture.html)
|
|
2
|
+
|
|
3
|
+
# Architecture
|
|
4
|
+
|
|
5
|
+
The package is intentionally small.
|
|
6
|
+
|
|
7
|
+
```text
|
|
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.
|
|
41
|
+
|
|
42
|
+
It contains only the paths that should be exposed to consumers.
|
|
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:
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
add definition
|
|
52
|
+
→ expose path
|
|
53
|
+
→ regenerate declarations
|
|
54
|
+
→ test
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The execution engine remains unchanged.
|
|
58
|
+
|
|
59
|
+
## Company
|
|
60
|
+
|
|
61
|
+
Company is runtime data supplied by the caller, not a fixed value in the public API.
|
|
62
|
+
|
|
63
|
+
## XML
|
|
64
|
+
|
|
65
|
+
The package creates and sends Tally XML. It does not require the response to be converted to JSON as part of this layer.
|
|
@@ -0,0 +1,57 @@
|
|
|
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">
|
|
6
|
+
<title>Developer</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>
|
|
22
|
+
</head>
|
|
23
|
+
<body>
|
|
24
|
+
<nav>
|
|
25
|
+
<a href="../README.html">README</a>
|
|
26
|
+
<a href="end-user.html">End User</a>
|
|
27
|
+
<a href="developer.html">Application Developer</a>
|
|
28
|
+
<a href="repo-developer.html">Repository Developer</a>
|
|
29
|
+
<a href="api.html">API</a>
|
|
30
|
+
<a href="architecture.html">Architecture</a>
|
|
31
|
+
</nav>
|
|
32
|
+
<h1>Application Developer Guide</h1>
|
|
33
|
+
<p>This guide is for developers consuming Tally Public API from another application.</p>
|
|
34
|
+
<h2>Public boundary</h2>
|
|
35
|
+
<p>The consumer sees a tree-shaped JavaScript API:</p>
|
|
36
|
+
<pre><code>const result = await tally.masters.units.fetch("Mani9");</code></pre>
|
|
37
|
+
<p>The consumer does not need to know:</p>
|
|
38
|
+
<ul>
|
|
39
|
+
<li>the internal source JSON structure;</li>
|
|
40
|
+
<ul>
|
|
41
|
+
<li>the TDL request template;</li>
|
|
42
|
+
<ul>
|
|
43
|
+
<li>how traversal finds the definition;</li>
|
|
44
|
+
<ul>
|
|
45
|
+
<li>how the HTTP request is constructed.</li>
|
|
46
|
+
<h2>Company name</h2>
|
|
47
|
+
<p>The company is runtime input.</p>
|
|
48
|
+
<pre><code>await tally.masters.units.fetch("Mani9");
|
|
49
|
+
await tally.masters.units.fetch("Another Company");</code></pre>
|
|
50
|
+
<p>The company should therefore not be permanently embedded in the source definition.</p>
|
|
51
|
+
<h2>CLI / scripting</h2>
|
|
52
|
+
<p>The same public operation can be exposed through a CLI layer without duplicating the Tally definition.</p>
|
|
53
|
+
<h2>Response</h2>
|
|
54
|
+
<p>The package returns the Tally response body. XML parsing and application-specific normalization remain outside this package.</p>
|
|
55
|
+
<p>For the internal architecture, see <a href="repo-developer.md">Repository Developer Guide</a>.</p>
|
|
56
|
+
</body>
|
|
57
|
+
</html>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[**View this document as HTML**](./developer.html)
|
|
2
|
+
|
|
3
|
+
# Application Developer Guide
|
|
4
|
+
|
|
5
|
+
This guide is for developers consuming Tally Public API from another application.
|
|
6
|
+
|
|
7
|
+
## Public boundary
|
|
8
|
+
|
|
9
|
+
The consumer sees a tree-shaped JavaScript API:
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
const result = await tally.masters.units.fetch("Mani9");
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The consumer does not need to know:
|
|
16
|
+
|
|
17
|
+
- the internal source JSON structure;
|
|
18
|
+
- the TDL request template;
|
|
19
|
+
- how traversal finds the definition;
|
|
20
|
+
- how the HTTP request is constructed.
|
|
21
|
+
|
|
22
|
+
## Company name
|
|
23
|
+
|
|
24
|
+
The company is runtime input.
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
await tally.masters.units.fetch("Mani9");
|
|
28
|
+
await tally.masters.units.fetch("Another Company");
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The company should therefore not be permanently embedded in the source definition.
|
|
32
|
+
|
|
33
|
+
## CLI / scripting
|
|
34
|
+
|
|
35
|
+
The same public operation can be exposed through a CLI layer without duplicating the Tally definition.
|
|
36
|
+
|
|
37
|
+
## Response
|
|
38
|
+
|
|
39
|
+
The package returns the Tally response body. XML parsing and application-specific normalization remain outside this package.
|
|
40
|
+
|
|
41
|
+
For the internal architecture, see [Repository Developer Guide](repo-developer.md).
|
|
@@ -0,0 +1,49 @@
|
|
|
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">
|
|
6
|
+
<title>End User</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>
|
|
22
|
+
</head>
|
|
23
|
+
<body>
|
|
24
|
+
<nav>
|
|
25
|
+
<a href="../README.html">README</a>
|
|
26
|
+
<a href="end-user.html">End User</a>
|
|
27
|
+
<a href="developer.html">Application Developer</a>
|
|
28
|
+
<a href="repo-developer.html">Repository Developer</a>
|
|
29
|
+
<a href="api.html">API</a>
|
|
30
|
+
<a href="architecture.html">Architecture</a>
|
|
31
|
+
</nav>
|
|
32
|
+
<h1>End User Guide</h1>
|
|
33
|
+
<p>This guide is for someone who wants to use the Tally package, not modify it.</p>
|
|
34
|
+
<h2>JavaScript</h2>
|
|
35
|
+
<pre><code>import tally from "./src/index.js";
|
|
36
|
+
|
|
37
|
+
const units = await tally.masters.units.fetch("Mani9");
|
|
38
|
+
console.log(units);</code></pre>
|
|
39
|
+
<p>The company name is supplied by the caller:</p>
|
|
40
|
+
<pre><code>tally.masters.units.fetch("My Company");</code></pre>
|
|
41
|
+
<p>The package builds the Tally request internally.</p>
|
|
42
|
+
<h2>What you receive</h2>
|
|
43
|
+
<p>The Tally response is returned as XML text. This package does not force an XML-to-JSON format on the consumer.</p>
|
|
44
|
+
<p>You can parse or transform the response with the tool you prefer.</p>
|
|
45
|
+
<h2>Public API</h2>
|
|
46
|
+
<p>See <a href="api.md">API Reference</a> for the currently exposed operations.</p>
|
|
47
|
+
<p>If you are integrating this package into a larger application, continue with the <a href="developer.md">Application Developer Guide</a>.</p>
|
|
48
|
+
</body>
|
|
49
|
+
</html>
|