@asturiu/v0-sdk 0.0.0-stage → 1.0.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 (239) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +5 -0
  4. package/README.md +82 -2
  5. package/contract/assertion-vectors.json +90 -0
  6. package/contract/schemas/branding.schema.json +46 -0
  7. package/contract/schemas/definitions.schema.json +376 -0
  8. package/contract/schemas/portal.schema.json +56 -0
  9. package/contract/tenant-api-routes.json +165 -0
  10. package/dist/branding.d.ts +131 -0
  11. package/dist/branding.d.ts.map +1 -0
  12. package/dist/branding.js +206 -0
  13. package/dist/branding.js.map +1 -0
  14. package/dist/changesets.d.ts +58 -0
  15. package/dist/changesets.d.ts.map +1 -0
  16. package/dist/changesets.js +18 -0
  17. package/dist/changesets.js.map +1 -0
  18. package/dist/cli/bin.d.ts +3 -0
  19. package/dist/cli/bin.d.ts.map +1 -0
  20. package/dist/cli/bin.js +12 -0
  21. package/dist/cli/bin.js.map +1 -0
  22. package/dist/cli/changesets.d.ts +14 -0
  23. package/dist/cli/changesets.d.ts.map +1 -0
  24. package/dist/cli/changesets.js +252 -0
  25. package/dist/cli/changesets.js.map +1 -0
  26. package/dist/cli/cli.d.ts +37 -0
  27. package/dist/cli/cli.d.ts.map +1 -0
  28. package/dist/cli/cli.js +415 -0
  29. package/dist/cli/cli.js.map +1 -0
  30. package/dist/cli/context.d.ts +147 -0
  31. package/dist/cli/context.d.ts.map +1 -0
  32. package/dist/cli/context.js +258 -0
  33. package/dist/cli/context.js.map +1 -0
  34. package/dist/cli/engine.d.ts +59 -0
  35. package/dist/cli/engine.d.ts.map +1 -0
  36. package/dist/cli/engine.js +85 -0
  37. package/dist/cli/engine.js.map +1 -0
  38. package/dist/cli/feedback.d.ts +40 -0
  39. package/dist/cli/feedback.d.ts.map +1 -0
  40. package/dist/cli/feedback.js +420 -0
  41. package/dist/cli/feedback.js.map +1 -0
  42. package/dist/cli/files.d.ts +83 -0
  43. package/dist/cli/files.d.ts.map +1 -0
  44. package/dist/cli/files.js +389 -0
  45. package/dist/cli/files.js.map +1 -0
  46. package/dist/cli/index.d.ts +8 -0
  47. package/dist/cli/index.d.ts.map +1 -0
  48. package/dist/cli/index.js +8 -0
  49. package/dist/cli/index.js.map +1 -0
  50. package/dist/cli/overview.d.ts +6 -0
  51. package/dist/cli/overview.d.ts.map +1 -0
  52. package/dist/cli/overview.js +379 -0
  53. package/dist/cli/overview.js.map +1 -0
  54. package/dist/cli/parts.d.ts +5 -0
  55. package/dist/cli/parts.d.ts.map +1 -0
  56. package/dist/cli/parts.js +414 -0
  57. package/dist/cli/parts.js.map +1 -0
  58. package/dist/cli/sources.d.ts +37 -0
  59. package/dist/cli/sources.d.ts.map +1 -0
  60. package/dist/cli/sources.js +91 -0
  61. package/dist/cli/sources.js.map +1 -0
  62. package/dist/cli/terminal.d.ts +135 -0
  63. package/dist/cli/terminal.d.ts.map +1 -0
  64. package/dist/cli/terminal.js +353 -0
  65. package/dist/cli/terminal.js.map +1 -0
  66. package/dist/cli/ui-page.d.ts +8 -0
  67. package/dist/cli/ui-page.d.ts.map +1 -0
  68. package/dist/cli/ui-page.js +216 -0
  69. package/dist/cli/ui-page.js.map +1 -0
  70. package/dist/cli/ui.d.ts +54 -0
  71. package/dist/cli/ui.d.ts.map +1 -0
  72. package/dist/cli/ui.js +251 -0
  73. package/dist/cli/ui.js.map +1 -0
  74. package/dist/client.d.ts +88 -0
  75. package/dist/client.d.ts.map +1 -0
  76. package/dist/client.js +165 -0
  77. package/dist/client.js.map +1 -0
  78. package/dist/contacts.d.ts +43 -0
  79. package/dist/contacts.d.ts.map +1 -0
  80. package/dist/contacts.js +46 -0
  81. package/dist/contacts.js.map +1 -0
  82. package/dist/definition-set.d.ts +731 -0
  83. package/dist/definition-set.d.ts.map +1 -0
  84. package/dist/definition-set.js +659 -0
  85. package/dist/definition-set.js.map +1 -0
  86. package/dist/definitions.d.ts +42 -0
  87. package/dist/definitions.d.ts.map +1 -0
  88. package/dist/definitions.js +154 -0
  89. package/dist/definitions.js.map +1 -0
  90. package/dist/enrolment.d.ts +9 -0
  91. package/dist/enrolment.d.ts.map +1 -0
  92. package/dist/enrolment.js +8 -0
  93. package/dist/enrolment.js.map +1 -0
  94. package/dist/fill.d.ts +73 -0
  95. package/dist/fill.d.ts.map +1 -0
  96. package/dist/fill.js +46 -0
  97. package/dist/fill.js.map +1 -0
  98. package/dist/index.d.ts +39 -0
  99. package/dist/index.d.ts.map +1 -0
  100. package/dist/index.js +39 -0
  101. package/dist/index.js.map +1 -0
  102. package/dist/notifications.d.ts +33 -0
  103. package/dist/notifications.d.ts.map +1 -0
  104. package/dist/notifications.js +36 -0
  105. package/dist/notifications.js.map +1 -0
  106. package/dist/oidc.d.ts +122 -0
  107. package/dist/oidc.d.ts.map +1 -0
  108. package/dist/oidc.js +150 -0
  109. package/dist/oidc.js.map +1 -0
  110. package/dist/overlay.d.ts +109 -0
  111. package/dist/overlay.d.ts.map +1 -0
  112. package/dist/overlay.js +58 -0
  113. package/dist/overlay.js.map +1 -0
  114. package/dist/passes.d.ts +95 -0
  115. package/dist/passes.d.ts.map +1 -0
  116. package/dist/passes.js +140 -0
  117. package/dist/passes.js.map +1 -0
  118. package/dist/portal-options.d.ts +65 -0
  119. package/dist/portal-options.d.ts.map +1 -0
  120. package/dist/portal-options.js +120 -0
  121. package/dist/portal-options.js.map +1 -0
  122. package/dist/reads.d.ts +41 -0
  123. package/dist/reads.d.ts.map +1 -0
  124. package/dist/reads.js +44 -0
  125. package/dist/reads.js.map +1 -0
  126. package/dist/recovery-words.d.ts +8 -0
  127. package/dist/recovery-words.d.ts.map +1 -0
  128. package/dist/recovery-words.js +136 -0
  129. package/dist/recovery-words.js.map +1 -0
  130. package/dist/recovery.d.ts +198 -0
  131. package/dist/recovery.d.ts.map +1 -0
  132. package/dist/recovery.js +112 -0
  133. package/dist/recovery.js.map +1 -0
  134. package/dist/reveal.d.ts +35 -0
  135. package/dist/reveal.d.ts.map +1 -0
  136. package/dist/reveal.js +66 -0
  137. package/dist/reveal.js.map +1 -0
  138. package/dist/seal.d.ts +15 -0
  139. package/dist/seal.d.ts.map +1 -0
  140. package/dist/seal.js +0 -0
  141. package/dist/seal.js.map +1 -0
  142. package/dist/session.d.ts +66 -0
  143. package/dist/session.d.ts.map +1 -0
  144. package/dist/session.js +61 -0
  145. package/dist/session.js.map +1 -0
  146. package/dist/signing-in-mark.d.ts +14 -0
  147. package/dist/signing-in-mark.d.ts.map +1 -0
  148. package/dist/signing-in-mark.js +24 -0
  149. package/dist/signing-in-mark.js.map +1 -0
  150. package/dist/signing-in.d.ts +22 -0
  151. package/dist/signing-in.d.ts.map +1 -0
  152. package/dist/signing-in.js +203 -0
  153. package/dist/signing-in.js.map +1 -0
  154. package/dist/tags.d.ts +96 -0
  155. package/dist/tags.d.ts.map +1 -0
  156. package/dist/tags.js +88 -0
  157. package/dist/tags.js.map +1 -0
  158. package/dist/tenant-subscription.d.ts +47 -0
  159. package/dist/tenant-subscription.d.ts.map +1 -0
  160. package/dist/tenant-subscription.js +7 -0
  161. package/dist/tenant-subscription.js.map +1 -0
  162. package/dist/testing/index.d.ts +125 -0
  163. package/dist/testing/index.d.ts.map +1 -0
  164. package/dist/testing/index.js +320 -0
  165. package/dist/testing/index.js.map +1 -0
  166. package/dist/theme.d.ts +237 -0
  167. package/dist/theme.d.ts.map +1 -0
  168. package/dist/theme.js +504 -0
  169. package/dist/theme.js.map +1 -0
  170. package/dist/tickets.d.ts +152 -0
  171. package/dist/tickets.d.ts.map +1 -0
  172. package/dist/tickets.js +65 -0
  173. package/dist/tickets.js.map +1 -0
  174. package/dist/tiers.d.ts +168 -0
  175. package/dist/tiers.d.ts.map +1 -0
  176. package/dist/tiers.js +341 -0
  177. package/dist/tiers.js.map +1 -0
  178. package/dist/types.d.ts +885 -0
  179. package/dist/types.d.ts.map +1 -0
  180. package/dist/types.js +12 -0
  181. package/dist/types.js.map +1 -0
  182. package/dist/urlid.d.ts +50 -0
  183. package/dist/urlid.d.ts.map +1 -0
  184. package/dist/urlid.js +78 -0
  185. package/dist/urlid.js.map +1 -0
  186. package/dist/version.d.ts +15 -0
  187. package/dist/version.d.ts.map +1 -0
  188. package/dist/version.js +15 -0
  189. package/dist/version.js.map +1 -0
  190. package/make/asturiu.mk +43 -0
  191. package/package.json +63 -4
  192. package/src/branding.ts +221 -0
  193. package/src/changesets.ts +61 -0
  194. package/src/cli/bin.ts +12 -0
  195. package/src/cli/changesets.ts +233 -0
  196. package/src/cli/cli.ts +425 -0
  197. package/src/cli/context.ts +299 -0
  198. package/src/cli/engine.ts +112 -0
  199. package/src/cli/feedback.ts +406 -0
  200. package/src/cli/files.ts +371 -0
  201. package/src/cli/index.ts +7 -0
  202. package/src/cli/overview.ts +343 -0
  203. package/src/cli/parts.ts +371 -0
  204. package/src/cli/sources.ts +111 -0
  205. package/src/cli/terminal.ts +384 -0
  206. package/src/cli/ui-page.ts +215 -0
  207. package/src/cli/ui.ts +266 -0
  208. package/src/client.ts +202 -0
  209. package/src/contacts.ts +61 -0
  210. package/src/definition-set.ts +965 -0
  211. package/src/definitions.ts +156 -0
  212. package/src/enrolment.ts +10 -0
  213. package/src/fill.ts +83 -0
  214. package/src/index.ts +38 -0
  215. package/src/notifications.ts +55 -0
  216. package/src/oidc.ts +199 -0
  217. package/src/overlay.ts +137 -0
  218. package/src/passes.ts +168 -0
  219. package/src/portal-options.ts +125 -0
  220. package/src/reads.ts +71 -0
  221. package/src/recovery-words.ts +137 -0
  222. package/src/recovery.ts +269 -0
  223. package/src/reveal.ts +72 -0
  224. package/src/seal.ts +0 -0
  225. package/src/session.ts +93 -0
  226. package/src/signing-in-mark.ts +23 -0
  227. package/src/signing-in.ts +213 -0
  228. package/src/tags.ts +146 -0
  229. package/src/tenant-subscription.ts +44 -0
  230. package/src/testing/index.ts +337 -0
  231. package/src/theme.ts +628 -0
  232. package/src/tickets.ts +195 -0
  233. package/src/tiers.ts +397 -0
  234. package/src/types.ts +847 -0
  235. package/src/urlid.ts +77 -0
  236. package/src/version.ts +15 -0
  237. package/templates/asturiu/branding.json +4 -0
  238. package/templates/asturiu/definitions.json +23 -0
  239. package/templates/asturiu/portal.json +16 -0
@@ -0,0 +1,216 @@
1
+ /**
2
+ * The local page of `asturiu-v0-tenant ui` (ADR-074 §7): one HTML document with its style and script inline, served
3
+ * from the package, nothing fetched from elsewhere. `__NONCE__` and `__COMMAND__` are filled in per response. The
4
+ * script writes every answer as text (`textContent`), never as markup: ticket text, titles and server messages are
5
+ * data.
6
+ */
7
+ export const UI_PAGE = `<!doctype html>
8
+ <html lang="en">
9
+ <head>
10
+ <meta charset="utf-8">
11
+ <meta name="viewport" content="width=device-width, initial-scale=1">
12
+ <meta name="color-scheme" content="light dark">
13
+ <meta name="robots" content="noindex">
14
+ <title>Tenant command line</title>
15
+ <style nonce="__NONCE__">
16
+ :root { --bg: #f6f5f1; --panel: #ffffff; --line: #e2e0d8; --fg: #1b1d21; --muted: #626770; --accent: #2b6f6a; --accent-fg: #ffffff; --ok: #2f7d3a; --warn: #9a6a00; --fail: #b3261e; --code: #eeece6; }
17
+ @media (prefers-color-scheme: dark) { :root { --bg: #0f1113; --panel: #171a1d; --line: #2a2f34; --fg: #e8e6e1; --muted: #9aa1a8; --accent: #5fb3aa; --accent-fg: #0f1113; --ok: #6cc47a; --warn: #e0b54a; --fail: #f07167; --code: #20252a; } }
18
+ * { box-sizing: border-box; }
19
+ body { margin: 0; background: var(--bg); color: var(--fg); font: 15px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif; }
20
+ header { padding: 16px 24px; border-bottom: 1px solid var(--line); display: flex; gap: 12px; align-items: baseline; flex-wrap: wrap; }
21
+ header h1 { font-size: 17px; margin: 0; }
22
+ header p { margin: 0; color: var(--muted); font-size: 13px; }
23
+ main { display: grid; grid-template-columns: minmax(240px, 300px) 1fr; gap: 24px; padding: 24px; max-width: 1280px; }
24
+ @media (max-width: 800px) { main { grid-template-columns: 1fr; padding: 16px; } }
25
+ nav section { margin-bottom: 20px; }
26
+ nav h2 { font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin: 0 0 8px; }
27
+ button { font: inherit; border: 1px solid var(--line); background: var(--panel); color: var(--fg); border-radius: 8px; padding: 6px 12px; cursor: pointer; margin: 0 6px 6px 0; }
28
+ button:hover { border-color: var(--accent); }
29
+ button.write { border-color: var(--accent); }
30
+ button[disabled] { opacity: .5; cursor: wait; }
31
+ input, select { font: inherit; border: 1px solid var(--line); background: var(--panel); color: var(--fg); border-radius: 8px; padding: 5px 8px; margin: 0 6px 6px 0; max-width: 100%; }
32
+ input[type=number] { width: 80px; }
33
+ label.check { display: inline-flex; gap: 4px; align-items: center; margin-right: 10px; font-size: 14px; }
34
+ #result { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 20px; min-height: 240px; overflow-x: auto; }
35
+ #result .empty { color: var(--muted); }
36
+ .line { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 13px; background: var(--code); padding: 6px 10px; border-radius: 6px; display: inline-block; margin: 4px 0 12px; word-break: break-all; }
37
+ .exit { font-weight: 600; }
38
+ .exit.ok { color: var(--ok); } .exit.warn { color: var(--warn); } .exit.fail { color: var(--fail); }
39
+ dl { display: grid; grid-template-columns: minmax(120px, max-content) 1fr; gap: 4px 16px; margin: 4px 0 8px; }
40
+ dt { color: var(--muted); }
41
+ dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
42
+ table { border-collapse: collapse; font-size: 14px; margin: 4px 0 8px; }
43
+ th, td { text-align: left; padding: 4px 10px 4px 0; border-bottom: 1px solid var(--line); vertical-align: top; overflow-wrap: anywhere; }
44
+ th { color: var(--muted); font-weight: 500; }
45
+ pre { white-space: pre-wrap; overflow-wrap: anywhere; background: var(--code); padding: 12px; border-radius: 8px; font-size: 13px; }
46
+ .prompt h3 { font-size: 14px; margin: 12px 0 4px; }
47
+ .prompt p { color: var(--muted); margin: 0 0 6px; font-size: 13px; }
48
+ details { margin-top: 16px; } summary { color: var(--muted); cursor: pointer; }
49
+ .handover { border-left: 3px solid var(--warn); padding: 4px 12px; margin: 8px 0 12px; }
50
+ </style>
51
+ </head>
52
+ <body>
53
+ <header>
54
+ <h1>Tenant command line</h1>
55
+ <p>This page runs on this machine only. Each button runs the same command as the terminal; the key stays in the command's process.</p>
56
+ </header>
57
+ <main>
58
+ <nav>
59
+ <section>
60
+ <h2>Overview</h2>
61
+ <button data-action="status">Status</button>
62
+ <button data-action="doctor">Doctor</button>
63
+ <button data-action="engine">Engine</button>
64
+ </section>
65
+ <section>
66
+ <h2>Repository files</h2>
67
+ <button data-action="definitions">Definition set</button>
68
+ <button data-action="branding">Branding and portal</button>
69
+ <div>
70
+ <label class="check"><input type="checkbox" name="part" value="definitions" checked>definitions</label>
71
+ <label class="check"><input type="checkbox" name="part" value="branding" checked>branding</label>
72
+ <label class="check"><input type="checkbox" name="part" value="portal" checked>portal</label>
73
+ </div>
74
+ <button data-action="apply" class="write">Apply to the Engine</button>
75
+ <div>
76
+ <button data-action="pull">Pull: show the differences</button>
77
+ <button data-action="pull-write" class="write">Pull: write the files</button>
78
+ </div>
79
+ </section>
80
+ <section>
81
+ <h2>Changesets</h2>
82
+ <button data-action="changesets">List</button>
83
+ <button data-action="changesets-pull" class="write">Pull the documents</button>
84
+ <div><input id="changeset-number" type="number" min="1" placeholder="#"><button data-action="changeset">Show one, with its prompt</button></div>
85
+ </section>
86
+ <section>
87
+ <h2>Feedback</h2>
88
+ <button data-action="feedback-queue">Queue</button>
89
+ <div><input id="feedback-file" placeholder="file in this repository (.md or .json)"></div>
90
+ <div>
91
+ <select id="feedback-kind"><option value="defect">defect</option><option value="limitation">limitation</option><option value="question">question</option></select>
92
+ <input id="feedback-area" placeholder="area">
93
+ <button data-action="feedback-add" class="write">Add to the queue</button>
94
+ </div>
95
+ <button data-action="feedback-dry-run">Show the report</button>
96
+ <button data-action="feedback-send" class="write">Send</button>
97
+ </section>
98
+ </nav>
99
+ <div id="result"><p class="empty">Pick a task on the left. The answer shows here, beside the line to type in a terminal instead.</p></div>
100
+ </main>
101
+ <script nonce="__NONCE__">
102
+ (() => {
103
+ const COMMAND = "__COMMAND__";
104
+ const QUESTIONS = {
105
+ apply: "Send the repository's files to the Engine?",
106
+ "pull-write": "Write the stored branding and portal into the repository's files? It replaces what is there.",
107
+ "changesets-pull": "Copy the missing changeset documents into the repository?",
108
+ "feedback-add": "Add this file to the feedback queue? Nothing is sent yet.",
109
+ "feedback-drop": "Take this finding out of the queue?",
110
+ "feedback-send": "Send the queued findings to the Engine team as one report?",
111
+ };
112
+ const EXITS = { 0: ["done", "ok"], 1: ["failed or refused", "fail"], 2: ["not understood", "fail"], 3: ["done here, not reported to the Engine", "warn"] };
113
+ const result = document.getElementById("result");
114
+ const el = (tag, text, cls) => { const e = document.createElement(tag); if (text !== undefined && text !== null) e.textContent = String(text); if (cls) e.className = cls; return e; };
115
+ const words = (k) => String(k).replace(/_/g, " ");
116
+ const isUrl = (s) => typeof s === "string" && /^https?:\\/\\/[^\\s]+$/.test(s);
117
+
118
+ function value(v, depth) {
119
+ if (v === null || v === undefined || v === "") return el("span", "—");
120
+ if (typeof v === "boolean") return el("span", v ? "yes" : "no");
121
+ if (typeof v === "number") return el("span", v);
122
+ if (typeof v === "string") {
123
+ if (isUrl(v)) { const a = el("a", v); a.href = v; a.rel = "noreferrer noopener"; a.target = "_blank"; return a; }
124
+ return v.includes("\\n") ? el("pre", v) : el("span", v);
125
+ }
126
+ if (Array.isArray(v)) {
127
+ if (!v.length) return el("span", "none");
128
+ if (v.every((x) => x && typeof x === "object" && !Array.isArray(x))) return table(v, depth);
129
+ return el("span", v.map((x) => (typeof x === "object" ? JSON.stringify(x) : String(x))).join(", "));
130
+ }
131
+ if (depth > 3) return el("span", JSON.stringify(v));
132
+ return object(v, depth);
133
+ }
134
+ function object(o, depth) {
135
+ const dl = el("dl");
136
+ for (const [k, v] of Object.entries(o)) {
137
+ if (k === "prompt" && typeof v === "string") continue;
138
+ dl.append(el("dt", words(k)));
139
+ const dd = el("dd");
140
+ dd.append(value(v, depth + 1));
141
+ dl.append(dd);
142
+ }
143
+ return dl;
144
+ }
145
+ function table(rows, depth) {
146
+ const cols = [...new Set(rows.flatMap((r) => Object.keys(r)))].filter((c) => !["detail", "stored", "posts", "parties", "decisions"].includes(c)).slice(0, 8);
147
+ const t = el("table"); const head = el("tr");
148
+ for (const c of cols) head.append(el("th", words(c)));
149
+ t.append(head);
150
+ for (const r of rows) {
151
+ const tr = el("tr");
152
+ for (const c of cols) { const td = el("td"); const v = r[c]; td.append(v && typeof v === "object" ? el("span", JSON.stringify(v)) : value(v, depth + 1)); tr.append(td); }
153
+ t.append(tr);
154
+ }
155
+ return t;
156
+ }
157
+
158
+ function show(answer) {
159
+ result.replaceChildren();
160
+ const [meaning, tone] = EXITS[answer.exit] || ["exit " + answer.exit, "fail"];
161
+ const head = el("p"); head.append(el("span", meaning, "exit " + tone));
162
+ result.append(head);
163
+ result.append(el("p", "In a terminal:"));
164
+ result.append(el("code", answer.terminal, "line"));
165
+ const r = answer.result;
166
+ if (r && typeof r === "object") {
167
+ if (r.reported === false && r.command) {
168
+ const h = el("div", null, "handover");
169
+ h.append(el("p", "Not reported to the Engine" + (r.reason ? ": " + r.reason : ".")));
170
+ h.append(el("code", r.command, "line"));
171
+ result.append(h);
172
+ }
173
+ if (typeof r.prompt === "string") {
174
+ const p = el("div", null, "prompt");
175
+ p.append(el("h3", "Prompt for your coding agent"));
176
+ p.append(el("p", "Show this to your agent once you have read it and agree. This page never runs it."));
177
+ p.append(el("pre", r.prompt));
178
+ result.append(p);
179
+ }
180
+ result.append(value(r, 0));
181
+ const raw = el("details"); raw.append(el("summary", "The answer as JSON")); raw.append(el("pre", JSON.stringify(r, null, 2)));
182
+ result.append(raw);
183
+ } else if (answer.output) result.append(el("pre", answer.output));
184
+ }
185
+
186
+ async function runAction(action, params) {
187
+ if (QUESTIONS[action] && !window.confirm(QUESTIONS[action])) return;
188
+ const buttons = document.querySelectorAll("button");
189
+ buttons.forEach((b) => (b.disabled = true));
190
+ result.replaceChildren(el("p", "Running " + COMMAND + " …", "empty"));
191
+ try {
192
+ const res = await fetch("/api/run", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ action, params }) });
193
+ const answer = await res.json();
194
+ if (!res.ok) { result.replaceChildren(el("p", answer.error || "The page refused the request.", "exit fail")); return; }
195
+ show(answer);
196
+ } catch (err) {
197
+ result.replaceChildren(el("p", "The command line stopped. Run it again for a new page.", "exit fail"));
198
+ } finally {
199
+ buttons.forEach((b) => (b.disabled = false));
200
+ }
201
+ }
202
+
203
+ document.querySelectorAll("button[data-action]").forEach((b) => b.addEventListener("click", () => {
204
+ const action = b.dataset.action;
205
+ const params = {};
206
+ if (action === "apply") params.parts = [...document.querySelectorAll("input[name=part]:checked")].map((i) => i.value);
207
+ if (action === "changeset") params.number = Number(document.getElementById("changeset-number").value);
208
+ if (action === "feedback-add") { params.file = document.getElementById("feedback-file").value; params.kind = document.getElementById("feedback-kind").value; params.area = document.getElementById("feedback-area").value; }
209
+ runAction(action, params);
210
+ }));
211
+ })();
212
+ </script>
213
+ </body>
214
+ </html>
215
+ `;
216
+ //# sourceMappingURL=ui-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-page.js","sourceRoot":"","sources":["../../src/cli/ui-page.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgNtB,CAAC"}
@@ -0,0 +1,54 @@
1
+ import { type Ctx } from "./context.js";
2
+ /** One action the page may ask for: the arguments it runs with, and the line the person would type instead. */
3
+ export interface UiAction {
4
+ argv: string[];
5
+ shown: string[];
6
+ /** Whether it writes to the repository or sends to the Engine: the page asks first. */
7
+ writes: boolean;
8
+ }
9
+ /**
10
+ * The closed list of what the page may run. Nothing outside it, and no argument the page sends goes on unchecked:
11
+ * no keys, no people, no roles, no Customers and no tickets of theirs (§7).
12
+ */
13
+ export declare function uiAction(root: string, name: string, p?: Record<string, unknown>): UiAction | null;
14
+ export interface UiRequest {
15
+ method: string;
16
+ url: string;
17
+ headers: Record<string, string | undefined>;
18
+ body?: string;
19
+ }
20
+ export interface UiResponse {
21
+ status: number;
22
+ headers: Record<string, string>;
23
+ body: string;
24
+ }
25
+ /**
26
+ * The page's request handler, without a socket: what the server runs per request, and what the tests call. `runAction`
27
+ * runs one action and answers its exit code and its JSON.
28
+ */
29
+ export declare function createUiHandler(o: {
30
+ port: number;
31
+ token: string;
32
+ session?: string;
33
+ command: string;
34
+ root: string;
35
+ runAction: (a: UiAction) => Promise<{
36
+ exit: number;
37
+ result: unknown;
38
+ output: string;
39
+ }>;
40
+ }): {
41
+ handle: (req: UiRequest) => Promise<UiResponse>;
42
+ address: string;
43
+ origin: string;
44
+ session: string;
45
+ };
46
+ export declare function escapeHtml(s: string): string;
47
+ /** Runs one action in this process, as the terminal would with `--json`, and answers its exit code and JSON. */
48
+ export declare function actionRunner(ctx: Ctx): (a: UiAction) => Promise<{
49
+ exit: number;
50
+ result: unknown;
51
+ output: string;
52
+ }>;
53
+ export declare function cmdUi(ctx: Ctx): Promise<void>;
54
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/cli/ui.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,KAAK,GAAG,EAAyB,MAAM,cAAc,CAAC;AAG/D,+GAA+G;AAC/G,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,uFAAuF;IACvF,MAAM,EAAE,OAAO,CAAC;CACjB;AAKD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,QAAQ,GAAG,IAAI,CA+CrG;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;CACd;AAkBD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE;kBAW9K,SAAS,KAAG,OAAO,CAAC,UAAU,CAAC;;;;EAyD3D;AAID,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,gHAAgH;AAChH,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,IACrB,GAAG,QAAQ;;;;GAY1B;AAQD,wBAAsB,KAAK,CAAC,GAAG,EAAE,GAAG,iBAiDnC"}
package/dist/cli/ui.js ADDED
@@ -0,0 +1,251 @@
1
+ /**
2
+ * `asturiu-v0-tenant ui` (ADR-074 §7): a page on this machine for the tasks that touch the repository's files, served
3
+ * by the command line's own process.
4
+ *
5
+ * - Loopback only: 127.0.0.1 on a free port. The address is printed once with a one-time token; the token becomes an
6
+ * HttpOnly, SameSite=Strict cookie and the address loses it. Every request must carry the Host of that address and
7
+ * every write its Origin. There are no CORS headers.
8
+ * - The key stays in this process. The page never receives it and never signs.
9
+ * - Each button runs `run()` (the same function the terminal does) with `--json`, from a closed list of actions, and
10
+ * shows the answer beside the line to type instead.
11
+ * - Text from the Engine is data: the page writes it as text, never as markup. Nothing is fetched from elsewhere.
12
+ */
13
+ import { spawn } from "node:child_process";
14
+ import { randomBytes, timingSafeEqual } from "node:crypto";
15
+ import { existsSync, statSync } from "node:fs";
16
+ import { createServer } from "node:http";
17
+ import path from "node:path";
18
+ import { run } from "./cli.js";
19
+ import { EXIT, Fail, emit, str } from "./context.js";
20
+ import { UI_PAGE } from "./ui-page.js";
21
+ const PARTS = ["definitions", "branding", "portal"];
22
+ const KINDS = ["defect", "limitation", "question"];
23
+ /**
24
+ * The closed list of what the page may run. Nothing outside it, and no argument the page sends goes on unchecked:
25
+ * no keys, no people, no roles, no Customers and no tickets of theirs (§7).
26
+ */
27
+ export function uiAction(root, name, p = {}) {
28
+ const same = (argv, writes = false) => ({ argv, shown: argv, writes });
29
+ switch (name) {
30
+ case "status":
31
+ case "doctor":
32
+ case "engine":
33
+ case "definitions":
34
+ case "branding":
35
+ case "changesets":
36
+ return same([name]);
37
+ case "apply": {
38
+ const parts = Array.isArray(p.parts) ? p.parts.filter((x) => typeof x === "string" && PARTS.includes(x)) : [];
39
+ return same(["apply", ...new Set(parts)], true);
40
+ }
41
+ case "pull":
42
+ return { argv: ["pull", "--dry-run"], shown: ["pull", "--dry-run"], writes: false };
43
+ case "pull-write":
44
+ return { argv: ["pull", "--write"], shown: ["pull", "--write"], writes: true };
45
+ case "changesets-pull":
46
+ return same(["changesets", "pull"], true);
47
+ case "changeset": {
48
+ const n = Number(p.number);
49
+ return Number.isInteger(n) && n > 0 && n < 10_000 ? same(["changeset", String(n)]) : null;
50
+ }
51
+ case "feedback-queue":
52
+ return same(["feedback", "queue"]);
53
+ case "feedback-add": {
54
+ const file = typeof p.file === "string" ? p.file.trim() : "";
55
+ const full = path.resolve(root, file);
56
+ // A file of this repository only: nothing outside it, nothing that is not a regular file.
57
+ if (!file || !(full === root || full.startsWith(root + path.sep)) || !existsSync(full) || !statSync(full).isFile() || !/\.(md|json)$/i.test(full))
58
+ return null;
59
+ const argv = ["feedback", "add", path.relative(root, full)];
60
+ if (typeof p.kind === "string" && KINDS.includes(p.kind))
61
+ argv.push("--kind", p.kind);
62
+ if (typeof p.area === "string" && /^[a-z0-9][a-z0-9 ,_-]{0,60}$/i.test(p.area))
63
+ argv.push("--area", p.area);
64
+ return same(argv, true);
65
+ }
66
+ case "feedback-drop": {
67
+ const n = Number(p.number);
68
+ return Number.isInteger(n) && n > 0 && n < 1000 ? { argv: ["feedback", "drop", String(n), "--yes"], shown: ["feedback", "drop", String(n)], writes: true } : null;
69
+ }
70
+ case "feedback-dry-run":
71
+ return same(["feedback", "send", "--dry-run"]);
72
+ case "feedback-send":
73
+ return { argv: ["feedback", "send", "--yes"], shown: ["feedback", "send"], writes: true };
74
+ default:
75
+ return null;
76
+ }
77
+ }
78
+ const SAFE_HEADERS = { "cache-control": "no-store", "x-content-type-options": "nosniff", "referrer-policy": "no-referrer", "x-frame-options": "DENY", "cross-origin-resource-policy": "same-origin" };
79
+ const equal = (a, b) => {
80
+ const x = Buffer.from(a);
81
+ const y = Buffer.from(b);
82
+ return x.length === y.length && timingSafeEqual(x, y);
83
+ };
84
+ function cookieOf(header, name) {
85
+ for (const part of (header ?? "").split(";")) {
86
+ const [k, ...v] = part.trim().split("=");
87
+ if (k === name)
88
+ return v.join("=");
89
+ }
90
+ return null;
91
+ }
92
+ /**
93
+ * The page's request handler, without a socket: what the server runs per request, and what the tests call. `runAction`
94
+ * runs one action and answers its exit code and its JSON.
95
+ */
96
+ export function createUiHandler(o) {
97
+ const address = `127.0.0.1:${o.port}`;
98
+ const origin = `http://${address}`;
99
+ const cookie = `asturiu_ui_${o.port}`;
100
+ const session = o.session ?? randomBytes(32).toString("base64url");
101
+ let token = o.token;
102
+ let busy = Promise.resolve();
103
+ const text = (status, body, extra = {}) => ({ status, headers: { ...SAFE_HEADERS, "content-type": "text/plain; charset=utf-8", ...extra }, body });
104
+ const json = (status, body) => ({ status, headers: { ...SAFE_HEADERS, "content-type": "application/json; charset=utf-8" }, body: JSON.stringify(body) });
105
+ async function handle(req) {
106
+ // The address the page was printed with, and no other: a page another site loads in this browser sends another Host.
107
+ if (req.headers.host !== address)
108
+ return text(421, "Open the address this command printed.");
109
+ const url = new URL(req.url, origin);
110
+ const signedIn = (() => {
111
+ const c = cookieOf(req.headers.cookie, cookie);
112
+ return c !== null && equal(c, session);
113
+ })();
114
+ if (req.method === "GET" && url.pathname === "/") {
115
+ const offered = url.searchParams.get("token");
116
+ if (offered !== null) {
117
+ // The one-time token: it becomes the cookie once, and the address loses it.
118
+ if (token === null || !equal(offered, token))
119
+ return text(403, "This address has been used already. Run the command again for a new one.");
120
+ token = null;
121
+ return { status: 303, headers: { ...SAFE_HEADERS, location: "/", "set-cookie": `${cookie}=${session}; HttpOnly; SameSite=Strict; Path=/`, "content-type": "text/plain; charset=utf-8" }, body: "" };
122
+ }
123
+ if (!signedIn)
124
+ return text(403, "Open the address this command printed, with its token.");
125
+ const nonce = randomBytes(16).toString("base64");
126
+ return {
127
+ status: 200,
128
+ headers: {
129
+ ...SAFE_HEADERS,
130
+ "content-type": "text/html; charset=utf-8",
131
+ "content-security-policy": `default-src 'none'; script-src 'nonce-${nonce}'; style-src 'nonce-${nonce}'; connect-src 'self'; img-src 'self' data:; base-uri 'none'; form-action 'none'; frame-ancestors 'none'`,
132
+ },
133
+ body: UI_PAGE.replaceAll("__NONCE__", nonce).replaceAll("__COMMAND__", escapeHtml(o.command)),
134
+ };
135
+ }
136
+ if (url.pathname === "/api/run") {
137
+ if (req.method !== "POST")
138
+ return text(405, "POST only.", { allow: "POST" });
139
+ if (!signedIn)
140
+ return json(403, { error: "not signed in to this page" });
141
+ // A write from another origin never reaches here: the browser sends this page's own Origin, and nothing else is let through.
142
+ if (req.headers.origin !== origin)
143
+ return json(403, { error: "wrong origin" });
144
+ if (!/^application\/json\b/.test(req.headers["content-type"] ?? ""))
145
+ return json(415, { error: "JSON only" });
146
+ if ((req.body ?? "").length > 16 * 1024)
147
+ return json(413, { error: "too large" });
148
+ let body;
149
+ try {
150
+ body = JSON.parse(req.body ?? "{}");
151
+ }
152
+ catch {
153
+ return json(400, { error: "not JSON" });
154
+ }
155
+ const name = typeof body.action === "string" ? body.action : "";
156
+ const params = body.params && typeof body.params === "object" ? body.params : {};
157
+ const action = uiAction(o.root, name, params);
158
+ if (!action)
159
+ return json(400, { error: `not an action this page runs: ${name.slice(0, 40)}` });
160
+ // One at a time: a command reads and writes the repository's files.
161
+ const done = busy.then(() => o.runAction(action));
162
+ busy = done.catch(() => undefined);
163
+ const r = await done;
164
+ return json(200, { action: name, exit: r.exit, terminal: `${o.command} ${action.shown.map(quote).join(" ")}`, writes: action.writes, result: r.result, ...(r.result === null ? { output: r.output } : {}) });
165
+ }
166
+ return text(404, "Nothing here.");
167
+ }
168
+ return { handle, address, origin, session };
169
+ }
170
+ const quote = (s) => (/^[A-Za-z0-9_:./=@-]+$/.test(s) ? s : JSON.stringify(s));
171
+ export function escapeHtml(s) {
172
+ return s.replace(/[&<>"']/g, (c) => `&#${c.charCodeAt(0)};`);
173
+ }
174
+ /** Runs one action in this process, as the terminal would with `--json`, and answers its exit code and JSON. */
175
+ export function actionRunner(ctx) {
176
+ return async (a) => {
177
+ let output = "";
178
+ const sink = { write: (s) => ((output += s), true), isTTY: false };
179
+ const exit = await run([...a.argv, "--json"], { root: ctx.root, env: ctx.env, config: ctx.config, fetch: ctx.fetch, invokedAs: ctx.cmd, io: { stdout: sink, stderr: { write: () => true, isTTY: false }, stdin: { isTTY: false } } });
180
+ let result = null;
181
+ try {
182
+ result = JSON.parse(output);
183
+ }
184
+ catch {
185
+ result = null;
186
+ }
187
+ return { exit, result, output: output.slice(0, 64 * 1024) };
188
+ };
189
+ }
190
+ function toUiRequest(req, body) {
191
+ const headers = {};
192
+ for (const [k, v] of Object.entries(req.headers))
193
+ headers[k] = Array.isArray(v) ? v.join(", ") : v;
194
+ return { method: req.method ?? "GET", url: req.url ?? "/", headers, body };
195
+ }
196
+ export async function cmdUi(ctx) {
197
+ const { t } = ctx;
198
+ const wanted = Number(str(ctx.flags.port) ?? 0);
199
+ if (!Number.isInteger(wanted) || wanted < 0 || wanted > 65535)
200
+ throw new Fail("--port takes a port number, or leave it out for a free one.", { code: EXIT.misunderstood });
201
+ const token = randomBytes(24).toString("base64url");
202
+ let handler = null;
203
+ const server = createServer((req, res) => {
204
+ const chunks = [];
205
+ let size = 0;
206
+ req.on("data", (c) => {
207
+ size += c.length;
208
+ if (size <= 64 * 1024)
209
+ chunks.push(c);
210
+ });
211
+ req.on("end", () => {
212
+ if (!handler)
213
+ return res.writeHead(503).end();
214
+ handler
215
+ .handle(toUiRequest(req, Buffer.concat(chunks).toString("utf8")))
216
+ .then((r) => res.writeHead(r.status, r.headers).end(r.body))
217
+ .catch(() => res.writeHead(500, { "content-type": "text/plain" }).end("The command failed."));
218
+ });
219
+ });
220
+ await new Promise((resolve, reject) => {
221
+ server.once("error", (err) => reject(new Fail(`The page could not start: ${err.code === "EADDRINUSE" ? `port ${wanted} is taken` : err.message}.`, { hint: err.code === "EPERM" ? "this sandbox forbids a local port: run it in your own terminal" : undefined })));
222
+ server.listen(wanted, "127.0.0.1", () => resolve());
223
+ });
224
+ const port = server.address().port;
225
+ handler = createUiHandler({ port, token, command: ctx.cmd, root: ctx.root, runAction: actionRunner(ctx) });
226
+ const url = `${handler.origin}/?token=${token}`;
227
+ if (ctx.json)
228
+ emit(ctx, { url, note: "The token works once. The page stops with this process." });
229
+ else {
230
+ t.banner("Local page", [`127.0.0.1:${port}`, "this machine only"]);
231
+ t.out(` ${t.paint.bold("Open")} ${t.link(url, url)}`);
232
+ t.out();
233
+ t.out(` ${t.paint.gray("The address works once: open it in your browser now. The key stays in this process. Ctrl+C stops the page.")}`);
234
+ t.out();
235
+ }
236
+ if (ctx.flags.open) {
237
+ const opener = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
238
+ try {
239
+ spawn(opener[0], opener[1], { detached: true, stdio: "ignore" }).on("error", () => undefined).unref();
240
+ }
241
+ catch {
242
+ // Opening a browser is a courtesy; the address is printed either way.
243
+ }
244
+ }
245
+ await new Promise((resolve) => {
246
+ const stop = () => server.close(() => resolve());
247
+ process.once("SIGINT", stop);
248
+ process.once("SIGTERM", stop);
249
+ });
250
+ }
251
+ //# sourceMappingURL=ui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/cli/ui.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ import type { Problem } from "./types.js";
2
+ /**
3
+ * The Interface API as a Frontend consumes it (components/05-interface-api.md
4
+ * §Conventions): `X-Asturiu-Session` on every call except session exchange,
5
+ * `Idempotency-Key` on writes, `If-Match` for concurrency, cursors for
6
+ * collections, `application/problem+json` for errors — and a `404` that never
7
+ * distinguishes absent from forbidden.
8
+ *
9
+ * Runs wherever `fetch` exists: a Next.js server, an edge runtime, a browser
10
+ * talking to the Web UI's own `/api/v0` proxy.
11
+ */
12
+ export declare class InterfaceApiError extends Error {
13
+ readonly status: number;
14
+ readonly problem: Problem;
15
+ constructor(status: number, problem: Problem);
16
+ get type(): string;
17
+ get isUnauthorized(): boolean;
18
+ get isNotFound(): boolean;
19
+ get isPaused(): boolean;
20
+ get isSuspended(): boolean;
21
+ /** `POST /v0/sessions` for someone with no Customer yet, while the Tenant takes no new ones (ADR-044). */
22
+ get isEnrolmentClosed(): boolean;
23
+ }
24
+ export interface CallOptions {
25
+ body?: unknown;
26
+ /** Raw payload (Attachment upload) — sent as-is with `contentType`. */
27
+ raw?: ArrayBuffer | Uint8Array | Blob;
28
+ contentType?: string;
29
+ headers?: Record<string, string | undefined>;
30
+ query?: Record<string, string | number | boolean | undefined | null>;
31
+ /** Default `true`; `false` for `POST /v0/sessions`, `/v0/status`, `/v0/health`. */
32
+ session?: boolean;
33
+ /** Default: a fresh key per `POST`/`PUT`. Pass a stable key to make a retry a replay. */
34
+ idempotencyKey?: string | false;
35
+ ifMatch?: number | string;
36
+ signal?: AbortSignal;
37
+ }
38
+ export interface Response<T> {
39
+ status: number;
40
+ body: T;
41
+ headers: Headers;
42
+ }
43
+ export interface InterfaceApiClientOptions {
44
+ /** `http://interface-api:8081` server-side, or the Web UI's own origin for the browser. */
45
+ baseUrl: string;
46
+ /** The opaque session identifier, if this client acts for a signed-in Customer. */
47
+ session?: string | null;
48
+ /** Path prefix: `/v0` against the Interface API, `/api/v0` against the Web UI proxy. */
49
+ prefix?: string;
50
+ /**
51
+ * The transport carries the session (the Web UI's `HttpOnly` cookie on its
52
+ * own `/api/v0` proxy): send no header and require no identifier. The
53
+ * browser never holds the session identifier itself.
54
+ */
55
+ ambientSession?: boolean;
56
+ fetch?: typeof fetch;
57
+ timeoutMs?: number;
58
+ }
59
+ export declare class InterfaceApiClient {
60
+ readonly baseUrl: string;
61
+ readonly prefix: string;
62
+ readonly session: string | null;
63
+ readonly ambientSession: boolean;
64
+ private readonly f;
65
+ private readonly timeoutMs;
66
+ constructor(opts: InterfaceApiClientOptions);
67
+ /** The same client acting for another (or no) session. */
68
+ withSession(session: string | null): InterfaceApiClient;
69
+ url(path: string, query?: CallOptions["query"]): string;
70
+ call<T = unknown>(method: string, path: string, opts?: CallOptions): Promise<Response<T>>;
71
+ /** Binary download (Attachment content). */
72
+ download(path: string, opts?: Omit<CallOptions, "body" | "raw">): Promise<{
73
+ status: number;
74
+ bytes: ArrayBuffer;
75
+ contentType: string;
76
+ filename?: string;
77
+ }>;
78
+ get<T = unknown>(path: string, query?: CallOptions["query"], opts?: CallOptions): Promise<T>;
79
+ post<T = unknown>(path: string, body?: unknown, opts?: CallOptions): Promise<T>;
80
+ put<T = unknown>(path: string, body?: unknown, opts?: CallOptions): Promise<T>;
81
+ patch<T = unknown>(path: string, body?: unknown, opts?: CallOptions): Promise<T>;
82
+ delete<T = unknown>(path: string, opts?: CallOptions): Promise<T>;
83
+ /** Walk every page of a cursor-paginated collection. */
84
+ all<T>(path: string, query?: CallOptions["query"], limit?: number): Promise<T[]>;
85
+ }
86
+ /** Every caller-facing error becomes a problem shape, so UIs render one thing. */
87
+ export declare function toProblem(err: unknown): Problem;
88
+ //# sourceMappingURL=client.d.ts.map