@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.
- package/AGENTS.md +255 -0
- package/CHANGELOG.md +15 -0
- package/LICENSE +21 -0
- package/README.md +836 -0
- package/dist/api-fetch.d.ts +16 -0
- package/dist/api-fetch.d.ts.map +1 -0
- package/dist/api-fetch.js +97 -0
- package/dist/api-fetch.js.map +1 -0
- package/dist/api-headers.d.ts +3 -0
- package/dist/api-headers.d.ts.map +1 -0
- package/dist/api-headers.js +25 -0
- package/dist/api-headers.js.map +1 -0
- package/dist/auth-flow.d.ts +23 -0
- package/dist/auth-flow.d.ts.map +1 -0
- package/dist/auth-flow.js +76 -0
- package/dist/auth-flow.js.map +1 -0
- package/dist/client.d.ts +106 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +1278 -0
- package/dist/client.js.map +1 -0
- package/dist/doc-url-sync.d.ts +19 -0
- package/dist/doc-url-sync.d.ts.map +1 -0
- package/dist/doc-url-sync.js +181 -0
- package/dist/doc-url-sync.js.map +1 -0
- package/dist/document-branches.d.ts +32 -0
- package/dist/document-branches.d.ts.map +1 -0
- package/dist/document-branches.js +89 -0
- package/dist/document-branches.js.map +1 -0
- package/dist/document-checkpoints.d.ts +24 -0
- package/dist/document-checkpoints.d.ts.map +1 -0
- package/dist/document-checkpoints.js +115 -0
- package/dist/document-checkpoints.js.map +1 -0
- package/dist/document-commands.d.ts +93 -0
- package/dist/document-commands.d.ts.map +1 -0
- package/dist/document-commands.js +423 -0
- package/dist/document-commands.js.map +1 -0
- package/dist/document-signals.d.ts +53 -0
- package/dist/document-signals.d.ts.map +1 -0
- package/dist/document-signals.js +114 -0
- package/dist/document-signals.js.map +1 -0
- package/dist/document-streams.d.ts +22 -0
- package/dist/document-streams.d.ts.map +1 -0
- package/dist/document-streams.js +98 -0
- package/dist/document-streams.js.map +1 -0
- package/dist/document-thumbnail-capture.d.ts +27 -0
- package/dist/document-thumbnail-capture.d.ts.map +1 -0
- package/dist/document-thumbnail-capture.js +160 -0
- package/dist/document-thumbnail-capture.js.map +1 -0
- package/dist/documents-namespace.d.ts +134 -0
- package/dist/documents-namespace.d.ts.map +1 -0
- package/dist/documents-namespace.js +190 -0
- package/dist/documents-namespace.js.map +1 -0
- package/dist/documents.d.ts +146 -0
- package/dist/documents.d.ts.map +1 -0
- package/dist/documents.js +2045 -0
- package/dist/documents.js.map +1 -0
- package/dist/emitter.d.ts +15 -0
- package/dist/emitter.d.ts.map +1 -0
- package/dist/emitter.js +90 -0
- package/dist/emitter.js.map +1 -0
- package/dist/errors.d.ts +18 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +22 -0
- package/dist/errors.js.map +1 -0
- package/dist/export-guest.d.ts +9 -0
- package/dist/export-guest.d.ts.map +1 -0
- package/dist/export-guest.js +225 -0
- package/dist/export-guest.js.map +1 -0
- package/dist/fetch-retry.d.ts +16 -0
- package/dist/fetch-retry.d.ts.map +1 -0
- package/dist/fetch-retry.js +90 -0
- package/dist/fetch-retry.js.map +1 -0
- package/dist/guest-link.d.ts +3 -0
- package/dist/guest-link.d.ts.map +1 -0
- package/dist/guest-link.js +13 -0
- package/dist/guest-link.js.map +1 -0
- package/dist/handles.d.ts +57 -0
- package/dist/handles.d.ts.map +1 -0
- package/dist/handles.js +1375 -0
- package/dist/handles.js.map +1 -0
- package/dist/hosted-runtime.d.ts +33 -0
- package/dist/hosted-runtime.d.ts.map +1 -0
- package/dist/hosted-runtime.js +99 -0
- package/dist/hosted-runtime.js.map +1 -0
- package/dist/hosted-ui.d.ts +84 -0
- package/dist/hosted-ui.d.ts.map +1 -0
- package/dist/hosted-ui.js +673 -0
- package/dist/hosted-ui.js.map +1 -0
- package/dist/importer.d.ts +22 -0
- package/dist/importer.d.ts.map +1 -0
- package/dist/importer.js +54 -0
- package/dist/importer.js.map +1 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +132 -0
- package/dist/index.js.map +1 -0
- package/dist/init-keys.d.ts +3 -0
- package/dist/init-keys.d.ts.map +1 -0
- package/dist/init-keys.js +13 -0
- package/dist/init-keys.js.map +1 -0
- package/dist/internal.d.ts +6 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +17 -0
- package/dist/internal.js.map +1 -0
- package/dist/jwt.d.ts +3 -0
- package/dist/jwt.d.ts.map +1 -0
- package/dist/jwt.js +22 -0
- package/dist/jwt.js.map +1 -0
- package/dist/launch-context.d.ts +4 -0
- package/dist/launch-context.d.ts.map +1 -0
- package/dist/launch-context.js +44 -0
- package/dist/launch-context.js.map +1 -0
- package/dist/login-hint.d.ts +4 -0
- package/dist/login-hint.d.ts.map +1 -0
- package/dist/login-hint.js +63 -0
- package/dist/login-hint.js.map +1 -0
- package/dist/mutate-batching.d.ts +14 -0
- package/dist/mutate-batching.d.ts.map +1 -0
- package/dist/mutate-batching.js +65 -0
- package/dist/mutate-batching.js.map +1 -0
- package/dist/open-document.d.ts +127 -0
- package/dist/open-document.d.ts.map +1 -0
- package/dist/open-document.js +2121 -0
- package/dist/open-document.js.map +1 -0
- package/dist/page-title.d.ts +3 -0
- package/dist/page-title.d.ts.map +1 -0
- package/dist/page-title.js +32 -0
- package/dist/page-title.js.map +1 -0
- package/dist/perf.d.ts +9 -0
- package/dist/perf.d.ts.map +1 -0
- package/dist/perf.js +39 -0
- package/dist/perf.js.map +1 -0
- package/dist/presence.d.ts +62 -0
- package/dist/presence.d.ts.map +1 -0
- package/dist/presence.js +331 -0
- package/dist/presence.js.map +1 -0
- package/dist/record-paging.d.ts +99 -0
- package/dist/record-paging.d.ts.map +1 -0
- package/dist/record-paging.js +220 -0
- package/dist/record-paging.js.map +1 -0
- package/dist/schema-conflict-dialog.d.ts +10 -0
- package/dist/schema-conflict-dialog.d.ts.map +1 -0
- package/dist/schema-conflict-dialog.js +164 -0
- package/dist/schema-conflict-dialog.js.map +1 -0
- package/dist/selection-persistence.d.ts +5 -0
- package/dist/selection-persistence.d.ts.map +1 -0
- package/dist/selection-persistence.js +90 -0
- package/dist/selection-persistence.js.map +1 -0
- package/dist/serializer.d.ts +3 -0
- package/dist/serializer.d.ts.map +1 -0
- package/dist/serializer.js +2 -0
- package/dist/serializer.js.map +1 -0
- package/dist/session-persistence.d.ts +4 -0
- package/dist/session-persistence.d.ts.map +1 -0
- package/dist/session-persistence.js +68 -0
- package/dist/session-persistence.js.map +1 -0
- package/dist/session-toolbar.d.ts +62 -0
- package/dist/session-toolbar.d.ts.map +1 -0
- package/dist/session-toolbar.js +1205 -0
- package/dist/session-toolbar.js.map +1 -0
- package/dist/session.d.ts +69 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +926 -0
- package/dist/session.js.map +1 -0
- package/dist/tail-ops.d.ts +28 -0
- package/dist/tail-ops.d.ts.map +1 -0
- package/dist/tail-ops.js +46 -0
- package/dist/tail-ops.js.map +1 -0
- package/dist/topic-lifecycle.d.ts +41 -0
- package/dist/topic-lifecycle.d.ts.map +1 -0
- package/dist/topic-lifecycle.js +169 -0
- package/dist/topic-lifecycle.js.map +1 -0
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/undo.d.ts +18 -0
- package/dist/undo.d.ts.map +1 -0
- package/dist/undo.js +110 -0
- package/dist/undo.js.map +1 -0
- package/dist/version-bar.d.ts +22 -0
- package/dist/version-bar.d.ts.map +1 -0
- package/dist/version-bar.js +169 -0
- package/dist/version-bar.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +8 -0
- package/dist/version.js.map +1 -0
- package/dist/vite.d.ts +15 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +36 -0
- package/dist/vite.js.map +1 -0
- package/dist/ws-client.d.ts +53 -0
- package/dist/ws-client.d.ts.map +1 -0
- package/dist/ws-client.js +604 -0
- package/dist/ws-client.js.map +1 -0
- package/dist/ws-frame-limit.d.ts +21 -0
- package/dist/ws-frame-limit.d.ts.map +1 -0
- package/dist/ws-frame-limit.js +40 -0
- package/dist/ws-frame-limit.js.map +1 -0
- package/docs/app-manifest.md +65 -0
- package/docs/custom-chrome.md +147 -0
- package/docs/hosted-ui-advanced.md +77 -0
- package/docs/imported-documents.md +261 -0
- package/docs/presence.md +129 -0
- package/docs/schemas.md +135 -0
- package/docs/streams.md +248 -0
- package/package.json +60 -0
- package/scripts/prepare.mjs +50 -0
- package/src/api-fetch.ts +127 -0
- package/src/api-headers.ts +28 -0
- package/src/auth-flow.ts +125 -0
- package/src/client.ts +1457 -0
- package/src/doc-url-sync.ts +183 -0
- package/src/document-branches.ts +124 -0
- package/src/document-checkpoints.ts +135 -0
- package/src/document-commands.ts +651 -0
- package/src/document-signals.ts +234 -0
- package/src/document-streams.ts +132 -0
- package/src/document-thumbnail-capture.ts +191 -0
- package/src/documents-namespace.ts +516 -0
- package/src/documents.ts +2426 -0
- package/src/emitter.ts +129 -0
- package/src/errors.ts +45 -0
- package/src/export-guest.ts +282 -0
- package/src/fetch-retry.ts +119 -0
- package/src/guest-link.ts +14 -0
- package/src/handles.ts +1731 -0
- package/src/hosted-runtime.ts +109 -0
- package/src/hosted-ui.ts +1020 -0
- package/src/importer.ts +89 -0
- package/src/index.ts +267 -0
- package/src/init-keys.ts +15 -0
- package/src/internal.ts +23 -0
- package/src/jwt.ts +18 -0
- package/src/launch-context.ts +43 -0
- package/src/login-hint.ts +60 -0
- package/src/mutate-batching.ts +63 -0
- package/src/open-document.ts +2869 -0
- package/src/page-title.ts +33 -0
- package/src/perf.ts +46 -0
- package/src/presence.ts +471 -0
- package/src/record-paging.ts +270 -0
- package/src/schema-conflict-dialog.ts +176 -0
- package/src/selection-persistence.ts +98 -0
- package/src/serializer.ts +15 -0
- package/src/session-persistence.ts +69 -0
- package/src/session-toolbar.ts +1457 -0
- package/src/session.ts +1262 -0
- package/src/tail-ops.ts +63 -0
- package/src/topic-lifecycle.ts +217 -0
- package/src/types.ts +75 -0
- package/src/undo.ts +125 -0
- package/src/version-bar.ts +221 -0
- package/src/version.ts +8 -0
- package/src/vite.ts +49 -0
- package/src/ws-client.ts +678 -0
- 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.
|