@brass-build/client 0.4.0 → 0.5.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 (327) hide show
  1. package/AGENTS.md +142 -41
  2. package/CHANGELOG.md +93 -4
  3. package/README.md +666 -179
  4. package/dist/acting-organization.d.ts.map +1 -1
  5. package/dist/acting-organization.js +6 -11
  6. package/dist/acting-organization.js.map +1 -1
  7. package/dist/api-fetch.d.ts +8 -0
  8. package/dist/api-fetch.d.ts.map +1 -1
  9. package/dist/api-fetch.js +35 -8
  10. package/dist/api-fetch.js.map +1 -1
  11. package/dist/batched-get.d.ts +11 -0
  12. package/dist/batched-get.d.ts.map +1 -0
  13. package/dist/batched-get.js +92 -0
  14. package/dist/batched-get.js.map +1 -0
  15. package/dist/call-service.d.ts +4 -0
  16. package/dist/call-service.d.ts.map +1 -1
  17. package/dist/call-service.js +66 -3
  18. package/dist/call-service.js.map +1 -1
  19. package/dist/client.d.ts +51 -2
  20. package/dist/client.d.ts.map +1 -1
  21. package/dist/client.js +982 -124
  22. package/dist/client.js.map +1 -1
  23. package/dist/document-checkpoints.d.ts +25 -2
  24. package/dist/document-checkpoints.d.ts.map +1 -1
  25. package/dist/document-checkpoints.js +258 -61
  26. package/dist/document-checkpoints.js.map +1 -1
  27. package/dist/document-commands.d.ts.map +1 -1
  28. package/dist/document-commands.js +5 -3
  29. package/dist/document-commands.js.map +1 -1
  30. package/dist/document-contents.d.ts +10 -0
  31. package/dist/document-contents.d.ts.map +1 -1
  32. package/dist/document-contents.js +23 -1
  33. package/dist/document-contents.js.map +1 -1
  34. package/dist/document-set-subscription.d.ts +56 -0
  35. package/dist/document-set-subscription.d.ts.map +1 -0
  36. package/dist/document-set-subscription.js +240 -0
  37. package/dist/document-set-subscription.js.map +1 -0
  38. package/dist/document-signals.d.ts +6 -0
  39. package/dist/document-signals.d.ts.map +1 -1
  40. package/dist/document-signals.js +31 -1
  41. package/dist/document-signals.js.map +1 -1
  42. package/dist/document-streams.d.ts +36 -2
  43. package/dist/document-streams.d.ts.map +1 -1
  44. package/dist/document-streams.js +69 -18
  45. package/dist/document-streams.js.map +1 -1
  46. package/dist/document-thumbnail-capture.d.ts +12 -2
  47. package/dist/document-thumbnail-capture.d.ts.map +1 -1
  48. package/dist/document-thumbnail-capture.js +103 -27
  49. package/dist/document-thumbnail-capture.js.map +1 -1
  50. package/dist/documents-namespace.d.ts +92 -10
  51. package/dist/documents-namespace.d.ts.map +1 -1
  52. package/dist/documents-namespace.js +285 -39
  53. package/dist/documents-namespace.js.map +1 -1
  54. package/dist/documents.d.ts +173 -8
  55. package/dist/documents.d.ts.map +1 -1
  56. package/dist/documents.js +1778 -310
  57. package/dist/documents.js.map +1 -1
  58. package/dist/errors.d.ts +3 -3
  59. package/dist/errors.d.ts.map +1 -1
  60. package/dist/errors.js.map +1 -1
  61. package/dist/fetch-retry.d.ts +1 -0
  62. package/dist/fetch-retry.d.ts.map +1 -1
  63. package/dist/fetch-retry.js +2 -0
  64. package/dist/fetch-retry.js.map +1 -1
  65. package/dist/file-choice.d.ts +2 -0
  66. package/dist/file-choice.d.ts.map +1 -0
  67. package/dist/file-choice.js +27 -0
  68. package/dist/file-choice.js.map +1 -0
  69. package/dist/guest-link.d.ts +18 -1
  70. package/dist/guest-link.d.ts.map +1 -1
  71. package/dist/guest-link.js +329 -1
  72. package/dist/guest-link.js.map +1 -1
  73. package/dist/handle-types.d.ts +67 -5
  74. package/dist/handle-types.d.ts.map +1 -1
  75. package/dist/handles.d.ts +15 -19
  76. package/dist/handles.d.ts.map +1 -1
  77. package/dist/handles.js +231 -76
  78. package/dist/handles.js.map +1 -1
  79. package/dist/hosted-ui.d.ts +61 -0
  80. package/dist/hosted-ui.d.ts.map +1 -1
  81. package/dist/hosted-ui.js +94 -42
  82. package/dist/hosted-ui.js.map +1 -1
  83. package/dist/import-contract.d.ts +74 -0
  84. package/dist/import-contract.d.ts.map +1 -0
  85. package/dist/import-contract.js +163 -0
  86. package/dist/import-contract.js.map +1 -0
  87. package/dist/import-guest.d.ts +9 -0
  88. package/dist/import-guest.d.ts.map +1 -0
  89. package/dist/import-guest.js +155 -0
  90. package/dist/import-guest.js.map +1 -0
  91. package/dist/import-report.d.ts +17 -0
  92. package/dist/import-report.d.ts.map +1 -0
  93. package/dist/import-report.js +7 -0
  94. package/dist/import-report.js.map +1 -0
  95. package/dist/importer-wait.d.ts +2 -0
  96. package/dist/importer-wait.d.ts.map +1 -0
  97. package/dist/importer-wait.js +5 -0
  98. package/dist/importer-wait.js.map +1 -0
  99. package/dist/importer.d.ts +18 -4
  100. package/dist/importer.d.ts.map +1 -1
  101. package/dist/importer.js +322 -105
  102. package/dist/importer.js.map +1 -1
  103. package/dist/in-development.d.ts +2 -0
  104. package/dist/in-development.d.ts.map +1 -0
  105. package/dist/in-development.js +10 -0
  106. package/dist/in-development.js.map +1 -0
  107. package/dist/index.d.ts +16 -8
  108. package/dist/index.d.ts.map +1 -1
  109. package/dist/index.js +24 -8
  110. package/dist/index.js.map +1 -1
  111. package/dist/init-keys.d.ts +1 -1
  112. package/dist/init-keys.d.ts.map +1 -1
  113. package/dist/init-keys.js +6 -1
  114. package/dist/init-keys.js.map +1 -1
  115. package/dist/input-documents.d.ts +67 -0
  116. package/dist/input-documents.d.ts.map +1 -0
  117. package/dist/input-documents.js +693 -0
  118. package/dist/input-documents.js.map +1 -0
  119. package/dist/inputs-status.d.ts +80 -0
  120. package/dist/inputs-status.d.ts.map +1 -0
  121. package/dist/inputs-status.js +460 -0
  122. package/dist/inputs-status.js.map +1 -0
  123. package/dist/inputs.d.ts +2 -0
  124. package/dist/inputs.d.ts.map +1 -0
  125. package/dist/inputs.js +793 -0
  126. package/dist/inputs.js.map +1 -0
  127. package/dist/internal.d.ts +6 -1
  128. package/dist/internal.d.ts.map +1 -1
  129. package/dist/internal.js +4 -1
  130. package/dist/internal.js.map +1 -1
  131. package/dist/join-content.d.ts +33 -0
  132. package/dist/join-content.d.ts.map +1 -0
  133. package/dist/join-content.js +114 -0
  134. package/dist/join-content.js.map +1 -0
  135. package/dist/join-stamp.d.ts +3 -0
  136. package/dist/join-stamp.d.ts.map +1 -0
  137. package/dist/join-stamp.js +12 -0
  138. package/dist/join-stamp.js.map +1 -0
  139. package/dist/manifest-drift.d.ts +9 -0
  140. package/dist/manifest-drift.d.ts.map +1 -0
  141. package/dist/manifest-drift.js +46 -0
  142. package/dist/manifest-drift.js.map +1 -0
  143. package/dist/open-document.d.ts +109 -2
  144. package/dist/open-document.d.ts.map +1 -1
  145. package/dist/open-document.js +1822 -811
  146. package/dist/open-document.js.map +1 -1
  147. package/dist/page-restore.d.ts +12 -0
  148. package/dist/page-restore.d.ts.map +1 -0
  149. package/dist/page-restore.js +23 -0
  150. package/dist/page-restore.js.map +1 -0
  151. package/dist/placement.d.ts +13 -0
  152. package/dist/placement.d.ts.map +1 -0
  153. package/dist/placement.js +34 -0
  154. package/dist/placement.js.map +1 -0
  155. package/dist/presence.d.ts +1 -0
  156. package/dist/presence.d.ts.map +1 -1
  157. package/dist/presence.js +16 -4
  158. package/dist/presence.js.map +1 -1
  159. package/dist/read-only-document.d.ts +87 -0
  160. package/dist/read-only-document.d.ts.map +1 -0
  161. package/dist/read-only-document.js +4 -0
  162. package/dist/read-only-document.js.map +1 -0
  163. package/dist/record-paging.d.ts +63 -6
  164. package/dist/record-paging.d.ts.map +1 -1
  165. package/dist/record-paging.js +122 -29
  166. package/dist/record-paging.js.map +1 -1
  167. package/dist/references.d.ts +40 -0
  168. package/dist/references.d.ts.map +1 -0
  169. package/dist/references.js +135 -0
  170. package/dist/references.js.map +1 -0
  171. package/dist/request-lane.d.ts +5 -0
  172. package/dist/request-lane.d.ts.map +1 -0
  173. package/dist/request-lane.js +48 -0
  174. package/dist/request-lane.js.map +1 -0
  175. package/dist/sealed-arrow.d.ts +170 -0
  176. package/dist/sealed-arrow.d.ts.map +1 -0
  177. package/dist/sealed-arrow.js +769 -0
  178. package/dist/sealed-arrow.js.map +1 -0
  179. package/dist/sealed-cache.d.ts +21 -0
  180. package/dist/sealed-cache.d.ts.map +1 -0
  181. package/dist/sealed-cache.js +247 -0
  182. package/dist/sealed-cache.js.map +1 -0
  183. package/dist/sealed-encode.d.ts +87 -0
  184. package/dist/sealed-encode.d.ts.map +1 -0
  185. package/dist/sealed-encode.js +876 -0
  186. package/dist/sealed-encode.js.map +1 -0
  187. package/dist/sealed-handles.d.ts +45 -0
  188. package/dist/sealed-handles.d.ts.map +1 -0
  189. package/dist/sealed-handles.js +408 -0
  190. package/dist/sealed-handles.js.map +1 -0
  191. package/dist/sealed-store.d.ts +242 -0
  192. package/dist/sealed-store.d.ts.map +1 -0
  193. package/dist/sealed-store.js +1155 -0
  194. package/dist/sealed-store.js.map +1 -0
  195. package/dist/serializer.d.ts +6 -15
  196. package/dist/serializer.d.ts.map +1 -1
  197. package/dist/session-toolbar.d.ts +20 -5
  198. package/dist/session-toolbar.d.ts.map +1 -1
  199. package/dist/session-toolbar.js +419 -67
  200. package/dist/session-toolbar.js.map +1 -1
  201. package/dist/session.d.ts +38 -1
  202. package/dist/session.d.ts.map +1 -1
  203. package/dist/session.js +562 -79
  204. package/dist/session.js.map +1 -1
  205. package/dist/sha256.d.ts +3 -0
  206. package/dist/sha256.d.ts.map +1 -0
  207. package/dist/sha256.js +74 -0
  208. package/dist/sha256.js.map +1 -0
  209. package/dist/stable-handles.d.ts +19 -0
  210. package/dist/stable-handles.d.ts.map +1 -0
  211. package/dist/stable-handles.js +193 -0
  212. package/dist/stable-handles.js.map +1 -0
  213. package/dist/staged-seal.d.ts +2 -0
  214. package/dist/staged-seal.d.ts.map +1 -0
  215. package/dist/staged-seal.js +76 -0
  216. package/dist/staged-seal.js.map +1 -0
  217. package/dist/subscriber-delivery.d.ts +8 -0
  218. package/dist/subscriber-delivery.d.ts.map +1 -0
  219. package/dist/subscriber-delivery.js +31 -0
  220. package/dist/subscriber-delivery.js.map +1 -0
  221. package/dist/tail-op-import.d.ts +10 -0
  222. package/dist/tail-op-import.d.ts.map +1 -0
  223. package/dist/tail-op-import.js +33 -0
  224. package/dist/tail-op-import.js.map +1 -0
  225. package/dist/topic-lifecycle.d.ts +6 -0
  226. package/dist/topic-lifecycle.d.ts.map +1 -1
  227. package/dist/topic-lifecycle.js +32 -2
  228. package/dist/topic-lifecycle.js.map +1 -1
  229. package/dist/trial-replace-dialog.d.ts +10 -0
  230. package/dist/trial-replace-dialog.d.ts.map +1 -0
  231. package/dist/trial-replace-dialog.js +153 -0
  232. package/dist/trial-replace-dialog.js.map +1 -0
  233. package/dist/types.d.ts +8 -1
  234. package/dist/types.d.ts.map +1 -1
  235. package/dist/undo.d.ts +60 -5
  236. package/dist/undo.d.ts.map +1 -1
  237. package/dist/undo.js +344 -75
  238. package/dist/undo.js.map +1 -1
  239. package/dist/version-bar.d.ts +1 -0
  240. package/dist/version-bar.d.ts.map +1 -1
  241. package/dist/version-bar.js +2 -1
  242. package/dist/version-bar.js.map +1 -1
  243. package/dist/version.d.ts +2 -2
  244. package/dist/version.js +1 -1
  245. package/dist/ws-client.d.ts +21 -0
  246. package/dist/ws-client.d.ts.map +1 -1
  247. package/dist/ws-client.js +192 -8
  248. package/dist/ws-client.js.map +1 -1
  249. package/dist/ws-frame-limit.d.ts +1 -0
  250. package/dist/ws-frame-limit.d.ts.map +1 -1
  251. package/dist/ws-frame-limit.js.map +1 -1
  252. package/docs/app-manifest.md +121 -17
  253. package/docs/custom-chrome.md +24 -16
  254. package/docs/hosted-ui-advanced.md +38 -6
  255. package/docs/imported-documents.md +104 -51
  256. package/docs/presence.md +16 -4
  257. package/docs/schemas.md +8 -5
  258. package/docs/services.md +6 -6
  259. package/docs/streams.md +139 -150
  260. package/docs/text-fields.md +26 -19
  261. package/package.json +5 -2
  262. package/src/acting-organization.ts +6 -12
  263. package/src/api-fetch.ts +53 -3
  264. package/src/auth-flow.ts +1 -1
  265. package/src/batched-get.ts +117 -0
  266. package/src/call-service.ts +78 -3
  267. package/src/client.ts +1092 -121
  268. package/src/document-checkpoints.ts +307 -65
  269. package/src/document-commands.ts +5 -5
  270. package/src/document-contents.ts +27 -1
  271. package/src/document-set-subscription.ts +274 -0
  272. package/src/document-signals.ts +47 -5
  273. package/src/document-streams.ts +85 -16
  274. package/src/document-thumbnail-capture.ts +118 -32
  275. package/src/documents-namespace.ts +539 -84
  276. package/src/documents.ts +2017 -348
  277. package/src/errors.ts +17 -6
  278. package/src/fetch-retry.ts +5 -0
  279. package/src/file-choice.ts +26 -0
  280. package/src/guest-link.ts +362 -1
  281. package/src/handle-types.ts +73 -47
  282. package/src/handles.ts +253 -83
  283. package/src/hosted-ui.ts +211 -50
  284. package/src/import-contract.ts +227 -0
  285. package/src/import-guest.ts +193 -0
  286. package/src/import-report.ts +24 -0
  287. package/src/importer-wait.ts +4 -0
  288. package/src/importer.ts +386 -131
  289. package/src/in-development.ts +10 -0
  290. package/src/index.ts +76 -16
  291. package/src/init-keys.ts +6 -1
  292. package/src/input-documents.ts +819 -0
  293. package/src/inputs-status.ts +598 -0
  294. package/src/inputs.ts +1090 -0
  295. package/src/internal.ts +7 -0
  296. package/src/join-content.ts +135 -0
  297. package/src/join-stamp.ts +12 -0
  298. package/src/manifest-drift.ts +54 -0
  299. package/src/open-document.ts +2346 -930
  300. package/src/page-restore.ts +38 -0
  301. package/src/placement.ts +54 -0
  302. package/src/presence.ts +21 -5
  303. package/src/read-only-document.ts +133 -0
  304. package/src/record-paging.ts +147 -25
  305. package/src/references.ts +207 -0
  306. package/src/request-lane.ts +59 -0
  307. package/src/sealed-arrow.ts +843 -0
  308. package/src/sealed-cache.ts +267 -0
  309. package/src/sealed-encode.ts +1015 -0
  310. package/src/sealed-handles.ts +486 -0
  311. package/src/sealed-store.ts +1330 -0
  312. package/src/serializer.ts +8 -20
  313. package/src/session-toolbar.ts +463 -72
  314. package/src/session.ts +740 -99
  315. package/src/sha256.ts +65 -0
  316. package/src/stable-handles.ts +235 -0
  317. package/src/staged-seal.ts +90 -0
  318. package/src/subscriber-delivery.ts +37 -0
  319. package/src/tail-op-import.ts +30 -0
  320. package/src/topic-lifecycle.ts +38 -2
  321. package/src/trial-replace-dialog.ts +163 -0
  322. package/src/types.ts +6 -6
  323. package/src/undo.ts +386 -73
  324. package/src/version-bar.ts +5 -1
  325. package/src/version.ts +1 -1
  326. package/src/ws-client.ts +208 -16
  327. package/src/ws-frame-limit.ts +1 -0
package/AGENTS.md CHANGED
@@ -16,19 +16,19 @@ guesses at a shape the real files contradict.
16
16
  **The work has a customary shape in the user's trade.** A punch list, a
17
17
  timesheet, an RFI, a site diary: people in that line of work pass these
18
18
  around as documents whose fields they all expect, so a shape for it
19
- exists and the user probably holds a copy. Ask for theirs before you
19
+ exists and the user probably has a copy. Ask for theirs before you
20
20
  design a schema. Inventing a schema for a shape that already exists
21
21
  forks that shape: the picker routes documents to apps by their declared
22
22
  schema, so each app's documents stop opening in the other, and the split
23
23
  stands. Ask the user rather than searching for the shape yourself: it
24
- reaches you as a document they already hold.
24
+ reaches you as a document they already have.
25
25
 
26
26
  Ask as well whenever the user brings up another application. What that
27
27
  product can hand over decides whether you adopt a shape or integrate,
28
28
  and only the user knows.
29
29
 
30
30
  A product you assumed, rather than one the user named, works the other
31
- way round. Data a product holds reaches you through its API rather than
31
+ way round. Data a product stores reaches you through its API rather than
32
32
  as a document, so a sprint board, a sales pipeline, or a ticket queue
33
33
  you guess lives in some tool leaves you no shape to adopt. Build it as
34
34
  below until the user names the tool.
@@ -47,18 +47,40 @@ section), and scaffold the app shell while the user answers.
47
47
 
48
48
  With an example in hand: the user adds it at their Brass dashboard
49
49
  (`https://app.brass.build`) and sends you back the document's link,
50
- and you read what that document holds. A resolved schema is your
50
+ and you read what that document contains. A resolved schema is your
51
51
  record contract: pull it and adopt it verbatim
52
52
  (`npx @brass-build/cli schema pull --doc <docId>`). Read the records too,
53
53
  before you write code against them
54
- (`npx @brass-build/cli contents --doc <docId>` writes the whole document as
55
- JSON): the schema names the fields and the data tells you what is in them.
54
+ (`npx @brass-build/cli contents --doc <docId>` writes the document's
55
+ `default` stream as JSON, and `--stream <name>` writes another stream): the
56
+ schema names the fields and the data tells you what is in them.
57
+ When your app reads that document through `Brass.chooseInputs` rather than
58
+ opening it, pull with `--out input-schema.json` instead and copy that
59
+ file's `schema` into an `inputs` entry. A plain pull writes over your
60
+ manifest's `schema`, and Brass would then offer your app to open that
61
+ document's family.
56
62
  Read all of it rather than the first few records, since a file's records are
57
- grouped by type and its opening records carry a couple of the types it holds
58
- and none of the rest. A stored file with
59
- no schema means your app is its first importer: register your parse
60
- half with `Brass.registerImporter`, and declare the schema of the
61
- records you write in `brass-app.json` so the next app can adopt it.
63
+ grouped by type and its opening records carry a couple of its types
64
+ and none of the rest.
65
+ When your app reads many documents through `Brass.chooseInputs`, ask the
66
+ user for the project or folder it will read rather than one file, and
67
+ sample that set with `npx @brass-build/cli contents --from project:<projectId>`.
68
+ Run it first with `--max-documents 0`, which lists the set without reading
69
+ it, to see the families the set's files belong to (the `family` on each
70
+ document it lists), then pass `--family` the families your `chooseInputs`
71
+ call names. The command lists the
72
+ documents that call returns, reads several of them whole, and counts every
73
+ record type their streams contain, with a few records of each type drawn from
74
+ different documents. Sample the set because one file shows only the types
75
+ it carries, and other files in the set can carry more. Reading a file
76
+ starts its import, as opening it does, so keep some files of the set out
77
+ of the sample for the first-run check below.
78
+ If a stored file has no schema, your app is its first importer. Register a
79
+ function with `Brass.registerImporter` that takes the file and returns its
80
+ records as JSON, and declare the schema of those records in
81
+ `brass-app.json` so the next app can adopt it. Call `registerImporter` at
82
+ startup, unconditionally, not after sign-in or after a document opens:
83
+ Brass may load your app only to run its importer.
62
84
  In your app, the file opens the way every document opens: through the
63
85
  session and the hosted picker (the picker also brings a file into
64
86
  Brass).
@@ -89,11 +111,22 @@ front whether the org has any: an org that set none prints nothing, and
89
111
  you proceed with the defaults below.
90
112
 
91
113
  The pull needs a signed-in session, so when `brass agents pull` reports
92
- no credential, run the sign-in yourself first (`brass login --start`,
93
- relay the printed URL and code to the human, then `brass login --check`
94
- until it reports approved). That is the same credential you will use to
95
- publish (see "Ship the app"), so drive the sign-in now. `brass agents
96
- pull` is detailed in the `@brass-build/cli` package's `AGENTS.md`.
114
+ no credential, run the sign-in yourself first: run `brass login --start`
115
+ and copy the URL and code it prints into the visible text of your reply.
116
+ Most interfaces collapse command output, so the human never sees a code
117
+ that stays there. Then keep running `brass login --check --wait` in the
118
+ same turn until it reports approved: only a check stores the session,
119
+ and if the human approves while no check is running, the approval waits
120
+ for your next check. If the human sees your reply only when your turn
121
+ ends (you run as a subagent, or in a harness that shows only the final
122
+ message), end the turn with the URL and code instead, and run the check
123
+ as soon as you resume. That is the same credential you will use to
124
+ publish (see "Ship the app").
125
+
126
+ When the pull lists several organizations instead of pulling, ask the
127
+ human which one the app is for, and pass that id as `--org` to the pull
128
+ and to your first `brass publish`. `brass agents pull` is detailed in
129
+ the `@brass-build/cli` package's `AGENTS.md`.
97
130
 
98
131
  ## Have a second agent review your work
99
132
 
@@ -105,23 +138,62 @@ reviewing your own work reconfirms it. Build with a review loop.
105
138
 
106
139
  Once the integration builds, have a **separate** agent (not you)
107
140
  adversarially review it and drive it in a real browser against the
108
- live backend. Hold that reviewer to implementation-independent checks:
141
+ live backend. Give that reviewer implementation-independent checks:
109
142
 
110
- - It should take the document's own records from a subscriber of its
111
- own (`doc.map(...).subscribe(...)` / `doc.list(...).subscribe(...)`)
112
- and validate them against the data spec itself, rather than trusting
113
- the app's own helpers.
143
+ - It should read the document's records itself (walk
144
+ `doc.map(...).entries()` / `doc.list(...).values()`, or subscribe to
145
+ follow edits) and validate them against the data spec, rather than
146
+ trusting the app's own helpers.
114
147
  - It should push the negative, zero, and boundary inputs of every
115
148
  operation.
116
149
  - It should confirm each edit round-trips and leaves the document
117
150
  consistent.
118
- - It should open the same document as **two** signed-in readers and put
119
- them in the same field at once: with one reader's caret sitting in a
120
- field, the other edits it. The first reader's screen has to show that
121
- value once their caret leaves, and a reader whose own edit goes over a
151
+ - If the app reads across many documents, it should run the app over a
152
+ set that includes files nobody has opened yet (the ones you kept out of
153
+ your `contents --from` sample, or files added just before the run),
154
+ because a file's import can still be running when the app opens it. It should confirm the app shows
155
+ a loading state while such an open waits, and renders the records once
156
+ it resolves. It should include a file only another app imports, and
157
+ confirm the app shows that file as not imported yet when its open
158
+ rejects with `not_imported`. Once the other app has imported the file,
159
+ Brass calls the key's handler for it again, and the app should then
160
+ read it.
161
+ - If the app offers use without an account, it should make a document
162
+ signed out, then sign in through the app's own sign-in on that page and
163
+ confirm the document is still there. Signing in any other way, such as
164
+ through `brass browser-session`, leaves the document behind.
165
+ - It should open the same document as **two** signed-in users and put
166
+ them in the same field at once: with one user's caret sitting in a
167
+ field, the other edits it. The first user's screen has to show that
168
+ value once their caret leaves, and a user whose own edit goes over a
122
169
  peer's has to be told so. Both halves fail silently, and a single
123
170
  session never reaches either.
124
171
 
172
+ Both you and the reviewer need a signed-in browser.
173
+ `brass browser-session` prints a URL that opens your app already signed
174
+ in as you:
175
+
176
+ ```sh
177
+ npx @brass-build/cli browser-session --return-to http://localhost:5173/
178
+ ```
179
+
180
+ Point `--return-to` at your dev server while you build, and at the
181
+ published URL once you have one. Run the command once per browser
182
+ context, at the moment that context is ready to navigate. Each URL signs
183
+ in one browser once and expires two minutes after it is printed. Give
184
+ each of the two users a URL. Both sign in to the human's account, so ask
185
+ the human for a second account when a check needs two different people.
186
+
187
+ Open the document by its id, through `Brass.openDocumentById` or the
188
+ `?doc=` parameter the session restores on boot. Use a document your app
189
+ created, or one a user previously opened in your app from Brass. Brass refuses
190
+ access to documents the user has not granted to your app, returning a 403 status.
191
+ Brass's own dialogs, such as the picker, open in that browser too once the human
192
+ has signed in to the Brass dashboard before. Otherwise a dialog asks for a
193
+ sign-in that the human has to complete. The `@brass-build/cli` package's
194
+ `AGENTS.md` covers the rest, including how to install and drive a headless
195
+ browser.
196
+
125
197
  Have the reviewer drive any gesture on a touch device as well as a
126
198
  desktop mouse. Drags, multi-point taps, and anything else
127
199
  pointer-driven commonly work under a mouse and break under touch, and a
@@ -141,13 +213,23 @@ the baseline for when there is no design.
141
213
  viewport; do not center the app in a `max-width: 720px` column.
142
214
  - **Render two distinct shells, signed-out and signed-in.** A
143
215
  signed-in shell with disabled buttons next to a sign-in CTA reads as
144
- broken. Mount the signed-in shell after `onUserChange` fires with a
145
- non-null user, and render **neither** shell during the bootstrap
146
- window before that first fire (see "Rendering auth state" in the
147
- README).
216
+ broken. Mount the working shell when `Brass.authStatus` is
217
+ `'signed-in'` or `'guest'` (a visitor working without an account has no
218
+ user), the signed-out shell only on `'signed-out'`, and **neither**
219
+ during the `'unknown'` window before `init` settles (see "Rendering auth
220
+ state" in the README).
221
+ - **Let a visitor try the app without an account.** Give the signed-out
222
+ shell New and Upload buttons beside Sign in, declare
223
+ `"access": { "create": "anyone" }`, and publish with
224
+ `--gate off --visibility public` (see "Try before signing in" in the
225
+ README). Declare `"create": "signed-in"` instead only when the app's
226
+ content comes from files people pick with `Brass.chooseInputs`, or
227
+ when every action calls a service. When one feature calls a service,
228
+ disable that feature for a visitor and offer the rest.
148
229
  - **Put auth chrome in the header of the signed-in shell only**: the
149
- user's email or sub, plus sign out. The sign-in CTA belongs in the
150
- body of the signed-out shell, not in a pre-rendered header.
230
+ user's email or sub, plus sign out. The sign-in CTA, and any way in
231
+ without an account (see "Try before signing in" in the README), belong
232
+ in the body of the signed-out shell, not in a pre-rendered header.
151
233
  - **Include the viewport meta tag**:
152
234
  `<meta name="viewport" content="width=device-width, initial-scale=1">`.
153
235
  - **If you toggle shells with `el.hidden`, add
@@ -169,14 +251,23 @@ the baseline for when there is no design.
169
251
  - **Disable, don't hide, on read-only documents.** When
170
252
  `doc.readOnly` is true, render the editor and share controls disabled
171
253
  with a `title` explaining why, rather than removing them. It covers
172
- every reason this reader cannot write: a view-only grant, a view-only
173
- share link, a historical-version preview, and a document still
174
- loading. Re-read it in your `doc.subscribe` handler rather than
254
+ every reason this user cannot write: a view-only grant, a view-only
255
+ share link, a historical-version preview, a document still loading
256
+ or being prepared for editing, a file too large to edit
257
+ (`doc.atCapacity`), and a copy your app opened with `readOnly` or
258
+ `frozen`. Re-read it in your `doc.subscribe` handler rather than
175
259
  reading it once at bind: it also flips when someone withdraws the
176
- reader's access while the document is open, which is what closes the
260
+ user's access while the document is open, which is what closes the
177
261
  editor at the moment writing stops working. Pair it with
178
262
  `Brass.onError`, where the sentence explaining a refused write
179
263
  arrives.
264
+ - **Make each user action one Undo step.** Call
265
+ `void doc.createCheckpoint()` at the end of every action that edits
266
+ the document: on `pointerup` after a drag, after a command runs, after
267
+ a field commits. In a text editor, call it in `beforeinput`
268
+ whenever the coming edit starts a new step (see "Undo, checkpoints,
269
+ and version history" in the README), and leave the automatic interval
270
+ as it is.
180
271
  - **Name the next action in empty states.** "No document open. Use
181
272
  Open to pick or create one."
182
273
  - **Gate edit affordances on an open document.** When
@@ -204,7 +295,7 @@ the baseline for when there is no design.
204
295
  resting button-like affordance so it reads as clickable rather than
205
296
  as a heading.
206
297
  - **Wire presence by default, and wire both halves.** When
207
- `doc.presence` is non-null (any open writable doc), publish your own
298
+ `doc.presence` is non-null (any live open), publish your own
208
299
  pointer / camera / selection state on every move AND render other
209
300
  participants' state in the working surface, not just an initials
210
301
  list in the header (the README's "Presence" section explains why
@@ -248,11 +339,13 @@ them. Drive each to completion rather than noting it and stopping:
248
339
  drive the sign-in: run `brass login`. In a local session it opens the
249
340
  human's browser to approve and completes on approval. On a headless
250
341
  box it prints a URL and short code the human approves from any device.
342
+ Copy both into the visible text of your reply, since most interfaces
343
+ collapse command output.
251
344
  Running it and getting the human through approval is your step. For CI
252
345
  the human supplies `BRASS_SERVICE_TOKEN` instead.
253
346
  - **A key for every service you declared.** An app that declares
254
347
  `services` in `brass-app.json` calls those hosts through Brass, which
255
- holds the credential, and the credential comes from the provider's own
348
+ stores the credential, and the credential comes from the provider's own
256
349
  console. `brass publish` names each host still waiting and the page
257
350
  that takes its key, in the log and in `warnings` under `--json`. Give
258
351
  the human that line as it stands: it carries the host and a link
@@ -264,17 +357,25 @@ Once `brass status` reports a credential, publish:
264
357
 
265
358
  ```sh
266
359
  npm run build
267
- npx @brass-build/cli publish ./dist
360
+ npx @brass-build/cli publish ./dist --name "My app"
268
361
  ```
269
362
 
270
- This deploys to `https://<slug>.onbrass.app`. Report the integration
363
+ This deploys to `https://<slug>.onbrass.app`. If the app lets a visitor
364
+ work without an account, declare `"access": { "create": "anyone" }` in
365
+ `brass-app.json` and add `--gate off --visibility public`. Without
366
+ `--gate off`, Brass asks every visitor to sign in before the app loads.
367
+ Without `--visibility public`, a visitor with no account cannot create a
368
+ document, and `Brass.session.error` carries the
369
+ reason.
370
+ Report the integration
271
371
  against this end state, and close out every item before you call it
272
372
  done:
273
373
 
274
374
  - **built**: `npm run build` is clean.
275
- - **signed in**: `brass status` confirms a credential.
375
+ - **signed in**: `brass status` confirms a publish credential.
276
376
  - **published**: `brass publish` reported a URL.
277
- - **opened**: you loaded that URL and confirmed sign-in works there.
377
+ - **opened**: you loaded that URL in a browser you drive, signed in
378
+ through `brass browser-session`, and used the app there.
278
379
  - **keyed**: `brass publish` named no host as still waiting for a key. A
279
380
  host it named is an open item like any other, so offer the link and
280
381
  wait rather than reporting the integration done around it.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,95 @@ and the package follows [semantic versioning](https://semver.org/spec/v2.0.0.htm
6
6
  While the version is below `1.0.0`, minor releases may introduce
7
7
  breaking changes.
8
8
 
9
+ ## 0.5.0
10
+
11
+ ### Breaking
12
+
13
+ - `registerImporter` takes `(file) => { streams, report? }` in place of
14
+ `(source, doc) => void`. Return your records instead of writing them to a
15
+ document.
16
+ - 0.5.0 removes `DocumentSourceStream` and `DocumentSourceBlob.streams`.
17
+ - `doc.createCheckpoint()` resolves to `void`, and 0.5.0 removes
18
+ `DocumentCheckpoint`. Remove code that reads the result.
19
+
20
+ ### Added
21
+
22
+ - Support for dashboards and other derived content
23
+ - `Brass.chooseInputs(families)` asks a user to select files, folders, or
24
+ projects. `Brass.chooseInput(families)` asks the user to pick a single
25
+ file.
26
+ - `doc.dependsOn(key, refs)` saves picked references in your document.
27
+ - `doc.subscribeInputDocuments(key, handlers)` calls your handlers as the
28
+ referenced files load, change or leave. See "Referencing other
29
+ documents" in the README.
30
+ - `Brass.documents.get(id)` returns a document's `family`, and
31
+ `member_of.chain` lists the folders and archives containing it.
32
+ - `inputs` in `brass-app.json` lists the schemas your app reads. The picker
33
+ offers files that match one of them.
34
+ - Faster read-only opening
35
+ - `readOnly: true` on `Brass.openDocumentById` or `session.open` opens a
36
+ `ReadOnlyDocument`, for apps that only display documents. Large documents
37
+ load significantly faster, and unchanged ones reopen without downloading
38
+ again.
39
+ - `Brass.init(appId, { open: { readOnly: true } })` opens every session
40
+ document read-only. Documents the session creates still open editable.
41
+ - `frozen: true` opens a copy that ignores later edits, for reading many
42
+ documents at once. `doc.onChanged(cb)` reports a change, and
43
+ `doc.reload()` updates the same copy to the latest version.
44
+ - `doc.reopen()` switches an open document between editable, `readOnly` and
45
+ `frozen`, so a user can view first and edit later.
46
+ - Optional trial use for signed-out users
47
+ - Signed-out users can create and open temporary documents, to try your app
48
+ before signing up. `doc.expiresAt` gives the expiry. Signing in from that
49
+ page keeps the document. See "Try before signing in" in the README.
50
+ - `access` in `brass-app.json` sets who can use your app. `create`
51
+ (`false`, `"signed-in"` or `"anyone"`) sets who can make new documents
52
+ (`"anyone"` needs a public app). Use `false` for an app that makes no
53
+ documents of its own. `open` (`"signed-in"` or `"anyone"`) sets who can
54
+ open a public link. A public app with its hosted load gate off and no
55
+ `create` lets signed-out users create documents. Set
56
+ `create: "signed-in"` to require a sign-in.
57
+ - `shared_schemas` in `brass-app.json` defines a schema once for other fields
58
+ to refer to.
59
+ - An `imports` entry can set its own `schema`, for imported files that differ
60
+ from your app's documents.
61
+ - List handles have `get(index)`, so you can read one item by its position.
62
+ To walk every entry, map and ordered map handles have `entries()` and list
63
+ handles have `values()`.
64
+ - `mutate(fn, { undoable: false })` keeps changes the user did not make out of
65
+ Undo.
66
+ - `doc.importReport` returns the report your importer produced.
67
+
68
+ ### Changed
69
+
70
+ - `callService` retries brief refusals itself and returns `rate_limited` if
71
+ they continue. Do not add your own immediate retry.
72
+ - Call `registerImporter` at startup, so your importer is ready whenever an
73
+ import starts.
74
+
75
+ ### Deprecated
76
+
77
+ - `read()` on `StoredMap` and `StoredList`. Use `keys()`, `entries()` or
78
+ `values()`.
79
+ - `session.pick()` and `Brass.selectDocument()`. Use `session.open()` with no
80
+ id.
81
+ - `documentOptions.readOnly`. Use the top-level `readOnly`, which returns a
82
+ `ReadOnlyDocument`.
83
+ - `ordered()` on ordered map handles. Use `entries()`.
84
+
85
+ ## 0.4.1
86
+
87
+ ### Fixed
88
+
89
+ - `Brass.user.display_name` and `Brass.user.avatar_url` keep resolving: the
90
+ profile read identifies the calling app the way every other call does.
91
+ Signing in as someone else also clears the previous person's organization
92
+ from the hosted toolbar.
93
+ - `Brass.callService` and `Brass.connectService` work on a document reached
94
+ through a project shared with you directly, which can sit in an organization
95
+ you are not a member of. Several calls needing an organization at once open
96
+ the chooser once between them.
97
+
9
98
  ## 0.4.0
10
99
 
11
100
  ### Added
@@ -37,10 +126,10 @@ breaking changes.
37
126
 
38
127
  ### Fixed
39
128
 
40
- - A document that cannot reach Brass reports the failure instead of accepting
41
- edits it cannot save. The first write calls `Brass.onError` and sets
42
- `doc.readOnly`, and a later `mutate` throws. Disable your editor on
43
- `doc.readOnly`.
129
+ - A document opened with no live connection configured to write through
130
+ reports the failure instead of accepting edits it cannot save. The first
131
+ write calls `Brass.onError` and sets `doc.readOnly`, and a later `mutate`
132
+ throws. Disable your editor on `doc.readOnly`.
44
133
  - Reopening a document whose import did not finish runs the import again.
45
134
  - A `doc.stream(name)` open that fails closes its connection, instead of
46
135
  leaving it open for the life of the page.