@hyperscale0/cli 1.0.0-alpha.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.
Files changed (3) hide show
  1. package/README.md +25 -0
  2. package/hyperscale.js +29 -0
  3. package/package.json +23 -0
package/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # @hyperscale0/cli
2
+
3
+ The Hyperscale command line. It drives one Product's operation surface with a
4
+ Product API key, and it learns that surface live from the Product itself, so it
5
+ never drifts from the contract.
6
+
7
+ ## Use
8
+
9
+ The only input is a Product API key, minted on the Developers desk.
10
+
11
+ ```bash
12
+ export HYPERSCALE_API_KEY=<your Product API key>
13
+
14
+ bunx @hyperscale0/cli whoami
15
+ bunx @hyperscale0/cli ops list account
16
+ bunx @hyperscale0/cli call account.list --input '{"limit":5}'
17
+ ```
18
+
19
+ `npx @hyperscale0/cli` runs the same command. Add `--json` to any of them for
20
+ machine-readable output.
21
+
22
+ Point it at another host with `--base-url`, and at the live plane with
23
+ `--environment live`. Live keys and sandbox keys are never interchangeable.
24
+
25
+ Run `bunx @hyperscale0/cli --help` for the full option list.
package/hyperscale.js ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ const DEFAULT_BASE_URL="https://hyperscale0.ai",DEFAULT_ENVIRONMENT="sandbox",USAGE=`hyperscale <command> [options]
3
+
4
+ Commands:
5
+ whoami Show the product this API key resolves to
6
+ ops list [filter] List the product's callable operations
7
+ call <operation> Call one operation by name or operation id
8
+
9
+ Options:
10
+ --api-key <key> Product API key (default: $HYPERSCALE_API_KEY)
11
+ --base-url <url> API origin (default: $HYPERSCALE_BASE_URL, else ${DEFAULT_BASE_URL})
12
+ --environment <name> sandbox or live (default: $HYPERSCALE_ENVIRONMENT, else ${DEFAULT_ENVIRONMENT})
13
+ --input <json> JSON input object for call
14
+ --idempotency-key <key> Idempotency key for a mutation (default: generated)
15
+ --json Print machine-readable JSON
16
+ --version Print the CLI version
17
+ --help Print this help
18
+
19
+ The key rides in the environment, never on the command line, unless you are
20
+ pasting a one-off into a throwaway shell.
21
+
22
+ Examples:
23
+ hyperscale whoami
24
+ hyperscale ops list account
25
+ hyperscale call account.list --input '{"limit":5}'
26
+ hyperscale call account.retrieve --input '{"accountId":"acct_sandbox_..."}'
27
+ `;class UserError extends Error{}const FLAGS_WITH_VALUES=new Set(["--api-key","--base-url","--environment","--idempotency-key","--input"]);function parseArgv(t){const r=[],e={};for(let o=0;o<t.length;o+=1){const n=t[o];if(!n.startsWith("--")){r.push(n);continue}if(FLAGS_WITH_VALUES.has(n)){const s=t[o+1];if(s===void 0)throw new UserError(`${n} needs a value`);e[n]=s,o+=1;continue}if(n==="--help"||n==="--version"||n==="--json"){e[n]=!0;continue}throw new UserError(`Unknown option: ${n}`)}return{flags:e,positional:r}}function resolveConfig(t,r){const e=t["--api-key"]??r.HYPERSCALE_API_KEY;if(!e)throw new UserError("No API key. Set HYPERSCALE_API_KEY, or pass --api-key. Mint a Product API key on the Developers desk.");const o=t["--environment"]??r.HYPERSCALE_ENVIRONMENT??DEFAULT_ENVIRONMENT;if(o!=="sandbox"&&o!=="live")throw new UserError(`Unknown environment: ${o}. Use sandbox or live.`);const n=(t["--base-url"]??r.HYPERSCALE_BASE_URL??DEFAULT_BASE_URL).replace(/\/+$/,"");return{apiKey:e,baseUrl:n,environment:o}}async function request(t,r,e={}){const o=`${t.baseUrl}${r}`;let n;try{n=await fetch(o,{...e,headers:{accept:"application/json",authorization:`Bearer ${t.apiKey}`,"x-hyperscale-environment":t.environment,...e.headers}})}catch(i){throw new UserError(`Could not reach ${o}: ${i.message}`)}const s=await n.text();return{response:n,text:s}}async function readProduct(t){const{response:r,text:e}=await request(t,"/v1/llms.txt");if(!r.ok)throw apiError(r,e);const o=/^# (.+)$/m.exec(e),n=/^> Generated for composition (\S+) /m.exec(e),s=/^## Operations \((\d+)\)$/m.exec(e);if(!o||!s)throw new Error("The product document is not in the expected format; upgrade the CLI.");const i=[],a=/^- ([A-Z]+) (\S+) · (\S+) \((\S+); idempotency (\S+)\)$/gm;for(const c of e.matchAll(a))i.push({idempotency:c[5],method:c[1],name:c[3],operationId:c[4],path:c[2]});const p=Number(s[1]);if(i.length!==p)throw new Error(`The product document declares ${p} operations but ${i.length} parsed; upgrade the CLI.`);const l=/^- Package: (.+)$/m.exec(e);return{compositionId:n?n[1]:null,operations:i,packageName:l?l[1].trim():null,title:o[1].trim()}}function apiError(t,r){let e=r.trim();try{const o=JSON.parse(r);o&&o.error&&typeof o.error.message=="string"&&(e=`${o.error.code}: ${o.error.message}`)}catch{}return new UserError(`HTTP ${t.status}${e?` \xB7 ${e}`:""}`)}async function commandWhoami(t,r){const e=await readProduct(t);if(r["--json"]){print(JSON.stringify({baseUrl:t.baseUrl,compositionId:e.compositionId,environment:t.environment,operationCount:e.operations.length,packageName:e.packageName,product:e.title},null,2));return}const o=[["Product",e.title],["Composition",e.compositionId??"unknown"],["Environment",t.environment],["API",t.baseUrl],["Operations",String(e.operations.length)],["SDK package",e.packageName??"not published"]],n=Math.max(...o.map(([s])=>s.length));for(const[s,i]of o)print(`${s.padEnd(n)} ${i}`)}async function commandOpsList(t,r,e){const o=await readProduct(t),n=e?e.toLowerCase():null,s=n?o.operations.filter(a=>a.name.toLowerCase().includes(n)||a.path.toLowerCase().includes(n)):o.operations;if(r["--json"]){print(JSON.stringify(s,null,2));return}if(s.length===0){print(e?`No operation matches ${e}`:"No operations");return}const i=Math.max(...s.map(a=>a.name.length));for(const a of s)print(`${a.name.padEnd(i)} ${a.method.padEnd(6)}${a.path}`)}function bindPath(t,r){const e={...r},o=[],n=t.path.replace(/\{([^}]+)\}/g,(s,i)=>{const a=e[i];return a==null?(o.push(i),""):(delete e[i],encodeURIComponent(String(a)))});if(o.length>0)throw new UserError(`${t.name} needs ${o.join(", ")} in --input`);return{path:n,remaining:e}}function queryString(t){const r=new URLSearchParams;for(const[o,n]of Object.entries(t))n!=null&&r.set(o,typeof n=="string"?n:JSON.stringify(n));const e=r.toString();return e?`?${e}`:""}async function commandCall(t,r,e){if(!e)throw new UserError("call needs an operation name");const n=(await readProduct(t)).operations.find(d=>d.name===e||d.operationId===e);if(!n)throw new UserError(`${e} is not an operation of this product. Run "hyperscale ops list" to see them.`);const s=parseInput(r["--input"]),{path:i,remaining:a}=bindPath(n,s),p={method:n.method};let l=i;n.method==="GET"?l+=queryString(a):(p.body=JSON.stringify(a),p.headers={"content-type":"application/json",...n.idempotency==="not_required"?{}:{"idempotency-key":r["--idempotency-key"]??globalThis.crypto.randomUUID()}});const{response:c,text:u}=await request(t,l,p);if(!c.ok)throw apiError(c,u);print(formatBody(u))}function parseInput(t){if(t===void 0)return{};let r;try{r=JSON.parse(t)}catch(e){throw new UserError(`--input is not valid JSON: ${e.message}`)}if(r===null||typeof r!="object"||Array.isArray(r))throw new UserError("--input must be a JSON object");return r}function formatBody(t){if(t.trim()==="")return"";try{return JSON.stringify(JSON.parse(t),null,2)}catch{return t}}function print(t){process.stdout.write(`${t}
28
+ `)}async function version(){const{readFileSync:t}=await import("node:fs");return JSON.parse(t(new URL("./package.json",import.meta.url),"utf8")).version}async function main(t,r){const{flags:e,positional:o}=parseArgv(t);if(e["--version"])return print(await version()),0;if(e["--help"]||o.length===0)return process.stdout.write(USAGE),o.length===0&&!e["--help"]?1:0;const[n,...s]=o,i=resolveConfig(e,r);if(n==="whoami")return await commandWhoami(i,e),0;if(n==="ops"){if(s[0]!=="list")throw new UserError('The only ops subcommand is "list"');return await commandOpsList(i,e,s[1]),0}if(n==="call")return await commandCall(i,e,s[0]),0;throw new UserError(`Unknown command: ${n}`)}main(process.argv.slice(2),process.env).then(t=>{process.exitCode=t},t=>{process.stderr.write(`${t instanceof UserError?t.message:t.stack??String(t)}
29
+ `),process.exitCode=1});
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@hyperscale0/cli",
3
+ "version": "1.0.0-alpha.1",
4
+ "description": "The Hyperscale command line: drive one Product's operation surface with a Product API key.",
5
+ "license": "LicenseRef-Hyperscale-Proprietary",
6
+ "author": "Hyperscale LLC",
7
+ "contributors": [
8
+ "Meshael AlBakaawi",
9
+ "Amir Ayub",
10
+ "Sara AlBakaawi"
11
+ ],
12
+ "type": "module",
13
+ "bin": {
14
+ "hyperscale": "hyperscale.js"
15
+ },
16
+ "engines": {
17
+ "node": ">=20"
18
+ },
19
+ "homepage": "https://hyperscale0.ai",
20
+ "publishConfig": {
21
+ "access": "public"
22
+ }
23
+ }