@brass-build/client 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 (258) hide show
  1. package/AGENTS.md +255 -0
  2. package/CHANGELOG.md +15 -0
  3. package/LICENSE +21 -0
  4. package/README.md +836 -0
  5. package/dist/api-fetch.d.ts +16 -0
  6. package/dist/api-fetch.d.ts.map +1 -0
  7. package/dist/api-fetch.js +97 -0
  8. package/dist/api-fetch.js.map +1 -0
  9. package/dist/api-headers.d.ts +3 -0
  10. package/dist/api-headers.d.ts.map +1 -0
  11. package/dist/api-headers.js +25 -0
  12. package/dist/api-headers.js.map +1 -0
  13. package/dist/auth-flow.d.ts +23 -0
  14. package/dist/auth-flow.d.ts.map +1 -0
  15. package/dist/auth-flow.js +76 -0
  16. package/dist/auth-flow.js.map +1 -0
  17. package/dist/client.d.ts +106 -0
  18. package/dist/client.d.ts.map +1 -0
  19. package/dist/client.js +1278 -0
  20. package/dist/client.js.map +1 -0
  21. package/dist/doc-url-sync.d.ts +19 -0
  22. package/dist/doc-url-sync.d.ts.map +1 -0
  23. package/dist/doc-url-sync.js +181 -0
  24. package/dist/doc-url-sync.js.map +1 -0
  25. package/dist/document-branches.d.ts +32 -0
  26. package/dist/document-branches.d.ts.map +1 -0
  27. package/dist/document-branches.js +89 -0
  28. package/dist/document-branches.js.map +1 -0
  29. package/dist/document-checkpoints.d.ts +24 -0
  30. package/dist/document-checkpoints.d.ts.map +1 -0
  31. package/dist/document-checkpoints.js +115 -0
  32. package/dist/document-checkpoints.js.map +1 -0
  33. package/dist/document-commands.d.ts +93 -0
  34. package/dist/document-commands.d.ts.map +1 -0
  35. package/dist/document-commands.js +423 -0
  36. package/dist/document-commands.js.map +1 -0
  37. package/dist/document-signals.d.ts +53 -0
  38. package/dist/document-signals.d.ts.map +1 -0
  39. package/dist/document-signals.js +114 -0
  40. package/dist/document-signals.js.map +1 -0
  41. package/dist/document-streams.d.ts +22 -0
  42. package/dist/document-streams.d.ts.map +1 -0
  43. package/dist/document-streams.js +98 -0
  44. package/dist/document-streams.js.map +1 -0
  45. package/dist/document-thumbnail-capture.d.ts +27 -0
  46. package/dist/document-thumbnail-capture.d.ts.map +1 -0
  47. package/dist/document-thumbnail-capture.js +160 -0
  48. package/dist/document-thumbnail-capture.js.map +1 -0
  49. package/dist/documents-namespace.d.ts +134 -0
  50. package/dist/documents-namespace.d.ts.map +1 -0
  51. package/dist/documents-namespace.js +190 -0
  52. package/dist/documents-namespace.js.map +1 -0
  53. package/dist/documents.d.ts +146 -0
  54. package/dist/documents.d.ts.map +1 -0
  55. package/dist/documents.js +2045 -0
  56. package/dist/documents.js.map +1 -0
  57. package/dist/emitter.d.ts +15 -0
  58. package/dist/emitter.d.ts.map +1 -0
  59. package/dist/emitter.js +90 -0
  60. package/dist/emitter.js.map +1 -0
  61. package/dist/errors.d.ts +18 -0
  62. package/dist/errors.d.ts.map +1 -0
  63. package/dist/errors.js +22 -0
  64. package/dist/errors.js.map +1 -0
  65. package/dist/export-guest.d.ts +9 -0
  66. package/dist/export-guest.d.ts.map +1 -0
  67. package/dist/export-guest.js +225 -0
  68. package/dist/export-guest.js.map +1 -0
  69. package/dist/fetch-retry.d.ts +16 -0
  70. package/dist/fetch-retry.d.ts.map +1 -0
  71. package/dist/fetch-retry.js +90 -0
  72. package/dist/fetch-retry.js.map +1 -0
  73. package/dist/guest-link.d.ts +3 -0
  74. package/dist/guest-link.d.ts.map +1 -0
  75. package/dist/guest-link.js +13 -0
  76. package/dist/guest-link.js.map +1 -0
  77. package/dist/handles.d.ts +57 -0
  78. package/dist/handles.d.ts.map +1 -0
  79. package/dist/handles.js +1375 -0
  80. package/dist/handles.js.map +1 -0
  81. package/dist/hosted-runtime.d.ts +33 -0
  82. package/dist/hosted-runtime.d.ts.map +1 -0
  83. package/dist/hosted-runtime.js +99 -0
  84. package/dist/hosted-runtime.js.map +1 -0
  85. package/dist/hosted-ui.d.ts +84 -0
  86. package/dist/hosted-ui.d.ts.map +1 -0
  87. package/dist/hosted-ui.js +673 -0
  88. package/dist/hosted-ui.js.map +1 -0
  89. package/dist/importer.d.ts +22 -0
  90. package/dist/importer.d.ts.map +1 -0
  91. package/dist/importer.js +54 -0
  92. package/dist/importer.js.map +1 -0
  93. package/dist/index.d.ts +54 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +132 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/init-keys.d.ts +3 -0
  98. package/dist/init-keys.d.ts.map +1 -0
  99. package/dist/init-keys.js +13 -0
  100. package/dist/init-keys.js.map +1 -0
  101. package/dist/internal.d.ts +6 -0
  102. package/dist/internal.d.ts.map +1 -0
  103. package/dist/internal.js +17 -0
  104. package/dist/internal.js.map +1 -0
  105. package/dist/jwt.d.ts +3 -0
  106. package/dist/jwt.d.ts.map +1 -0
  107. package/dist/jwt.js +22 -0
  108. package/dist/jwt.js.map +1 -0
  109. package/dist/launch-context.d.ts +4 -0
  110. package/dist/launch-context.d.ts.map +1 -0
  111. package/dist/launch-context.js +44 -0
  112. package/dist/launch-context.js.map +1 -0
  113. package/dist/login-hint.d.ts +4 -0
  114. package/dist/login-hint.d.ts.map +1 -0
  115. package/dist/login-hint.js +63 -0
  116. package/dist/login-hint.js.map +1 -0
  117. package/dist/mutate-batching.d.ts +14 -0
  118. package/dist/mutate-batching.d.ts.map +1 -0
  119. package/dist/mutate-batching.js +65 -0
  120. package/dist/mutate-batching.js.map +1 -0
  121. package/dist/open-document.d.ts +127 -0
  122. package/dist/open-document.d.ts.map +1 -0
  123. package/dist/open-document.js +2121 -0
  124. package/dist/open-document.js.map +1 -0
  125. package/dist/page-title.d.ts +3 -0
  126. package/dist/page-title.d.ts.map +1 -0
  127. package/dist/page-title.js +32 -0
  128. package/dist/page-title.js.map +1 -0
  129. package/dist/perf.d.ts +9 -0
  130. package/dist/perf.d.ts.map +1 -0
  131. package/dist/perf.js +39 -0
  132. package/dist/perf.js.map +1 -0
  133. package/dist/presence.d.ts +62 -0
  134. package/dist/presence.d.ts.map +1 -0
  135. package/dist/presence.js +331 -0
  136. package/dist/presence.js.map +1 -0
  137. package/dist/record-paging.d.ts +99 -0
  138. package/dist/record-paging.d.ts.map +1 -0
  139. package/dist/record-paging.js +220 -0
  140. package/dist/record-paging.js.map +1 -0
  141. package/dist/schema-conflict-dialog.d.ts +10 -0
  142. package/dist/schema-conflict-dialog.d.ts.map +1 -0
  143. package/dist/schema-conflict-dialog.js +164 -0
  144. package/dist/schema-conflict-dialog.js.map +1 -0
  145. package/dist/selection-persistence.d.ts +5 -0
  146. package/dist/selection-persistence.d.ts.map +1 -0
  147. package/dist/selection-persistence.js +90 -0
  148. package/dist/selection-persistence.js.map +1 -0
  149. package/dist/serializer.d.ts +3 -0
  150. package/dist/serializer.d.ts.map +1 -0
  151. package/dist/serializer.js +2 -0
  152. package/dist/serializer.js.map +1 -0
  153. package/dist/session-persistence.d.ts +4 -0
  154. package/dist/session-persistence.d.ts.map +1 -0
  155. package/dist/session-persistence.js +68 -0
  156. package/dist/session-persistence.js.map +1 -0
  157. package/dist/session-toolbar.d.ts +62 -0
  158. package/dist/session-toolbar.d.ts.map +1 -0
  159. package/dist/session-toolbar.js +1205 -0
  160. package/dist/session-toolbar.js.map +1 -0
  161. package/dist/session.d.ts +69 -0
  162. package/dist/session.d.ts.map +1 -0
  163. package/dist/session.js +926 -0
  164. package/dist/session.js.map +1 -0
  165. package/dist/tail-ops.d.ts +28 -0
  166. package/dist/tail-ops.d.ts.map +1 -0
  167. package/dist/tail-ops.js +46 -0
  168. package/dist/tail-ops.js.map +1 -0
  169. package/dist/topic-lifecycle.d.ts +41 -0
  170. package/dist/topic-lifecycle.d.ts.map +1 -0
  171. package/dist/topic-lifecycle.js +169 -0
  172. package/dist/topic-lifecycle.js.map +1 -0
  173. package/dist/types.d.ts +22 -0
  174. package/dist/types.d.ts.map +1 -0
  175. package/dist/types.js +2 -0
  176. package/dist/types.js.map +1 -0
  177. package/dist/undo.d.ts +18 -0
  178. package/dist/undo.d.ts.map +1 -0
  179. package/dist/undo.js +110 -0
  180. package/dist/undo.js.map +1 -0
  181. package/dist/version-bar.d.ts +22 -0
  182. package/dist/version-bar.d.ts.map +1 -0
  183. package/dist/version-bar.js +169 -0
  184. package/dist/version-bar.js.map +1 -0
  185. package/dist/version.d.ts +3 -0
  186. package/dist/version.d.ts.map +1 -0
  187. package/dist/version.js +8 -0
  188. package/dist/version.js.map +1 -0
  189. package/dist/vite.d.ts +15 -0
  190. package/dist/vite.d.ts.map +1 -0
  191. package/dist/vite.js +36 -0
  192. package/dist/vite.js.map +1 -0
  193. package/dist/ws-client.d.ts +53 -0
  194. package/dist/ws-client.d.ts.map +1 -0
  195. package/dist/ws-client.js +604 -0
  196. package/dist/ws-client.js.map +1 -0
  197. package/dist/ws-frame-limit.d.ts +21 -0
  198. package/dist/ws-frame-limit.d.ts.map +1 -0
  199. package/dist/ws-frame-limit.js +40 -0
  200. package/dist/ws-frame-limit.js.map +1 -0
  201. package/docs/app-manifest.md +65 -0
  202. package/docs/custom-chrome.md +147 -0
  203. package/docs/hosted-ui-advanced.md +77 -0
  204. package/docs/imported-documents.md +261 -0
  205. package/docs/presence.md +129 -0
  206. package/docs/schemas.md +135 -0
  207. package/docs/streams.md +248 -0
  208. package/package.json +60 -0
  209. package/scripts/prepare.mjs +50 -0
  210. package/src/api-fetch.ts +127 -0
  211. package/src/api-headers.ts +28 -0
  212. package/src/auth-flow.ts +125 -0
  213. package/src/client.ts +1457 -0
  214. package/src/doc-url-sync.ts +183 -0
  215. package/src/document-branches.ts +124 -0
  216. package/src/document-checkpoints.ts +135 -0
  217. package/src/document-commands.ts +651 -0
  218. package/src/document-signals.ts +234 -0
  219. package/src/document-streams.ts +132 -0
  220. package/src/document-thumbnail-capture.ts +191 -0
  221. package/src/documents-namespace.ts +516 -0
  222. package/src/documents.ts +2426 -0
  223. package/src/emitter.ts +129 -0
  224. package/src/errors.ts +45 -0
  225. package/src/export-guest.ts +282 -0
  226. package/src/fetch-retry.ts +119 -0
  227. package/src/guest-link.ts +14 -0
  228. package/src/handles.ts +1731 -0
  229. package/src/hosted-runtime.ts +109 -0
  230. package/src/hosted-ui.ts +1020 -0
  231. package/src/importer.ts +89 -0
  232. package/src/index.ts +267 -0
  233. package/src/init-keys.ts +15 -0
  234. package/src/internal.ts +23 -0
  235. package/src/jwt.ts +18 -0
  236. package/src/launch-context.ts +43 -0
  237. package/src/login-hint.ts +60 -0
  238. package/src/mutate-batching.ts +63 -0
  239. package/src/open-document.ts +2869 -0
  240. package/src/page-title.ts +33 -0
  241. package/src/perf.ts +46 -0
  242. package/src/presence.ts +471 -0
  243. package/src/record-paging.ts +270 -0
  244. package/src/schema-conflict-dialog.ts +176 -0
  245. package/src/selection-persistence.ts +98 -0
  246. package/src/serializer.ts +15 -0
  247. package/src/session-persistence.ts +69 -0
  248. package/src/session-toolbar.ts +1457 -0
  249. package/src/session.ts +1262 -0
  250. package/src/tail-ops.ts +63 -0
  251. package/src/topic-lifecycle.ts +217 -0
  252. package/src/types.ts +75 -0
  253. package/src/undo.ts +125 -0
  254. package/src/version-bar.ts +221 -0
  255. package/src/version.ts +8 -0
  256. package/src/vite.ts +49 -0
  257. package/src/ws-client.ts +678 -0
  258. package/src/ws-frame-limit.ts +52 -0
package/AGENTS.md ADDED
@@ -0,0 +1,255 @@
1
+ # Instructions for AI coding agents
2
+
3
+ You are likely an AI coding agent building an app on
4
+ `@brass-build/client`. The [README](./README.md) teaches the API;
5
+ this file is addressed to you specifically and carries two things the
6
+ README does not: how to verify your work, and the UX baseline a
7
+ generated app is expected to meet. Apply both.
8
+
9
+ ## Find out where the app's data comes from
10
+
11
+ **The request names a format, a corpus, or an export.** Our IFC models,
12
+ the GPX tracks off my watch, the change orders our subs email us. Ask
13
+ for one real example as your first action, before you design anything.
14
+ That file decides your record shape, and an app built ahead of it
15
+ guesses at a shape the real files contradict.
16
+
17
+ **The work has a customary shape in the user's trade.** A punch list, a
18
+ timesheet, an RFI, a site diary: people in that line of work pass these
19
+ around as documents whose fields they all expect, so a shape for it
20
+ exists and the user probably holds a copy. Ask for theirs before you
21
+ design a schema. A schema you invent for a shape that already exists
22
+ forks it: the picker routes documents to apps by their declared schema,
23
+ so each app's documents stop opening in the other, and the split
24
+ stands. Ask the user rather than looking, because a shape reaches you
25
+ through a document that already carries it.
26
+
27
+ Ask as well whenever the user brings up another application. What that
28
+ product can hand over decides whether you adopt a shape or integrate,
29
+ and only the user knows.
30
+
31
+ A product you assumed rather than one they named is the other way
32
+ round. Data a product holds reaches you through its API rather than as
33
+ a document, so a sprint board, a sales pipeline, or a ticket queue you
34
+ guess lives in some tool leaves you no shape to adopt. Build it as
35
+ below until the user names the tool.
36
+
37
+ **The data starts in your app.** A canvas, a poll, a garden planner, a
38
+ personal collection of notes or recipes: the document means something
39
+ only inside your app, and whatever you design becomes its shape.
40
+ Design the records from the request, declare their schema in
41
+ `brass-app.json`, and build. Asking for a file here stalls a task that
42
+ has none behind it, and it reads to the user as though their request
43
+ was incomplete.
44
+
45
+ Either question runs alongside the work that does not depend on the
46
+ answer, rather than idling: drive the sign-in, fetch the organization's
47
+ instructions (next section), and scaffold the app shell while the user
48
+ answers.
49
+
50
+ With an example in hand: the user adds it at their Brass dashboard
51
+ (`https://app.brass.build`) and sends you back the document's link,
52
+ and you read what that document holds. A resolved schema is your
53
+ record contract: pull it and adopt it verbatim
54
+ (`npx @brass-build/cli schema pull --doc <docId>`). A stored file with
55
+ no schema means your app is its first importer: register your parse
56
+ half with `Brass.registerImporter`, and declare the schema of the
57
+ records you write in `brass-app.json` so the next app can adopt it.
58
+ In your app, the file opens the way every document opens: through the
59
+ session and the hosted picker (the picker also brings a file into
60
+ Brass).
61
+
62
+ Adopt a pulled schema verbatim, keywords included. A schema describes
63
+ the data, so an `x-brass-` keyword in it belongs to the file you pulled
64
+ it from, and dropping the keyword declares a different contract.
65
+
66
+ `brass publish` prints warnings on stderr and repeats them in
67
+ `warnings` in its `--json` result. Read them and act on what they name,
68
+ then publish again and expect a clean result. Tell the user what you
69
+ changed and why.
70
+
71
+ ## Fetch the organization's coding instructions
72
+
73
+ Before you write any code (and while the user finds their
74
+ example file), run this and follow what it prints:
75
+
76
+ ```sh
77
+ npx @brass-build/cli agents pull --stdout
78
+ ```
79
+
80
+ It prints the organization's own conventions for apps built on Brass
81
+ (its `AGENTS.md` / `CLAUDE.md`) to stdout. Read them inline and treat
82
+ them as an instruction file for this task; they take precedence over
83
+ the generic defaults here. Run it rather than deciding up front whether
84
+ the org has any: if it has set none the command prints nothing and you
85
+ proceed with the defaults below, but that is something you learn by
86
+ running it, not by assuming it, so this is a step you take, not a box
87
+ you skip. The pull needs a signed-in session, so if `brass agents pull`
88
+ reports no credential, run the sign-in yourself first (`brass login
89
+ --start`, relay the printed URL and code to the human, then `brass
90
+ login --check` until it reports approved), and it is the same
91
+ credential you will use to publish (see "Ship the app"), so drive that
92
+ sign-in now rather than skipping the fetch. `brass agents pull` is detailed in the
93
+ `@brass-build/cli` package's `AGENTS.md`.
94
+
95
+ ## Have a second agent review your work
96
+
97
+ Brass documents are persistent and shared: a write that compiles and
98
+ looks right on screen can still be subtly wrong in the stored
99
+ document, and once saved it syncs to every collaborator and reopens
100
+ later. You share the blind spot that produced any such bug, so
101
+ reviewing your own work tends to reconfirm it. Build with a review
102
+ loop instead of treating one as optional polish.
103
+
104
+ Once the integration builds, have a **separate** agent (not you)
105
+ adversarially review it and drive it in a real browser against the
106
+ live backend. Hold that reviewer to implementation-independent checks:
107
+
108
+ - It should read the document back through the handles
109
+ (`doc.map(...).read()` / `doc.list(...).read()`) and validate the
110
+ result against the data spec itself, rather than trusting the app's
111
+ own helpers.
112
+ - It should push the negative, zero, and boundary inputs of every
113
+ operation.
114
+ - It should confirm each edit round-trips and leaves the document
115
+ consistent.
116
+
117
+ Driving it on a touch device, not just a desktop mouse, tends to be
118
+ where the surprising bugs are: interactive gestures (drags,
119
+ multi-point taps, anything pointer-driven) commonly work under a mouse
120
+ but break under touch, and layout looking fine at a narrow width says
121
+ nothing about whether the gesture still functions there. Worth a pass
122
+ on real touch when the app has any.
123
+
124
+ Fix what the reviewer finds and iterate until the reviewer's own
125
+ checks pass. A single build pass routinely ships writes that are wrong
126
+ but plausible; this loop is what catches them, and it is worth a round
127
+ before you call an integration done.
128
+
129
+ ## Apply these UX defaults
130
+
131
+ When the prompt you were given is silent on UX, default to the
132
+ following. A real design in the prompt overrides any of them; this is
133
+ the baseline for when there is no design.
134
+
135
+ - **Build an app, not a website.** The working surface fills the
136
+ viewport; do not center the app in a `max-width: 720px` column.
137
+ - **Render two distinct shells, signed-out and signed-in.** A
138
+ signed-in shell with disabled buttons next to a sign-in CTA reads as
139
+ broken. Mount the signed-in shell after `onUserChange` fires with a
140
+ non-null user, and render **neither** shell during the bootstrap
141
+ window before that first fire (see "Rendering auth state" in the
142
+ README).
143
+ - **Put auth chrome in the header of the signed-in shell only**: the
144
+ user's email or sub, plus sign out. The sign-in CTA belongs in the
145
+ body of the signed-out shell, not in a pre-rendered header.
146
+ - **Include the viewport meta tag**:
147
+ `<meta name="viewport" content="width=device-width, initial-scale=1">`.
148
+ - **If you toggle shells with `el.hidden`, add
149
+ `[hidden] { display: none !important }` to your CSS.** The built-in
150
+ `[hidden]` rule has the lowest possible specificity, so a `display:`
151
+ rule you set on the same element (`display: flex` on a signed-in
152
+ shell) outranks it and `el.hidden = true` silently stops hiding
153
+ anything. A class toggle sidesteps it; the plain-DOM shell pattern is
154
+ where it bites.
155
+ - **Make touch targets at least 40px**: `padding: 12px 16px` on
156
+ tappable controls.
157
+ - **Disable, don't hide, on read-only documents.** When
158
+ `doc.readOnly` is true (a viewer-role grant, or a historical-version
159
+ preview), render the editor and share controls disabled with a
160
+ `title` explaining why, rather than removing them. `doc.readOnly` is
161
+ the public signal; gate on it, not on a role field.
162
+ - **Name the next action in empty states.** "No document open. Use
163
+ Open to pick or create one."
164
+ - **Gate edit affordances on an open document.** When
165
+ `session.status` is `empty` or `signed-out`, render the empty or
166
+ sign-in state in place of the editor, not over it. A canvas or tool
167
+ palette that responds to input before a document is open lets the
168
+ user produce work that silently cannot be persisted and is discarded
169
+ when the first document opens.
170
+ - **Render the `error` status.** When `session.status` is `error` (a
171
+ document the user opened could not be opened: deleted, or an access
172
+ the platform collapses to a non-disclosing 404; or a document that was
173
+ open being deleted out from under the user), render
174
+ `session.error.message` verbatim, surrounded by your own New / Open
175
+ actions, not the plain empty state. Falling through to "No document
176
+ open" reads as if the user asked for nothing and hides the failure.
177
+ Render the platform's message rather than writing your own (same as
178
+ `session.loadingMessage`): it stays one deliberately non-disclosing
179
+ string for both "deleted" and "no access", so never word them
180
+ differently and never let the wording hint which occurred.
181
+ - **Prefer `Brass.mountToolbar` for the document menu.** If the shell
182
+ is fully custom, render `session.commands` in one `<menu>` anchored
183
+ to a `<details>`/`<summary>` disclosure widget with the active doc's
184
+ name and a caret as the trigger, and style the `<summary>` with a
185
+ resting button-like affordance so it reads as clickable rather than
186
+ as a heading.
187
+ - **Wire presence by default, and wire both halves.** When
188
+ `doc.presence` is non-null (any open writable doc), publish your own
189
+ pointer / camera / selection state on every move AND render other
190
+ participants' state in the working surface, not just an initials
191
+ list in the header (the README's "Presence" section explains why
192
+ wiring only one half is the common mistake). Skip presence entirely
193
+ only if the prompt explicitly says single-user.
194
+ - **Follow the copy style.** Sentence case for headings. No em
195
+ dashes, no exclamation marks, and no "please" or "sorry" in errors:
196
+ "Document not found." not "Sorry, we couldn't find that document!"
197
+ Use "sign in" / "sign out", not "log in" / "log out".
198
+
199
+ ## Ship the app
200
+
201
+ A build that compiles is not a finished integration. It is finished
202
+ when a user can sign in and, if the task calls for a deployed app, open
203
+ it at a real URL. Drive it there rather than stopping at "it builds".
204
+
205
+ Run `brass status` first, and act on what it prints:
206
+
207
+ ```sh
208
+ npx @brass-build/cli status
209
+ ```
210
+
211
+ It inspects the credential and app state for this environment and ends
212
+ in a `Next:` line naming the one command to run. Follow that line, then
213
+ run `brass status` again. It is the control surface for the rest of this
214
+ section: rather than reasoning about publishing from prose, you run it
215
+ and do what it says.
216
+
217
+ Two steps need the human's Brass account, and you cannot stand in for
218
+ it. Both are steps you drive to completion, not blockers you note and
219
+ stop at:
220
+
221
+ - **Getting an app id.** `Brass.init` needs the `app_id` of a
222
+ registered app. Run the first `brass publish` (below): it creates the
223
+ app and writes its id to `.brass/project.json`, which you read back
224
+ into `Brass.init('brass_app_...')`. A new app already allows sign-in
225
+ from `localhost`, so once you have the id, `Brass.signIn()` works in
226
+ local development with no further setup. (Or the human creates the app
227
+ on the dashboard and gives you the id.)
228
+ - **A publish credential.** When `brass status` reports no credential,
229
+ drive the sign-in: run `brass login`. In a local session it opens the
230
+ human's browser to approve and completes on approval; on a headless
231
+ box it prints a URL and short code the human approves from any device.
232
+ Running it and getting the human through approval is your step. For CI
233
+ the human supplies `BRASS_SERVICE_TOKEN` instead. You cannot mint
234
+ either, but neither is a wall you stop at.
235
+
236
+ Once `brass status` reports a credential, publish:
237
+
238
+ ```sh
239
+ npm run build
240
+ npx @brass-build/cli publish ./dist
241
+ ```
242
+
243
+ This deploys to `https://<slug>.onbrass.app`. Report the integration
244
+ against this end state, and close out every item before you call it
245
+ done:
246
+
247
+ - **built**: `npm run build` is clean.
248
+ - **signed in**: `brass status` confirms a credential.
249
+ - **published**: `brass publish` reported a URL.
250
+ - **opened**: you loaded that URL and confirmed sign-in works there.
251
+
252
+ An open item is the next thing to offer. When publishing is waiting only
253
+ on the human's sign-in, say so and offer to walk them through
254
+ `brass login` now, rather than leaving it as a note and stopping. The
255
+ short path for you is `AGENTS.md` in the `@brass-build/cli` package.
package/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@brass-build/client` are recorded here. The
4
+ format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
+ and the package follows [semantic versioning](https://semver.org/spec/v2.0.0.html).
6
+ While the version is below `1.0.0`, minor releases may introduce
7
+ breaking changes.
8
+
9
+ ## 0.1.0
10
+
11
+ Initial public release. The SDK turns a document into a live,
12
+ multi-user, persistent workspace: sign-in, the hosted file toolbar, and
13
+ a subscribe-render-mutate loop per open document. Ships as an ESM-only
14
+ package with a `./vite` subpath that configures the WASM runtime's
15
+ bundler needs.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Brass Software LLC
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.