@brass-build/client 0.4.1 → 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 (323) hide show
  1. package/AGENTS.md +124 -45
  2. package/CHANGELOG.md +80 -4
  3. package/README.md +666 -179
  4. package/dist/api-fetch.d.ts +8 -0
  5. package/dist/api-fetch.d.ts.map +1 -1
  6. package/dist/api-fetch.js +35 -8
  7. package/dist/api-fetch.js.map +1 -1
  8. package/dist/batched-get.d.ts +11 -0
  9. package/dist/batched-get.d.ts.map +1 -0
  10. package/dist/batched-get.js +92 -0
  11. package/dist/batched-get.js.map +1 -0
  12. package/dist/call-service.d.ts +4 -0
  13. package/dist/call-service.d.ts.map +1 -1
  14. package/dist/call-service.js +66 -3
  15. package/dist/call-service.js.map +1 -1
  16. package/dist/client.d.ts +48 -2
  17. package/dist/client.d.ts.map +1 -1
  18. package/dist/client.js +918 -115
  19. package/dist/client.js.map +1 -1
  20. package/dist/document-checkpoints.d.ts +25 -2
  21. package/dist/document-checkpoints.d.ts.map +1 -1
  22. package/dist/document-checkpoints.js +258 -61
  23. package/dist/document-checkpoints.js.map +1 -1
  24. package/dist/document-commands.d.ts.map +1 -1
  25. package/dist/document-commands.js +5 -3
  26. package/dist/document-commands.js.map +1 -1
  27. package/dist/document-contents.d.ts +10 -0
  28. package/dist/document-contents.d.ts.map +1 -1
  29. package/dist/document-contents.js +23 -1
  30. package/dist/document-contents.js.map +1 -1
  31. package/dist/document-set-subscription.d.ts +56 -0
  32. package/dist/document-set-subscription.d.ts.map +1 -0
  33. package/dist/document-set-subscription.js +240 -0
  34. package/dist/document-set-subscription.js.map +1 -0
  35. package/dist/document-signals.d.ts +6 -0
  36. package/dist/document-signals.d.ts.map +1 -1
  37. package/dist/document-signals.js +31 -1
  38. package/dist/document-signals.js.map +1 -1
  39. package/dist/document-streams.d.ts +36 -2
  40. package/dist/document-streams.d.ts.map +1 -1
  41. package/dist/document-streams.js +69 -18
  42. package/dist/document-streams.js.map +1 -1
  43. package/dist/document-thumbnail-capture.d.ts +12 -2
  44. package/dist/document-thumbnail-capture.d.ts.map +1 -1
  45. package/dist/document-thumbnail-capture.js +103 -27
  46. package/dist/document-thumbnail-capture.js.map +1 -1
  47. package/dist/documents-namespace.d.ts +92 -10
  48. package/dist/documents-namespace.d.ts.map +1 -1
  49. package/dist/documents-namespace.js +285 -39
  50. package/dist/documents-namespace.js.map +1 -1
  51. package/dist/documents.d.ts +173 -8
  52. package/dist/documents.d.ts.map +1 -1
  53. package/dist/documents.js +1778 -310
  54. package/dist/documents.js.map +1 -1
  55. package/dist/errors.d.ts +3 -3
  56. package/dist/errors.d.ts.map +1 -1
  57. package/dist/errors.js.map +1 -1
  58. package/dist/fetch-retry.d.ts +1 -0
  59. package/dist/fetch-retry.d.ts.map +1 -1
  60. package/dist/fetch-retry.js +2 -0
  61. package/dist/fetch-retry.js.map +1 -1
  62. package/dist/file-choice.d.ts +2 -0
  63. package/dist/file-choice.d.ts.map +1 -0
  64. package/dist/file-choice.js +27 -0
  65. package/dist/file-choice.js.map +1 -0
  66. package/dist/guest-link.d.ts +18 -1
  67. package/dist/guest-link.d.ts.map +1 -1
  68. package/dist/guest-link.js +329 -1
  69. package/dist/guest-link.js.map +1 -1
  70. package/dist/handle-types.d.ts +67 -5
  71. package/dist/handle-types.d.ts.map +1 -1
  72. package/dist/handles.d.ts +15 -19
  73. package/dist/handles.d.ts.map +1 -1
  74. package/dist/handles.js +231 -76
  75. package/dist/handles.js.map +1 -1
  76. package/dist/hosted-ui.d.ts +61 -0
  77. package/dist/hosted-ui.d.ts.map +1 -1
  78. package/dist/hosted-ui.js +94 -42
  79. package/dist/hosted-ui.js.map +1 -1
  80. package/dist/import-contract.d.ts +74 -0
  81. package/dist/import-contract.d.ts.map +1 -0
  82. package/dist/import-contract.js +163 -0
  83. package/dist/import-contract.js.map +1 -0
  84. package/dist/import-guest.d.ts +9 -0
  85. package/dist/import-guest.d.ts.map +1 -0
  86. package/dist/import-guest.js +155 -0
  87. package/dist/import-guest.js.map +1 -0
  88. package/dist/import-report.d.ts +17 -0
  89. package/dist/import-report.d.ts.map +1 -0
  90. package/dist/import-report.js +7 -0
  91. package/dist/import-report.js.map +1 -0
  92. package/dist/importer-wait.d.ts +2 -0
  93. package/dist/importer-wait.d.ts.map +1 -0
  94. package/dist/importer-wait.js +5 -0
  95. package/dist/importer-wait.js.map +1 -0
  96. package/dist/importer.d.ts +18 -4
  97. package/dist/importer.d.ts.map +1 -1
  98. package/dist/importer.js +322 -105
  99. package/dist/importer.js.map +1 -1
  100. package/dist/in-development.d.ts +2 -0
  101. package/dist/in-development.d.ts.map +1 -0
  102. package/dist/in-development.js +10 -0
  103. package/dist/in-development.js.map +1 -0
  104. package/dist/index.d.ts +16 -8
  105. package/dist/index.d.ts.map +1 -1
  106. package/dist/index.js +24 -8
  107. package/dist/index.js.map +1 -1
  108. package/dist/init-keys.d.ts +1 -1
  109. package/dist/init-keys.d.ts.map +1 -1
  110. package/dist/init-keys.js +6 -1
  111. package/dist/init-keys.js.map +1 -1
  112. package/dist/input-documents.d.ts +67 -0
  113. package/dist/input-documents.d.ts.map +1 -0
  114. package/dist/input-documents.js +693 -0
  115. package/dist/input-documents.js.map +1 -0
  116. package/dist/inputs-status.d.ts +80 -0
  117. package/dist/inputs-status.d.ts.map +1 -0
  118. package/dist/inputs-status.js +460 -0
  119. package/dist/inputs-status.js.map +1 -0
  120. package/dist/inputs.d.ts +2 -0
  121. package/dist/inputs.d.ts.map +1 -0
  122. package/dist/inputs.js +793 -0
  123. package/dist/inputs.js.map +1 -0
  124. package/dist/internal.d.ts +6 -1
  125. package/dist/internal.d.ts.map +1 -1
  126. package/dist/internal.js +4 -1
  127. package/dist/internal.js.map +1 -1
  128. package/dist/join-content.d.ts +33 -0
  129. package/dist/join-content.d.ts.map +1 -0
  130. package/dist/join-content.js +114 -0
  131. package/dist/join-content.js.map +1 -0
  132. package/dist/join-stamp.d.ts +3 -0
  133. package/dist/join-stamp.d.ts.map +1 -0
  134. package/dist/join-stamp.js +12 -0
  135. package/dist/join-stamp.js.map +1 -0
  136. package/dist/manifest-drift.d.ts +9 -0
  137. package/dist/manifest-drift.d.ts.map +1 -0
  138. package/dist/manifest-drift.js +46 -0
  139. package/dist/manifest-drift.js.map +1 -0
  140. package/dist/open-document.d.ts +109 -2
  141. package/dist/open-document.d.ts.map +1 -1
  142. package/dist/open-document.js +1822 -811
  143. package/dist/open-document.js.map +1 -1
  144. package/dist/page-restore.d.ts +12 -0
  145. package/dist/page-restore.d.ts.map +1 -0
  146. package/dist/page-restore.js +23 -0
  147. package/dist/page-restore.js.map +1 -0
  148. package/dist/placement.d.ts +13 -0
  149. package/dist/placement.d.ts.map +1 -0
  150. package/dist/placement.js +34 -0
  151. package/dist/placement.js.map +1 -0
  152. package/dist/presence.d.ts +1 -0
  153. package/dist/presence.d.ts.map +1 -1
  154. package/dist/presence.js +16 -4
  155. package/dist/presence.js.map +1 -1
  156. package/dist/read-only-document.d.ts +87 -0
  157. package/dist/read-only-document.d.ts.map +1 -0
  158. package/dist/read-only-document.js +4 -0
  159. package/dist/read-only-document.js.map +1 -0
  160. package/dist/record-paging.d.ts +63 -6
  161. package/dist/record-paging.d.ts.map +1 -1
  162. package/dist/record-paging.js +122 -29
  163. package/dist/record-paging.js.map +1 -1
  164. package/dist/references.d.ts +40 -0
  165. package/dist/references.d.ts.map +1 -0
  166. package/dist/references.js +135 -0
  167. package/dist/references.js.map +1 -0
  168. package/dist/request-lane.d.ts +5 -0
  169. package/dist/request-lane.d.ts.map +1 -0
  170. package/dist/request-lane.js +48 -0
  171. package/dist/request-lane.js.map +1 -0
  172. package/dist/sealed-arrow.d.ts +170 -0
  173. package/dist/sealed-arrow.d.ts.map +1 -0
  174. package/dist/sealed-arrow.js +769 -0
  175. package/dist/sealed-arrow.js.map +1 -0
  176. package/dist/sealed-cache.d.ts +21 -0
  177. package/dist/sealed-cache.d.ts.map +1 -0
  178. package/dist/sealed-cache.js +247 -0
  179. package/dist/sealed-cache.js.map +1 -0
  180. package/dist/sealed-encode.d.ts +87 -0
  181. package/dist/sealed-encode.d.ts.map +1 -0
  182. package/dist/sealed-encode.js +876 -0
  183. package/dist/sealed-encode.js.map +1 -0
  184. package/dist/sealed-handles.d.ts +45 -0
  185. package/dist/sealed-handles.d.ts.map +1 -0
  186. package/dist/sealed-handles.js +408 -0
  187. package/dist/sealed-handles.js.map +1 -0
  188. package/dist/sealed-store.d.ts +242 -0
  189. package/dist/sealed-store.d.ts.map +1 -0
  190. package/dist/sealed-store.js +1155 -0
  191. package/dist/sealed-store.js.map +1 -0
  192. package/dist/serializer.d.ts +6 -15
  193. package/dist/serializer.d.ts.map +1 -1
  194. package/dist/session-toolbar.d.ts +20 -5
  195. package/dist/session-toolbar.d.ts.map +1 -1
  196. package/dist/session-toolbar.js +419 -67
  197. package/dist/session-toolbar.js.map +1 -1
  198. package/dist/session.d.ts +38 -1
  199. package/dist/session.d.ts.map +1 -1
  200. package/dist/session.js +562 -79
  201. package/dist/session.js.map +1 -1
  202. package/dist/sha256.d.ts +3 -0
  203. package/dist/sha256.d.ts.map +1 -0
  204. package/dist/sha256.js +74 -0
  205. package/dist/sha256.js.map +1 -0
  206. package/dist/stable-handles.d.ts +19 -0
  207. package/dist/stable-handles.d.ts.map +1 -0
  208. package/dist/stable-handles.js +193 -0
  209. package/dist/stable-handles.js.map +1 -0
  210. package/dist/staged-seal.d.ts +2 -0
  211. package/dist/staged-seal.d.ts.map +1 -0
  212. package/dist/staged-seal.js +76 -0
  213. package/dist/staged-seal.js.map +1 -0
  214. package/dist/subscriber-delivery.d.ts +8 -0
  215. package/dist/subscriber-delivery.d.ts.map +1 -0
  216. package/dist/subscriber-delivery.js +31 -0
  217. package/dist/subscriber-delivery.js.map +1 -0
  218. package/dist/tail-op-import.d.ts +10 -0
  219. package/dist/tail-op-import.d.ts.map +1 -0
  220. package/dist/tail-op-import.js +33 -0
  221. package/dist/tail-op-import.js.map +1 -0
  222. package/dist/topic-lifecycle.d.ts +6 -0
  223. package/dist/topic-lifecycle.d.ts.map +1 -1
  224. package/dist/topic-lifecycle.js +32 -2
  225. package/dist/topic-lifecycle.js.map +1 -1
  226. package/dist/trial-replace-dialog.d.ts +10 -0
  227. package/dist/trial-replace-dialog.d.ts.map +1 -0
  228. package/dist/trial-replace-dialog.js +153 -0
  229. package/dist/trial-replace-dialog.js.map +1 -0
  230. package/dist/types.d.ts +8 -1
  231. package/dist/types.d.ts.map +1 -1
  232. package/dist/undo.d.ts +60 -5
  233. package/dist/undo.d.ts.map +1 -1
  234. package/dist/undo.js +344 -75
  235. package/dist/undo.js.map +1 -1
  236. package/dist/version-bar.d.ts +1 -0
  237. package/dist/version-bar.d.ts.map +1 -1
  238. package/dist/version-bar.js +2 -1
  239. package/dist/version-bar.js.map +1 -1
  240. package/dist/version.d.ts +2 -2
  241. package/dist/version.js +1 -1
  242. package/dist/ws-client.d.ts +21 -0
  243. package/dist/ws-client.d.ts.map +1 -1
  244. package/dist/ws-client.js +192 -8
  245. package/dist/ws-client.js.map +1 -1
  246. package/dist/ws-frame-limit.d.ts +1 -0
  247. package/dist/ws-frame-limit.d.ts.map +1 -1
  248. package/dist/ws-frame-limit.js.map +1 -1
  249. package/docs/app-manifest.md +121 -17
  250. package/docs/custom-chrome.md +24 -16
  251. package/docs/hosted-ui-advanced.md +38 -6
  252. package/docs/imported-documents.md +104 -51
  253. package/docs/presence.md +16 -4
  254. package/docs/schemas.md +8 -5
  255. package/docs/services.md +6 -6
  256. package/docs/streams.md +139 -150
  257. package/docs/text-fields.md +26 -19
  258. package/package.json +5 -2
  259. package/src/api-fetch.ts +53 -3
  260. package/src/auth-flow.ts +1 -1
  261. package/src/batched-get.ts +117 -0
  262. package/src/call-service.ts +78 -3
  263. package/src/client.ts +1022 -112
  264. package/src/document-checkpoints.ts +307 -65
  265. package/src/document-commands.ts +5 -5
  266. package/src/document-contents.ts +27 -1
  267. package/src/document-set-subscription.ts +274 -0
  268. package/src/document-signals.ts +47 -5
  269. package/src/document-streams.ts +85 -16
  270. package/src/document-thumbnail-capture.ts +118 -32
  271. package/src/documents-namespace.ts +539 -84
  272. package/src/documents.ts +2017 -348
  273. package/src/errors.ts +17 -6
  274. package/src/fetch-retry.ts +5 -0
  275. package/src/file-choice.ts +26 -0
  276. package/src/guest-link.ts +362 -1
  277. package/src/handle-types.ts +73 -47
  278. package/src/handles.ts +253 -83
  279. package/src/hosted-ui.ts +211 -50
  280. package/src/import-contract.ts +227 -0
  281. package/src/import-guest.ts +193 -0
  282. package/src/import-report.ts +24 -0
  283. package/src/importer-wait.ts +4 -0
  284. package/src/importer.ts +386 -131
  285. package/src/in-development.ts +10 -0
  286. package/src/index.ts +76 -16
  287. package/src/init-keys.ts +6 -1
  288. package/src/input-documents.ts +819 -0
  289. package/src/inputs-status.ts +598 -0
  290. package/src/inputs.ts +1090 -0
  291. package/src/internal.ts +7 -0
  292. package/src/join-content.ts +135 -0
  293. package/src/join-stamp.ts +12 -0
  294. package/src/manifest-drift.ts +54 -0
  295. package/src/open-document.ts +2346 -930
  296. package/src/page-restore.ts +38 -0
  297. package/src/placement.ts +54 -0
  298. package/src/presence.ts +21 -5
  299. package/src/read-only-document.ts +133 -0
  300. package/src/record-paging.ts +147 -25
  301. package/src/references.ts +207 -0
  302. package/src/request-lane.ts +59 -0
  303. package/src/sealed-arrow.ts +843 -0
  304. package/src/sealed-cache.ts +267 -0
  305. package/src/sealed-encode.ts +1015 -0
  306. package/src/sealed-handles.ts +486 -0
  307. package/src/sealed-store.ts +1330 -0
  308. package/src/serializer.ts +8 -20
  309. package/src/session-toolbar.ts +463 -72
  310. package/src/session.ts +740 -99
  311. package/src/sha256.ts +65 -0
  312. package/src/stable-handles.ts +235 -0
  313. package/src/staged-seal.ts +90 -0
  314. package/src/subscriber-delivery.ts +37 -0
  315. package/src/tail-op-import.ts +30 -0
  316. package/src/topic-lifecycle.ts +38 -2
  317. package/src/trial-replace-dialog.ts +163 -0
  318. package/src/types.ts +6 -6
  319. package/src/undo.ts +386 -73
  320. package/src/version-bar.ts +5 -1
  321. package/src/version.ts +1 -1
  322. package/src/ws-client.ts +208 -16
  323. 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,20 +138,34 @@ 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
 
@@ -134,14 +181,18 @@ Point `--return-to` at your dev server while you build, and at the
134
181
  published URL once you have one. Run the command once per browser
135
182
  context, at the moment that context is ready to navigate. Each URL signs
136
183
  in one browser once and expires two minutes after it is printed. Give
137
- the two readers a URL each. Both readers are you, so ask the human for a
138
- second account when a check needs them to be different people.
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.
139
186
 
140
187
  Open the document by its id, through `Brass.openDocumentById` or the
141
- `?doc=` parameter the session restores on boot. The picker and Brass's
142
- other dialogs need a Brass sign-in, which this URL does not provide. The
143
- `@brass-build/cli` package's `AGENTS.md` covers the rest, including how
144
- to install and drive a headless browser.
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.
145
196
 
146
197
  Have the reviewer drive any gesture on a touch device as well as a
147
198
  desktop mouse. Drags, multi-point taps, and anything else
@@ -162,13 +213,23 @@ the baseline for when there is no design.
162
213
  viewport; do not center the app in a `max-width: 720px` column.
163
214
  - **Render two distinct shells, signed-out and signed-in.** A
164
215
  signed-in shell with disabled buttons next to a sign-in CTA reads as
165
- broken. Mount the signed-in shell after `onUserChange` fires with a
166
- non-null user, and render **neither** shell during the bootstrap
167
- window before that first fire (see "Rendering auth state" in the
168
- 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.
169
229
  - **Put auth chrome in the header of the signed-in shell only**: the
170
- user's email or sub, plus sign out. The sign-in CTA belongs in the
171
- 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.
172
233
  - **Include the viewport meta tag**:
173
234
  `<meta name="viewport" content="width=device-width, initial-scale=1">`.
174
235
  - **If you toggle shells with `el.hidden`, add
@@ -190,14 +251,23 @@ the baseline for when there is no design.
190
251
  - **Disable, don't hide, on read-only documents.** When
191
252
  `doc.readOnly` is true, render the editor and share controls disabled
192
253
  with a `title` explaining why, rather than removing them. It covers
193
- every reason this reader cannot write: a view-only grant, a view-only
194
- share link, a historical-version preview, and a document still
195
- 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
196
259
  reading it once at bind: it also flips when someone withdraws the
197
- 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
198
261
  editor at the moment writing stops working. Pair it with
199
262
  `Brass.onError`, where the sentence explaining a refused write
200
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.
201
271
  - **Name the next action in empty states.** "No document open. Use
202
272
  Open to pick or create one."
203
273
  - **Gate edit affordances on an open document.** When
@@ -225,7 +295,7 @@ the baseline for when there is no design.
225
295
  resting button-like affordance so it reads as clickable rather than
226
296
  as a heading.
227
297
  - **Wire presence by default, and wire both halves.** When
228
- `doc.presence` is non-null (any open writable doc), publish your own
298
+ `doc.presence` is non-null (any live open), publish your own
229
299
  pointer / camera / selection state on every move AND render other
230
300
  participants' state in the working surface, not just an initials
231
301
  list in the header (the README's "Presence" section explains why
@@ -269,11 +339,13 @@ them. Drive each to completion rather than noting it and stopping:
269
339
  drive the sign-in: run `brass login`. In a local session it opens the
270
340
  human's browser to approve and completes on approval. On a headless
271
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.
272
344
  Running it and getting the human through approval is your step. For CI
273
345
  the human supplies `BRASS_SERVICE_TOKEN` instead.
274
346
  - **A key for every service you declared.** An app that declares
275
347
  `services` in `brass-app.json` calls those hosts through Brass, which
276
- 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
277
349
  console. `brass publish` names each host still waiting and the page
278
350
  that takes its key, in the log and in `warnings` under `--json`. Give
279
351
  the human that line as it stands: it carries the host and a link
@@ -285,10 +357,17 @@ Once `brass status` reports a credential, publish:
285
357
 
286
358
  ```sh
287
359
  npm run build
288
- npx @brass-build/cli publish ./dist
360
+ npx @brass-build/cli publish ./dist --name "My app"
289
361
  ```
290
362
 
291
- 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
292
371
  against this end state, and close out every item before you call it
293
372
  done:
294
373
 
package/CHANGELOG.md CHANGED
@@ -6,6 +6,82 @@ 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
+
9
85
  ## 0.4.1
10
86
 
11
87
  ### Fixed
@@ -50,10 +126,10 @@ breaking changes.
50
126
 
51
127
  ### Fixed
52
128
 
53
- - A document that cannot reach Brass reports the failure instead of accepting
54
- edits it cannot save. The first write calls `Brass.onError` and sets
55
- `doc.readOnly`, and a later `mutate` throws. Disable your editor on
56
- `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`.
57
133
  - Reopening a document whose import did not finish runs the import again.
58
134
  - A `doc.stream(name)` open that fails closes its connection, instead of
59
135
  leaving it open for the life of the page.