@yuou-finance/cli 0.1.0

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 (3) hide show
  1. package/README.md +115 -0
  2. package/package.json +31 -0
  3. package/scripts/run.js +51 -0
package/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # HSCS CLI
2
+
3
+ This Go CLI calls the API Key based `CliInvocationController` in `hscs-cli-service`. It stores each profile's API Key in the profile configuration, queries the organization and active roles associated with that key, and sends HTTP requests through `/cli/v1/invoke`.
4
+
5
+ ## Install from npm
6
+
7
+ After the npm packages have been published to your configured registry, install the command with Node.js 18 or newer. Go is not needed on the installation machine.
8
+
9
+ ```sh
10
+ npm install -g @yuou-finance/cli@0.1.0
11
+ hscs --help
12
+
13
+ # Run without a global install.
14
+ npx --yes @yuou-finance/cli@0.1.0 --help
15
+ ```
16
+
17
+ The initial packages contain binaries for macOS arm64, macOS x64, and Windows x64. The platform-specific binary is installed as an optional npm dependency. See [the npm release guide](docs/npm-release.md) for building and publishing all four packages.
18
+
19
+ ## Build and install
20
+
21
+ Use Go 1.24 or newer:
22
+
23
+ ```sh
24
+ go build -trimpath -o hscs ./cmd/hscs
25
+ go test ./...
26
+ go test -race -shuffle=on -count=1 ./...
27
+ go vet ./...
28
+ ```
29
+
30
+ Profiles store the service base URL, an optional local user label, and the API Key. The API Key determines the authenticated user and organization. New profiles use `https://service-api.yuoucn.com` by default; use `--environment URL` to override it. Existing profiles keep their configured URLs. Create a separate profile for each environment so each can keep its own service URL and API Key:
31
+
32
+ ```sh
33
+ hscs profile add prod
34
+ hscs profile add test --environment https://your-test-service.example
35
+
36
+ # Select the environment to use; profile list marks the current one with '*'.
37
+ hscs profile use test
38
+ hscs profile list
39
+ hscs profile show
40
+
41
+ # Import the test environment's API Key while the test profile is selected.
42
+ hscs api-key import "API_KEY"
43
+ hscs identity organization-id
44
+ hscs identity roles
45
+
46
+ # Switch back to production and import its API Key separately.
47
+ hscs profile use prod
48
+ hscs api-key import "PRODUCTION_API_KEY"
49
+ ```
50
+
51
+ Run `hscs profile use test` or `hscs profile use prod` to switch environments. API Keys are kept in their respective profiles. Replace the test service URL with the value for your deployment.
52
+
53
+ `api-key import` and `api-key rotate` accept the API Key as a positional string and save it in the profile configuration file. The key is stored as plain text in that file; command-line arguments may also appear in shell history and local process inspection. `hscs api-key delete` removes the current profile's key. Profile deletion removes the profile and its API Key.
54
+
55
+ Pass `--verbose` before or after a command to log HTTP method, endpoint, downstream target, response status and timing to stderr. Verbose output omits authentication headers and request/response bodies.
56
+
57
+ For a headless deployment, set both `HSCS_SECURESTORE_FILE` and `HSCS_SECURESTORE_KEY`. The key must be base64 encoding of exactly 32 random bytes, supplied through your secret manager's environment injection. Keep the key outside the encrypted store and configuration, preserve it across invocations, and restrict access to the process environment.
58
+
59
+ ## Invocation
60
+
61
+ `hscs identity organization-id` prints the organization ID for the current API Key. `hscs identity roles` prints the user's active roles as JSON. Use a listed role ID with `--role-id`; when omitted, the service selects the user's first active role.
62
+
63
+ Static operations send their source-defined path in `X-CLI-Path`; query values are sent on the `/cli/v1/invoke` request and forwarded to the downstream endpoint. The service verifies that any organization ID in the path matches the API Key's organization. Use `--data-file` or `--stdin` for request body bytes and `--output RELATIVE_FILE` to save successful response bytes. For path templates, pass user-supplied values with `--path-params`. The CLI fetches `{organizationId}` from `/cli/v1/invoke/organization-id` using the current API Key; do not pass it yourself. Other values are encoded as individual path segments; missing, unused, or unsafe values are rejected.
64
+
65
+ The static `hscs-business-manage query-ar-sales-orders` command queries revenue sales orders (营收销售单) through `POST /v1/{organizationId}/ar/sales-orders/query`. It first fetches the current organization ID through the CLI service, then uses it in the downstream path. Provide a JSON object body:
66
+
67
+ ```sh
68
+ hscs hscs-business-manage query-ar-sales-orders \
69
+ --data-file request.json
70
+ ```
71
+
72
+ The request body can also come from stdin with `--stdin`. For example, `request.json` may contain `{"salesOrderNum":"<sales-order-number>"}`. Replace placeholders with values from the current environment.
73
+
74
+ The `hscs-business-manage list-cusz-sale-orders` command lists customized CUSZ sales orders through `POST /v1/{organizationId}/cusz/sale-orders/list`. It fetches the current organization ID automatically and accepts a JSON object body with optional filters:
75
+
76
+ ```sh
77
+ hscs hscs-business-manage list-cusz-sale-orders \
78
+ --data-file request.json
79
+ ```
80
+
81
+ The `hscs-business-manage get-cusz-sale-order-detail` command gets a customized sales order detail through `GET /v1/{organizationId}/cusz/sale-orders/{saleOrderId}`. It fetches the current organization ID automatically; provide the required numeric `saleOrderId` with `--path-params`:
82
+
83
+ ```sh
84
+ hscs hscs-business-manage get-cusz-sale-order-detail \
85
+ --path-params '{"saleOrderId":12345}'
86
+ ```
87
+
88
+ Static service operations bind HTTP method and target path in source; they do not accept `--method` or `--path`. Additional yecai bill-pipeline commands are available under:
89
+
90
+ - `hscs-business-maindata` (for example `page-stores`)
91
+ - `hscs-internet-everything` (for example `get-platform-config-lov`, `upload-out-data-file`)
92
+ - `hscs-data-integration` (for example `query-itf-file-records`, `split-itf-imp-batches`)
93
+ - `hscs-business-manage` (receipt, recon, and cust-rec operations such as `query-receipt-headers`, `confirm-recon`)
94
+ - `hzero-iam` (for example `select-self`)
95
+
96
+ Examples:
97
+
98
+ ```sh
99
+ hscs hscs-internet-everything get-platform-config-lov \
100
+ --query '{"lovCode":"<lov-code>"}'
101
+ hscs hscs-internet-everything upload-out-data-file \
102
+ --file ./bill.csv \
103
+ --form-fields '{"platform":"ALIPAY","shopId":"<shop-id>"}'
104
+ hscs hscs-business-manage get-receipt-header-detail \
105
+ --path-params '{"receiptHeaderId":"<id>"}'
106
+ hscs hzero-iam select-self
107
+ ```
108
+
109
+ `split-itf-imp-batches` and `import-itf-imp-headers` require a JSON array body; most other POST operations require a JSON object body. See `skills/hscs-cli/REFERENCE.md` for the full static command list.
110
+
111
+ The CLI does not follow redirects. For an HTTP error response, it writes the service's error body to stderr and exits non-zero; it does not retry automatically. For binary or large successful results, use `--output` so response bytes are streamed to a file.
112
+
113
+ ## Verification limits
114
+
115
+ Local tests use test servers and do not prove compatibility with a deployed service. Record source commit, clean/dirty status, Go toolchain, target OS/architecture, build command and binary SHA-256 for a release. Windows compilation does not substitute for native Windows execution, ACL verification or keyring validation.
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@yuou-finance/cli",
3
+ "version": "0.1.0",
4
+ "description": "HSCS command-line interface",
5
+ "license": "UNLICENSED",
6
+ "bin": {
7
+ "hscs": "scripts/run.js"
8
+ },
9
+ "scripts": {
10
+ "pack:release": "node scripts/build-npm-packages.js"
11
+ },
12
+ "files": [
13
+ "scripts/run.js"
14
+ ],
15
+ "os": [
16
+ "darwin",
17
+ "win32"
18
+ ],
19
+ "cpu": [
20
+ "x64",
21
+ "arm64"
22
+ ],
23
+ "engines": {
24
+ "node": ">=18"
25
+ },
26
+ "optionalDependencies": {
27
+ "@yuou-finance/cli-darwin-arm64": "0.1.0",
28
+ "@yuou-finance/cli-darwin-x64": "0.1.0",
29
+ "@yuou-finance/cli-win32-x64": "0.1.0"
30
+ }
31
+ }
package/scripts/run.js ADDED
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict'
4
+
5
+ const { spawn } = require('node:child_process')
6
+
7
+ const platforms = {
8
+ 'darwin-arm64': ['@yuou-finance/cli-darwin-arm64', 'hscs'],
9
+ 'darwin-x64': ['@yuou-finance/cli-darwin-x64', 'hscs'],
10
+ 'win32-x64': ['@yuou-finance/cli-win32-x64', 'hscs.exe'],
11
+ }
12
+
13
+ const platform = `${process.platform}-${process.arch}`
14
+ const selected = platforms[platform]
15
+ if (!selected) {
16
+ console.error(`hscs: unsupported platform ${platform}`)
17
+ process.exit(1)
18
+ }
19
+
20
+ let binary
21
+ try {
22
+ binary = require.resolve(`${selected[0]}/bin/${selected[1]}`)
23
+ } catch (error) {
24
+ if (error.code !== 'MODULE_NOT_FOUND') {
25
+ throw error
26
+ }
27
+ console.error(`hscs: platform package ${selected[0]} is missing; reinstall @yuou-finance/cli with optional dependencies enabled`)
28
+ process.exit(1)
29
+ }
30
+
31
+ const child = spawn(binary, process.argv.slice(2), { stdio: 'inherit' })
32
+ for (const signal of ['SIGINT', 'SIGTERM']) {
33
+ process.on(signal, () => {
34
+ if (child.exitCode === null) {
35
+ child.kill(signal)
36
+ }
37
+ })
38
+ }
39
+ child.on('error', (error) => {
40
+ console.error(`hscs: cannot start ${binary}: ${error.message}`)
41
+ process.exitCode = 1
42
+ })
43
+ child.on('exit', (code, signal) => {
44
+ if (signal === 'SIGINT') {
45
+ process.exitCode = 130
46
+ } else if (signal === 'SIGTERM') {
47
+ process.exitCode = 143
48
+ } else {
49
+ process.exitCode = code === null ? 1 : code
50
+ }
51
+ })