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 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
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ # Tally Simple
2
+
3
+ [![npm version](https://img.shields.io/npm/v/tally-simple.svg)](https://www.npmjs.com/package/tally-simple)
4
+ [![license](https://img.shields.io/npm/l/tally-simple.svg)](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(&quot;Mani9&quot;);</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(&quot;Mani9&quot;);</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(&quot;Mani9&quot;);
49
+ await tally.masters.units.fetch(&quot;Another Company&quot;);</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 &quot;./src/index.js&quot;;
36
+
37
+ const units = await tally.masters.units.fetch(&quot;Mani9&quot;);
38
+ console.log(units);</code></pre>
39
+ <p>The company name is supplied by the caller:</p>
40
+ <pre><code>tally.masters.units.fetch(&quot;My Company&quot;);</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>