Skip to content

Commit 5eb7663

Browse files
Add built node RPC OpenAPI spec for GitBook (stacks-core b62be8ee9) (#1893)
Bundled from stacks-core docs/rpc at b62be8ee9 with @redocly/cli 2.19, then normalized so each schema appears once under its declared name. Includes the normalize script and rebuild instructions.
1 parent 397efc6 commit 5eb7663

3 files changed

Lines changed: 8362 additions & 0 deletions

File tree

‎openapi/stacks-node-rpc/README.md‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Node RPC OpenAPI spec for GitBook
2+
3+
Source: stacks-network/stacks-core `docs/rpc/` at commit `b62be8ee94f2a08dc58d5ff6809a6d08b813c3e9` (main after PR #7691, 2026-10-06).
4+
GitBook spec slug: `stacks-node-rpc-api-dereferenced-new` (org `hoh4mQXTl8NvI3cETroY`).
5+
6+
## Why the extra step
7+
8+
`redocly bundle` turns every schema file into a component named after the file (`contract-interface.schema`), next to the name `openapi.yaml` declares (`ContractInterface`). The bundle has 114 schemas, 55 of them duplicates; GitBook lists each one on the models page. `normalize.py` folds each file-named component into its declared name, renames the 4 that have no declared name (`GetStackerSetPox4`, `GetStackerSetPox5`, `Principal`, `StandardPrincipal`) and rewrites every reference. Result: 59 schemas, 57 paths, 57 operations, same `redocly lint` result as upstream `openapi.yaml` (valid, 19 warnings).
9+
10+
## Rebuild
11+
12+
Run from a checkout of stacks-network/docs. Requires git, Node.js with npx, and Python 3.
13+
14+
```bash
15+
COMMIT=b62be8ee94f2a08dc58d5ff6809a6d08b813c3e9
16+
SHORT=${COMMIT:0:9}
17+
OUT="$PWD/openapi/stacks-node-rpc"
18+
TMP=$(mktemp -d)
19+
git clone -q --filter=blob:none --no-checkout https://github.com/stacks-network/stacks-core "$TMP/core"
20+
git -C "$TMP/core" sparse-checkout set docs/rpc
21+
git -C "$TMP/core" checkout -q "$COMMIT"
22+
cd "$TMP/core/docs/rpc"
23+
npx -y @redocly/cli@2.19 bundle openapi.yaml -o "$TMP/bundle.json" # 2.19 = the version stacks-core CI pins
24+
python3 "$OUT/normalize.py" "$TMP/bundle.json" "$OUT/stacks-node-rpc.$SHORT.json"
25+
npx -y @redocly/cli@2.19 lint "$OUT/stacks-node-rpc.$SHORT.json"
26+
cd - >/dev/null
27+
```
28+
29+
sha256 of `stacks-node-rpc.b62be8ee9.json`: `6bfbdf37b0380126035dfe4e46c7fbf7b4f4e8000c6e0a2979808910a48c2b32`
30+
31+
## Updating
32+
33+
When stacks-core changes `docs/rpc`, set `COMMIT` to the new commit (prefer a release tag's commit), rebuild, add the new file next to the old one, and point the GitBook spec at the new raw URL pinned to the docs merge commit. Old files can be removed once GitBook no longer points at them.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""Collapse redocly's file-named components into the names declared in openapi.yaml."""
2+
import json, re, sys
3+
src, out = sys.argv[1], sys.argv[2]
4+
d = json.load(open(src))
5+
s = d['components']['schemas']
6+
P = '#/components/schemas/'
7+
rename = {}
8+
# 1. declared alias X -> {$ref: P+F}: move F's body into X
9+
for k, v in list(s.items()):
10+
if '.' not in k and isinstance(v, dict) and list(v) == ['$ref'] and v['$ref'].startswith(P):
11+
f = v['$ref'][len(P):]
12+
if '.' in f and f not in rename:
13+
rename[f] = k
14+
# 2. remaining file-named components get a PascalCase name
15+
def pascal(f):
16+
stem = f.removesuffix('.schema')
17+
return ''.join(w[:1].upper() + w[1:] for w in re.split(r'[-_.]', stem))
18+
for k in list(s):
19+
if '.' in k and k not in rename:
20+
n = pascal(k)
21+
assert n not in s and n not in rename.values(), (k, n)
22+
rename[k] = n
23+
def walk(o):
24+
if isinstance(o, dict):
25+
for key, v in list(o.items()):
26+
if isinstance(v, str) and v.startswith(P) and v[len(P):] in rename:
27+
o[key] = P + rename[v[len(P):]]
28+
else:
29+
walk(v)
30+
elif isinstance(o, list):
31+
for v in o: walk(v)
32+
new = {}
33+
for k, v in s.items():
34+
if k in rename: continue
35+
if k in rename.values() and isinstance(v, dict) and list(v) == ['$ref']:
36+
f = v['$ref'][len(P):]; new[k] = s[f]; continue
37+
new[k] = v
38+
for f, n in rename.items():
39+
if n not in new: new[n] = s[f]
40+
d['components']['schemas'] = new
41+
walk(d)
42+
txt = json.dumps(d)
43+
left = re.findall(r'#/components/schemas/([A-Za-z0-9_.-]+)', txt)
44+
assert not [x for x in left if x not in new], set(x for x in left if x not in new)
45+
assert not [k for k in new if '.' in k]
46+
json.dump(d, open(out, 'w'), indent=2)
47+
print(len(s), '->', len(new), 'schemas;', len([r for r in rename.values() if r not in s]), 'new names:', sorted(r for r in rename.values() if r not in s))

0 commit comments

Comments
 (0)