bookish-press 0.4.45 → 0.4.47

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 (533) hide show
  1. package/.env.example +8 -0
  2. package/.firebaserc +8 -0
  3. package/.prettierignore +8 -0
  4. package/.prettierrc.json +5 -0
  5. package/_update-notifier-last-checked +0 -0
  6. package/firebase.json +46 -0
  7. package/firestore.indexes.json +4 -0
  8. package/firestore.rules +59 -0
  9. package/functions/.eslintrc.js +28 -0
  10. package/functions/package-lock.json +12595 -0
  11. package/functions/package.json +43 -0
  12. package/functions/src/index.ts +345 -0
  13. package/functions/tsconfig.dev.json +3 -0
  14. package/functions/tsconfig.json +15 -0
  15. package/package.json +53 -270
  16. package/scripts/claims.cjs +99 -0
  17. package/src/app.d.ts +9 -0
  18. package/src/app.html +24 -0
  19. package/src/lib/components/Auth.svelte +65 -0
  20. package/{components/Authentication.d.ts → src/lib/components/Authentication.ts} +2 -0
  21. package/{components → src/lib/components}/BookPreview.svelte +27 -22
  22. package/{components → src/lib/components}/External.svelte +2 -1
  23. package/src/lib/components/Link.svelte +58 -0
  24. package/{components → src/lib/components}/app/BookList.svelte +6 -3
  25. package/{components → src/lib/components}/app/Button.svelte +5 -4
  26. package/{components → src/lib/components}/app/Feedback.svelte +11 -7
  27. package/{components → src/lib/components}/app/Head.svelte +2 -1
  28. package/{components → src/lib/components}/app/Large.svelte +0 -0
  29. package/{components → src/lib/components}/app/Lead.svelte +0 -0
  30. package/{components → src/lib/components}/app/Link.svelte +4 -3
  31. package/{components → src/lib/components}/app/Options.svelte +5 -4
  32. package/{components → src/lib/components}/app/Paragraph.svelte +2 -1
  33. package/{components → src/lib/components}/app/Section.svelte +0 -0
  34. package/{components → src/lib/components}/app/Table.svelte +0 -0
  35. package/{components → src/lib/components}/app/TextInput.svelte +12 -9
  36. package/{components → src/lib/components}/chapter/Atom.svelte +18 -12
  37. package/src/lib/components/chapter/Block.svelte +42 -0
  38. package/{components → src/lib/components}/chapter/Callout.svelte +6 -3
  39. package/{components → src/lib/components}/chapter/CaptionedCode.svelte +21 -13
  40. package/{components → src/lib/components}/chapter/ChapterBody.svelte +13 -9
  41. package/{components → src/lib/components}/chapter/Citations.svelte +34 -33
  42. package/{components → src/lib/components}/chapter/Code.svelte +63 -58
  43. package/{components → src/lib/components}/chapter/Comment.svelte +30 -18
  44. package/{components → src/lib/components}/chapter/Definition.svelte +23 -17
  45. package/{components → src/lib/components}/chapter/Embed.svelte +97 -77
  46. package/src/lib/components/chapter/ErrorMessage.svelte +12 -0
  47. package/{components → src/lib/components}/chapter/ExtendedPrism.js +0 -0
  48. package/{components → src/lib/components}/chapter/Figure.svelte +34 -26
  49. package/{components → src/lib/components}/chapter/Footnote.svelte +32 -20
  50. package/{components → src/lib/components}/chapter/Format.svelte +39 -34
  51. package/{components → src/lib/components}/chapter/InlineCode.svelte +9 -5
  52. package/{components → src/lib/components}/chapter/Label.svelte +23 -14
  53. package/{components → src/lib/components}/chapter/Link.svelte +27 -21
  54. package/{components → src/lib/components}/chapter/List.svelte +5 -3
  55. package/{components → src/lib/components}/chapter/Marginal.svelte +54 -41
  56. package/{components → src/lib/components}/chapter/Paragraph.svelte +25 -20
  57. package/{components → src/lib/components}/chapter/Positioned.svelte +4 -1
  58. package/{components → src/lib/components}/chapter/Problem.svelte +0 -0
  59. package/src/lib/components/chapter/Python.svelte +144 -0
  60. package/{components → src/lib/components}/chapter/Quote.svelte +9 -5
  61. package/{components → src/lib/components}/chapter/Rule.svelte +4 -1
  62. package/{components → src/lib/components}/chapter/Table.svelte +11 -7
  63. package/src/lib/components/chapter/Text.svelte +109 -0
  64. package/src/lib/components/editor/BookishEditor.svelte +1101 -0
  65. package/src/lib/components/editor/CalloutEditor.svelte +14 -0
  66. package/{components → src/lib/components}/editor/CaptionedCodeEditor.svelte +10 -6
  67. package/src/lib/components/editor/CaretContext.ts +55 -0
  68. package/{components/editor/CaretState.d.ts → src/lib/components/editor/CaretState.ts} +6 -7
  69. package/{components/editor/CaretUtilities.d.ts → src/lib/components/editor/CaretUtilities.ts} +1 -0
  70. package/{components → src/lib/components}/editor/CaretView.svelte +25 -20
  71. package/src/lib/components/editor/CitationsEditor.svelte +64 -0
  72. package/{components/editor/Clipboard.d.ts → src/lib/components/editor/Clipboard.ts} +2 -1
  73. package/{components/editor/Command.d.ts → src/lib/components/editor/Command.ts} +8 -2
  74. package/{components/editor/Commands.js → src/lib/components/editor/Commands.ts} +730 -315
  75. package/src/lib/components/editor/ConfirmButton.svelte +51 -0
  76. package/src/lib/components/editor/DefinitionEditor.svelte +44 -0
  77. package/src/lib/components/editor/EmbedEditor.svelte +152 -0
  78. package/{components → src/lib/components}/editor/Icon.svelte +2 -1
  79. package/{components → src/lib/components}/editor/ImageChooser.svelte +24 -19
  80. package/src/lib/components/editor/InlineCodeEditor.svelte +16 -0
  81. package/{components → src/lib/components}/editor/LabelEditor.svelte +14 -9
  82. package/{components → src/lib/components}/editor/LanguageEditor.svelte +8 -5
  83. package/src/lib/components/editor/LinkEditor.svelte +110 -0
  84. package/{components → src/lib/components}/editor/Note.svelte +0 -0
  85. package/{components → src/lib/components}/editor/Permissions.svelte +43 -36
  86. package/src/lib/components/editor/PositionEditor.svelte +21 -0
  87. package/src/lib/components/editor/QuoteEditor.svelte +14 -0
  88. package/{components → src/lib/components}/editor/Switch.svelte +14 -11
  89. package/src/lib/components/editor/TableEditor.svelte +14 -0
  90. package/{components → src/lib/components}/editor/TextEditor.svelte +101 -89
  91. package/src/lib/components/editor/Toggle.svelte +47 -0
  92. package/src/lib/components/editor/Toolbar.svelte +297 -0
  93. package/{components → src/lib/components}/editor/ToolbarGroup.svelte +5 -3
  94. package/{components → src/lib/components}/editor/ToolbarSpacer.svelte +0 -0
  95. package/src/lib/components/editor/URLEditor.svelte +15 -0
  96. package/{components/editor/UndoState.d.ts → src/lib/components/editor/UndoState.ts} +3 -2
  97. package/{components → src/lib/components}/editor/icons/annotate.svg +0 -0
  98. package/{components → src/lib/components}/editor/icons/block.svg +0 -0
  99. package/{components → src/lib/components}/editor/icons/bold.svg +0 -0
  100. package/{components → src/lib/components}/editor/icons/bullets.svg +0 -0
  101. package/{components → src/lib/components}/editor/icons/callout.svg +0 -0
  102. package/{components → src/lib/components}/editor/icons/citation.svg +0 -0
  103. package/{components → src/lib/components}/editor/icons/clear.svg +0 -0
  104. package/{components → src/lib/components}/editor/icons/clipboard.svg +0 -0
  105. package/{components → src/lib/components}/editor/icons/code.svg +0 -0
  106. package/{components → src/lib/components}/editor/icons/columnafter.svg +0 -0
  107. package/{components → src/lib/components}/editor/icons/columnbefore.svg +0 -0
  108. package/{components → src/lib/components}/editor/icons/comment.svg +0 -0
  109. package/{components → src/lib/components}/editor/icons/copy.svg +0 -0
  110. package/{components → src/lib/components}/editor/icons/cut.svg +0 -0
  111. package/{components → src/lib/components}/editor/icons/define.svg +0 -0
  112. package/{components → src/lib/components}/editor/icons/deletecolumn.svg +0 -0
  113. package/{components → src/lib/components}/editor/icons/deleterow.svg +0 -0
  114. package/{components → src/lib/components}/editor/icons/footnote.svg +0 -0
  115. package/{components → src/lib/components}/editor/icons/header1.svg +0 -0
  116. package/{components → src/lib/components}/editor/icons/header2.svg +0 -0
  117. package/{components → src/lib/components}/editor/icons/header3.svg +0 -0
  118. package/{components → src/lib/components}/editor/icons/home.svg +0 -0
  119. package/{components → src/lib/components}/editor/icons/indent.svg +0 -0
  120. package/{components → src/lib/components}/editor/icons/italic.svg +0 -0
  121. package/{components → src/lib/components}/editor/icons/label.svg +0 -0
  122. package/{components → src/lib/components}/editor/icons/left.svg +0 -0
  123. package/{components → src/lib/components}/editor/icons/level.svg +0 -0
  124. package/{components → src/lib/components}/editor/icons/link.svg +0 -0
  125. package/{components → src/lib/components}/editor/icons/list.svg +0 -0
  126. package/{components → src/lib/components}/editor/icons/media.svg +0 -0
  127. package/{components → src/lib/components}/editor/icons/middle.svg +0 -0
  128. package/{components → src/lib/components}/editor/icons/numbers.svg +0 -0
  129. package/{components → src/lib/components}/editor/icons/paragraph.svg +0 -0
  130. package/{components → src/lib/components}/editor/icons/paste.svg +0 -0
  131. package/{components → src/lib/components}/editor/icons/quote.svg +0 -0
  132. package/{components → src/lib/components}/editor/icons/redo.svg +0 -0
  133. package/{components → src/lib/components}/editor/icons/right.svg +0 -0
  134. package/{components → src/lib/components}/editor/icons/rowabove.svg +0 -0
  135. package/{components → src/lib/components}/editor/icons/rowbelow.svg +0 -0
  136. package/{components → src/lib/components}/editor/icons/rule.svg +0 -0
  137. package/{components → src/lib/components}/editor/icons/sub.svg +0 -0
  138. package/{components → src/lib/components}/editor/icons/super.svg +0 -0
  139. package/{components → src/lib/components}/editor/icons/table.svg +0 -0
  140. package/{components → src/lib/components}/editor/icons/text.svg +0 -0
  141. package/{components → src/lib/components}/editor/icons/time.svg +0 -0
  142. package/{components → src/lib/components}/editor/icons/undo.svg +0 -0
  143. package/{components → src/lib/components}/editor/icons/unindent.svg +0 -0
  144. package/{components → src/lib/components}/editor/icons/unlink.svg +0 -0
  145. package/{components → src/lib/components}/page/Acknowledgements.svelte +19 -10
  146. package/src/lib/components/page/Authors.svelte +92 -0
  147. package/src/lib/components/page/BookLoader.svelte +77 -0
  148. package/src/lib/components/page/BulkReferenceEditor.svelte +86 -0
  149. package/src/lib/components/page/Chapter.svelte +449 -0
  150. package/src/lib/components/page/ChapterContext.ts +13 -0
  151. package/{components → src/lib/components}/page/ChapterNumber.svelte +0 -0
  152. package/{components → src/lib/components}/page/ChapterTitle.svelte +4 -2
  153. package/src/lib/components/page/Contexts.ts +176 -0
  154. package/{components → src/lib/components}/page/DefinitionView.svelte +52 -37
  155. package/{components → src/lib/components}/page/Description.svelte +15 -7
  156. package/src/lib/components/page/Edition.svelte +189 -0
  157. package/src/lib/components/page/EditionLoader.svelte +123 -0
  158. package/{components → src/lib/components}/page/Editions.svelte +22 -18
  159. package/{components → src/lib/components}/page/Glossary.svelte +33 -28
  160. package/{components → src/lib/components}/page/Header.svelte +59 -52
  161. package/{components → src/lib/components}/page/Index.svelte +48 -41
  162. package/{components → src/lib/components}/page/Instructions.svelte +2 -1
  163. package/{components → src/lib/components}/page/License.svelte +17 -9
  164. package/{components → src/lib/components}/page/Loading.svelte +0 -0
  165. package/{components → src/lib/components}/page/Media.svelte +44 -27
  166. package/{components → src/lib/components}/page/MediaPreview.svelte +3 -2
  167. package/{components → src/lib/components}/page/Muted.svelte +0 -0
  168. package/{components → src/lib/components}/page/Outline.svelte +140 -110
  169. package/src/lib/components/page/Page.svelte +94 -0
  170. package/{components → src/lib/components}/page/PageHeader.svelte +2 -1
  171. package/{components → src/lib/components}/page/PageParagraph.svelte +0 -0
  172. package/src/lib/components/page/PossibleChapter.svelte +16 -0
  173. package/src/lib/components/page/PossibleReference.svelte +14 -0
  174. package/{components → src/lib/components}/page/Print.svelte +5 -3
  175. package/{components → src/lib/components}/page/Publish.svelte +59 -52
  176. package/{components → src/lib/components}/page/Reference.svelte +39 -30
  177. package/{components → src/lib/components}/page/References.svelte +18 -14
  178. package/{components → src/lib/components}/page/Rows.svelte +0 -0
  179. package/src/lib/components/page/Search.svelte +153 -0
  180. package/{components → src/lib/components}/page/Status.svelte +5 -3
  181. package/{components → src/lib/components}/page/SubdomainEditor.svelte +16 -13
  182. package/{components → src/lib/components}/page/TableOfContents.svelte +79 -68
  183. package/src/lib/components/page/TableOfContentsImage.svelte +22 -0
  184. package/{components → src/lib/components}/page/TableOfContentsRow.svelte +34 -24
  185. package/{components → src/lib/components}/page/ThemeEditor.svelte +44 -33
  186. package/{components → src/lib/components}/page/ThemeEditorPreview.svelte +21 -12
  187. package/src/lib/components/page/ThemeSetEditor.svelte +21 -0
  188. package/{components → src/lib/components}/page/ThemeVariableEditor.svelte +18 -14
  189. package/{components → src/lib/components}/page/Title.svelte +0 -0
  190. package/{components → src/lib/components}/page/Unknown.svelte +10 -8
  191. package/{components/page/margins.js → src/lib/components/page/margins.ts} +79 -46
  192. package/{index.js → src/lib/index.js} +0 -0
  193. package/src/lib/models/CRUD.ts +469 -0
  194. package/{models/Firebase.js → src/lib/models/Firebase.ts} +26 -16
  195. package/src/lib/models/book/Book.ts +283 -0
  196. package/src/lib/models/book/BookMedia.ts +182 -0
  197. package/src/lib/models/book/BookSaveStatus.ts +8 -0
  198. package/src/lib/models/book/Chapter.ts +462 -0
  199. package/{models/book/ChapterID.js → src/lib/models/book/ChapterID.ts} +1 -0
  200. package/src/lib/models/book/Definition.ts +2 -0
  201. package/src/lib/models/book/Edition.ts +1216 -0
  202. package/src/lib/models/book/Reference.ts +171 -0
  203. package/{models/book/Schema.js → src/lib/models/book/Schema.ts} +1 -0
  204. package/{models/book/Theme.js → src/lib/models/book/Theme.ts} +111 -6
  205. package/{models/book/ThemeColors.d.ts → src/lib/models/book/ThemeColors.ts} +6 -0
  206. package/{models/book/Words.js → src/lib/models/book/Words.ts} +1 -0
  207. package/{models/chapter/AtomNode.js → src/lib/models/chapter/AtomNode.ts} +30 -10
  208. package/{models/chapter/BlockNode.js → src/lib/models/chapter/BlockNode.ts} +80 -47
  209. package/src/lib/models/chapter/BlocksNode.test.ts +867 -0
  210. package/{models/chapter/BlocksNode.js → src/lib/models/chapter/BlocksNode.ts} +571 -359
  211. package/{models/chapter/Bookkeeping.d.ts → src/lib/models/chapter/Bookkeeping.ts} +0 -0
  212. package/src/lib/models/chapter/CalloutNode.ts +79 -0
  213. package/{models/chapter/Caret.js → src/lib/models/chapter/Caret.ts} +50 -26
  214. package/src/lib/models/chapter/ChapterNode.ts +169 -0
  215. package/{models/chapter/CitationsNode.js → src/lib/models/chapter/CitationsNode.ts} +17 -10
  216. package/{models/chapter/CodeNode.js → src/lib/models/chapter/CodeNode.ts} +125 -62
  217. package/src/lib/models/chapter/CommentNode.ts +61 -0
  218. package/{models/chapter/DefinitionNode.js → src/lib/models/chapter/DefinitionNode.ts} +14 -8
  219. package/src/lib/models/chapter/Edit.ts +6 -0
  220. package/src/lib/models/chapter/EmbedNode.ts +257 -0
  221. package/{models/chapter/ErrorNode.js → src/lib/models/chapter/ErrorNode.ts} +15 -8
  222. package/src/lib/models/chapter/FootnoteNode.ts +59 -0
  223. package/src/lib/models/chapter/FormatNode.test.ts +137 -0
  224. package/{models/chapter/FormatNode.js → src/lib/models/chapter/FormatNode.ts} +443 -262
  225. package/{models/chapter/InlineCodeNode.js → src/lib/models/chapter/InlineCodeNode.ts} +17 -9
  226. package/{models/chapter/LabelNode.js → src/lib/models/chapter/LabelNode.ts} +26 -10
  227. package/{models/chapter/LinkNode.js → src/lib/models/chapter/LinkNode.ts} +12 -7
  228. package/{models/chapter/ListNode.test.js → src/lib/models/chapter/ListNode.test.ts} +57 -20
  229. package/{models/chapter/ListNode.js → src/lib/models/chapter/ListNode.ts} +277 -200
  230. package/src/lib/models/chapter/MetadataNode.ts +44 -0
  231. package/{models → src/lib/models}/chapter/Node.test.js +0 -0
  232. package/{models/chapter/Node.js → src/lib/models/chapter/Node.ts} +155 -71
  233. package/src/lib/models/chapter/ParagraphNode.test.ts +54 -0
  234. package/{models/chapter/ParagraphNode.js → src/lib/models/chapter/ParagraphNode.ts} +95 -58
  235. package/{models/chapter/Parser.test.js → src/lib/models/chapter/Parser.test.ts} +7 -0
  236. package/{models/chapter/Parser.js → src/lib/models/chapter/Parser.ts} +369 -184
  237. package/{models/chapter/Position.d.ts → src/lib/models/chapter/Position.ts} +0 -0
  238. package/src/lib/models/chapter/QuoteNode.ts +135 -0
  239. package/{models/chapter/RootNode.d.ts → src/lib/models/chapter/RootNode.ts} +2 -0
  240. package/{models/chapter/RuleNode.js → src/lib/models/chapter/RuleNode.ts} +9 -6
  241. package/{models/chapter/TableNode.test.js → src/lib/models/chapter/TableNode.test.ts} +27 -10
  242. package/{models/chapter/TableNode.js → src/lib/models/chapter/TableNode.ts} +141 -82
  243. package/{models/chapter/TextNode.test.js → src/lib/models/chapter/TextNode.test.ts} +2 -0
  244. package/{models/chapter/TextNode.js → src/lib/models/chapter/TextNode.ts} +117 -65
  245. package/{util/getSubdomain.js → src/lib/util/getSubdomain.ts} +14 -8
  246. package/{util/isMobile.js → src/lib/util/isMobile.ts} +1 -0
  247. package/{util/mineReference.js → src/lib/util/mineReference.ts} +45 -25
  248. package/{util/scrollToEyeLevel.js → src/lib/util/scrollToEyeLevel.ts} +4 -2
  249. package/src/params/edition.ts +3 -0
  250. package/src/routes/+error.svelte +12 -0
  251. package/src/routes/+layout.svelte +241 -0
  252. package/src/routes/+page.svelte +43 -0
  253. package/src/routes/Footer.svelte +0 -0
  254. package/src/routes/Header.svelte +112 -0
  255. package/src/routes/[bookid]/+layout.svelte +5 -0
  256. package/src/routes/[bookid]/[[editionid=edition]]/+error.svelte +14 -0
  257. package/src/routes/[bookid]/[[editionid=edition]]/+layout.svelte +7 -0
  258. package/src/routes/[bookid]/[[editionid=edition]]/+page.svelte +5 -0
  259. package/src/routes/[bookid]/[[editionid=edition]]/[chapterid]/+page.svelte +5 -0
  260. package/src/routes/[bookid]/[[editionid=edition]]/glossary/+page.svelte +5 -0
  261. package/src/routes/[bookid]/[[editionid=edition]]/index/[[letter]]/+page.svelte +5 -0
  262. package/src/routes/[bookid]/[[editionid=edition]]/media/+page.svelte +5 -0
  263. package/src/routes/[bookid]/[[editionid=edition]]/print/+page.svelte +5 -0
  264. package/src/routes/[bookid]/[[editionid=edition]]/references/+page.svelte +5 -0
  265. package/src/routes/[bookid]/[[editionid=edition]]/search/+page.svelte +5 -0
  266. package/src/routes/[bookid]/editions/+page.svelte +20 -0
  267. package/src/routes/about/+page.svelte +102 -0
  268. package/src/routes/confirm/+page.svelte +62 -0
  269. package/src/routes/email/+page.svelte +99 -0
  270. package/src/routes/login/+page.svelte +66 -0
  271. package/src/routes/read/+page.svelte +38 -0
  272. package/src/routes/write/+error.svelte +10 -0
  273. package/src/routes/write/+layout.svelte +11 -0
  274. package/src/routes/write/+page.svelte +114 -0
  275. package/src/routes/write/[bookid]/+layout.svelte +5 -0
  276. package/src/routes/write/[bookid]/[[editionid=edition]]/+layout.svelte +7 -0
  277. package/src/routes/write/[bookid]/[[editionid=edition]]/+page.svelte +5 -0
  278. package/src/routes/write/[bookid]/[[editionid=edition]]/[chapterid]/+page.svelte +5 -0
  279. package/src/routes/write/[bookid]/[[editionid=edition]]/glossary/+page.svelte +5 -0
  280. package/src/routes/write/[bookid]/[[editionid=edition]]/index/[[letter]]/+page.svelte +5 -0
  281. package/src/routes/write/[bookid]/[[editionid=edition]]/media/+page.svelte +5 -0
  282. package/src/routes/write/[bookid]/[[editionid=edition]]/print/+page.svelte +5 -0
  283. package/src/routes/write/[bookid]/[[editionid=edition]]/references/+page.svelte +5 -0
  284. package/src/routes/write/[bookid]/[[editionid=edition]]/search/+page.svelte +5 -0
  285. package/src/routes/write/[bookid]/[[editionid=edition]]/theme/+page.svelte +5 -0
  286. package/src/routes/write/[bookid]/[[editionid=edition]]/unknown/+page.svelte +5 -0
  287. package/src/routes/write/[bookid]/editions/+page.svelte +20 -0
  288. package/src/vite-env.d.ts +1 -0
  289. package/static/icons/favicon.png +0 -0
  290. package/static/icons/icon.png +0 -0
  291. package/static/icons/ios-icon.png +0 -0
  292. package/storage.rules +9 -0
  293. package/svelte.config.js +19 -0
  294. package/tsconfig.json +18 -0
  295. package/tsconfig.node.json +9 -0
  296. package/vite.config.ts +8 -0
  297. package/vite.reader.config.ts +32 -0
  298. package/components/Auth.svelte +0 -55
  299. package/components/Auth.svelte.d.ts +0 -16
  300. package/components/Authentication.js +0 -1
  301. package/components/BookPreview.svelte.d.ts +0 -18
  302. package/components/External.svelte.d.ts +0 -18
  303. package/components/Link.svelte +0 -51
  304. package/components/Link.svelte.d.ts +0 -18
  305. package/components/app/BookList.svelte.d.ts +0 -18
  306. package/components/app/Button.svelte.d.ts +0 -22
  307. package/components/app/Feedback.svelte.d.ts +0 -18
  308. package/components/app/Head.svelte.d.ts +0 -18
  309. package/components/app/Large.svelte.d.ts +0 -27
  310. package/components/app/Lead.svelte.d.ts +0 -27
  311. package/components/app/Link.svelte.d.ts +0 -20
  312. package/components/app/Options.svelte.d.ts +0 -19
  313. package/components/app/Paragraph.svelte.d.ts +0 -18
  314. package/components/app/Section.svelte.d.ts +0 -27
  315. package/components/app/Table.svelte.d.ts +0 -27
  316. package/components/app/TextInput.svelte.d.ts +0 -22
  317. package/components/chapter/Atom.svelte.d.ts +0 -19
  318. package/components/chapter/Block.svelte +0 -37
  319. package/components/chapter/Block.svelte.d.ts +0 -17
  320. package/components/chapter/Callout.svelte.d.ts +0 -17
  321. package/components/chapter/CaptionedCode.svelte.d.ts +0 -17
  322. package/components/chapter/ChapterBody.svelte.d.ts +0 -19
  323. package/components/chapter/Citations.svelte.d.ts +0 -17
  324. package/components/chapter/Code.svelte.d.ts +0 -22
  325. package/components/chapter/Comment.svelte.d.ts +0 -17
  326. package/components/chapter/Definition.svelte.d.ts +0 -17
  327. package/components/chapter/Embed.svelte.d.ts +0 -20
  328. package/components/chapter/ErrorMessage.svelte +0 -9
  329. package/components/chapter/ErrorMessage.svelte.d.ts +0 -17
  330. package/components/chapter/ExtendedPrism.d.ts +0 -2
  331. package/components/chapter/Figure.svelte.d.ts +0 -24
  332. package/components/chapter/Footnote.svelte.d.ts +0 -19
  333. package/components/chapter/Format.svelte.d.ts +0 -19
  334. package/components/chapter/InlineCode.svelte.d.ts +0 -17
  335. package/components/chapter/Label.svelte.d.ts +0 -17
  336. package/components/chapter/Link.svelte.d.ts +0 -17
  337. package/components/chapter/List.svelte.d.ts +0 -17
  338. package/components/chapter/Marginal.svelte.d.ts +0 -22
  339. package/components/chapter/Paragraph.svelte.d.ts +0 -18
  340. package/components/chapter/Positioned.svelte.d.ts +0 -19
  341. package/components/chapter/Problem.svelte.d.ts +0 -27
  342. package/components/chapter/Python.svelte +0 -128
  343. package/components/chapter/Python.svelte.d.ts +0 -18
  344. package/components/chapter/Quote.svelte.d.ts +0 -17
  345. package/components/chapter/Rule.svelte.d.ts +0 -17
  346. package/components/chapter/Table.svelte.d.ts +0 -17
  347. package/components/chapter/Text.svelte +0 -87
  348. package/components/chapter/Text.svelte.d.ts +0 -18
  349. package/components/editor/BookishEditor.svelte +0 -884
  350. package/components/editor/BookishEditor.svelte.d.ts +0 -25
  351. package/components/editor/CalloutEditor.svelte +0 -10
  352. package/components/editor/CalloutEditor.svelte.d.ts +0 -17
  353. package/components/editor/CaptionedCodeEditor.svelte.d.ts +0 -17
  354. package/components/editor/CaretContext.d.ts +0 -50
  355. package/components/editor/CaretContext.js +0 -1
  356. package/components/editor/CaretState.js +0 -1
  357. package/components/editor/CaretUtilities.js +0 -1
  358. package/components/editor/CaretView.svelte.d.ts +0 -25
  359. package/components/editor/CitationsEditor.svelte +0 -53
  360. package/components/editor/CitationsEditor.svelte.d.ts +0 -17
  361. package/components/editor/Clipboard.js +0 -1
  362. package/components/editor/Command.js +0 -1
  363. package/components/editor/Commands.d.ts +0 -3
  364. package/components/editor/ConfirmButton.svelte +0 -49
  365. package/components/editor/ConfirmButton.svelte.d.ts +0 -19
  366. package/components/editor/DefinitionEditor.svelte +0 -36
  367. package/components/editor/DefinitionEditor.svelte.d.ts +0 -17
  368. package/components/editor/EmbedEditor.svelte +0 -137
  369. package/components/editor/EmbedEditor.svelte.d.ts +0 -17
  370. package/components/editor/Icon.svelte.d.ts +0 -16
  371. package/components/editor/ImageChooser.svelte.d.ts +0 -18
  372. package/components/editor/InlineCodeEditor.svelte +0 -12
  373. package/components/editor/InlineCodeEditor.svelte.d.ts +0 -17
  374. package/components/editor/LabelEditor.svelte.d.ts +0 -17
  375. package/components/editor/LanguageEditor.svelte.d.ts +0 -17
  376. package/components/editor/LinkEditor.svelte +0 -100
  377. package/components/editor/LinkEditor.svelte.d.ts +0 -17
  378. package/components/editor/Note.svelte.d.ts +0 -27
  379. package/components/editor/Permissions.svelte.d.ts +0 -20
  380. package/components/editor/PositionEditor.svelte +0 -17
  381. package/components/editor/PositionEditor.svelte.d.ts +0 -18
  382. package/components/editor/QuoteEditor.svelte +0 -10
  383. package/components/editor/QuoteEditor.svelte.d.ts +0 -17
  384. package/components/editor/Switch.svelte.d.ts +0 -20
  385. package/components/editor/TableEditor.svelte +0 -10
  386. package/components/editor/TableEditor.svelte.d.ts +0 -17
  387. package/components/editor/TextEditor.svelte.d.ts +0 -24
  388. package/components/editor/Toggle.svelte +0 -41
  389. package/components/editor/Toggle.svelte.d.ts +0 -19
  390. package/components/editor/Toolbar.svelte +0 -249
  391. package/components/editor/Toolbar.svelte.d.ts +0 -17
  392. package/components/editor/ToolbarGroup.svelte.d.ts +0 -18
  393. package/components/editor/ToolbarSpacer.svelte.d.ts +0 -23
  394. package/components/editor/URLEditor.svelte +0 -13
  395. package/components/editor/URLEditor.svelte.d.ts +0 -18
  396. package/components/editor/UndoState.js +0 -1
  397. package/components/page/Acknowledgements.svelte.d.ts +0 -14
  398. package/components/page/Authors.svelte +0 -85
  399. package/components/page/Authors.svelte.d.ts +0 -21
  400. package/components/page/BookLoader.svelte +0 -59
  401. package/components/page/BookLoader.svelte.d.ts +0 -16
  402. package/components/page/BulkReferenceEditor.svelte +0 -63
  403. package/components/page/BulkReferenceEditor.svelte.d.ts +0 -14
  404. package/components/page/Chapter.svelte +0 -392
  405. package/components/page/Chapter.svelte.d.ts +0 -18
  406. package/components/page/ChapterContext.d.ts +0 -10
  407. package/components/page/ChapterContext.js +0 -1
  408. package/components/page/ChapterNumber.svelte.d.ts +0 -27
  409. package/components/page/ChapterTitle.svelte.d.ts +0 -18
  410. package/components/page/Contexts.d.ts +0 -47
  411. package/components/page/Contexts.js +0 -133
  412. package/components/page/DefinitionView.svelte.d.ts +0 -18
  413. package/components/page/Description.svelte.d.ts +0 -14
  414. package/components/page/Edition.svelte +0 -161
  415. package/components/page/Edition.svelte.d.ts +0 -20
  416. package/components/page/EditionLoader.svelte +0 -99
  417. package/components/page/EditionLoader.svelte.d.ts +0 -18
  418. package/components/page/Editions.svelte.d.ts +0 -14
  419. package/components/page/Glossary.svelte.d.ts +0 -14
  420. package/components/page/Header.svelte.d.ts +0 -29
  421. package/components/page/Index.svelte.d.ts +0 -14
  422. package/components/page/Instructions.svelte.d.ts +0 -18
  423. package/components/page/License.svelte.d.ts +0 -14
  424. package/components/page/Loading.svelte.d.ts +0 -23
  425. package/components/page/Media.svelte.d.ts +0 -14
  426. package/components/page/MediaPreview.svelte.d.ts +0 -19
  427. package/components/page/Muted.svelte.d.ts +0 -27
  428. package/components/page/Outline.svelte.d.ts +0 -19
  429. package/components/page/Page.svelte +0 -84
  430. package/components/page/Page.svelte.d.ts +0 -19
  431. package/components/page/PageHeader.svelte.d.ts +0 -18
  432. package/components/page/PageParagraph.svelte.d.ts +0 -27
  433. package/components/page/PossibleChapter.svelte +0 -14
  434. package/components/page/PossibleChapter.svelte.d.ts +0 -14
  435. package/components/page/PossibleReference.svelte +0 -11
  436. package/components/page/PossibleReference.svelte.d.ts +0 -18
  437. package/components/page/Print.svelte.d.ts +0 -14
  438. package/components/page/Publish.svelte.d.ts +0 -14
  439. package/components/page/Reference.svelte.d.ts +0 -17
  440. package/components/page/References.svelte.d.ts +0 -14
  441. package/components/page/Rows.svelte.d.ts +0 -27
  442. package/components/page/Search.svelte +0 -133
  443. package/components/page/Search.svelte.d.ts +0 -14
  444. package/components/page/Status.svelte.d.ts +0 -14
  445. package/components/page/SubdomainEditor.svelte.d.ts +0 -14
  446. package/components/page/TableOfContents.svelte.d.ts +0 -14
  447. package/components/page/TableOfContentsImage.svelte +0 -18
  448. package/components/page/TableOfContentsImage.svelte.d.ts +0 -16
  449. package/components/page/TableOfContentsRow.svelte.d.ts +0 -24
  450. package/components/page/ThemeEditor.svelte.d.ts +0 -14
  451. package/components/page/ThemeEditorPreview.svelte.d.ts +0 -17
  452. package/components/page/ThemeSetEditor.svelte +0 -19
  453. package/components/page/ThemeSetEditor.svelte.d.ts +0 -18
  454. package/components/page/ThemeVariableEditor.svelte.d.ts +0 -18
  455. package/components/page/Title.svelte.d.ts +0 -27
  456. package/components/page/Unknown.svelte.d.ts +0 -16
  457. package/components/page/margins.d.ts +0 -2
  458. package/index.d.ts +0 -15
  459. package/models/CRUD.d.ts +0 -27
  460. package/models/CRUD.js +0 -262
  461. package/models/Firebase.d.ts +0 -5
  462. package/models/book/Book.d.ts +0 -61
  463. package/models/book/Book.js +0 -135
  464. package/models/book/BookMedia.d.ts +0 -23
  465. package/models/book/BookMedia.js +0 -108
  466. package/models/book/BookSaveStatus.d.ts +0 -7
  467. package/models/book/BookSaveStatus.js +0 -8
  468. package/models/book/Chapter.d.ts +0 -81
  469. package/models/book/Chapter.js +0 -212
  470. package/models/book/ChapterID.d.ts +0 -10
  471. package/models/book/Definition.d.ts +0 -6
  472. package/models/book/Definition.js +0 -1
  473. package/models/book/Edition.d.ts +0 -139
  474. package/models/book/Edition.js +0 -620
  475. package/models/book/Reference.d.ts +0 -24
  476. package/models/book/Reference.js +0 -78
  477. package/models/book/Schema.d.ts +0 -174
  478. package/models/book/Theme.d.ts +0 -113
  479. package/models/book/ThemeColors.js +0 -1
  480. package/models/book/Words.d.ts +0 -2
  481. package/models/chapter/AtomNode.d.ts +0 -18
  482. package/models/chapter/BlockNode.d.ts +0 -20
  483. package/models/chapter/BlocksNode.d.ts +0 -50
  484. package/models/chapter/BlocksNode.test.d.ts +0 -1
  485. package/models/chapter/BlocksNode.test.js +0 -568
  486. package/models/chapter/Bookkeeping.js +0 -1
  487. package/models/chapter/CalloutNode.d.ts +0 -17
  488. package/models/chapter/CalloutNode.js +0 -58
  489. package/models/chapter/Caret.d.ts +0 -23
  490. package/models/chapter/ChapterNode.d.ts +0 -34
  491. package/models/chapter/ChapterNode.js +0 -117
  492. package/models/chapter/CitationsNode.d.ts +0 -16
  493. package/models/chapter/CodeNode.d.ts +0 -35
  494. package/models/chapter/CommentNode.d.ts +0 -18
  495. package/models/chapter/CommentNode.js +0 -48
  496. package/models/chapter/DefinitionNode.d.ts +0 -12
  497. package/models/chapter/Edit.d.ts +0 -7
  498. package/models/chapter/Edit.js +0 -1
  499. package/models/chapter/EmbedNode.d.ts +0 -45
  500. package/models/chapter/EmbedNode.js +0 -168
  501. package/models/chapter/ErrorNode.d.ts +0 -17
  502. package/models/chapter/FootnoteNode.d.ts +0 -18
  503. package/models/chapter/FootnoteNode.js +0 -47
  504. package/models/chapter/FormatNode.d.ts +0 -60
  505. package/models/chapter/FormatNode.test.d.ts +0 -1
  506. package/models/chapter/FormatNode.test.js +0 -96
  507. package/models/chapter/InlineCodeNode.d.ts +0 -12
  508. package/models/chapter/LabelNode.d.ts +0 -17
  509. package/models/chapter/LinkNode.d.ts +0 -12
  510. package/models/chapter/ListNode.d.ts +0 -51
  511. package/models/chapter/ListNode.test.d.ts +0 -1
  512. package/models/chapter/MetadataNode.d.ts +0 -17
  513. package/models/chapter/MetadataNode.js +0 -32
  514. package/models/chapter/Node.d.ts +0 -38
  515. package/models/chapter/Node.test.d.ts +0 -1
  516. package/models/chapter/ParagraphNode.d.ts +0 -33
  517. package/models/chapter/ParagraphNode.test.d.ts +0 -1
  518. package/models/chapter/ParagraphNode.test.js +0 -30
  519. package/models/chapter/Parser.d.ts +0 -75
  520. package/models/chapter/Parser.test.d.ts +0 -1
  521. package/models/chapter/Position.js +0 -1
  522. package/models/chapter/QuoteNode.d.ts +0 -25
  523. package/models/chapter/QuoteNode.js +0 -99
  524. package/models/chapter/RootNode.js +0 -1
  525. package/models/chapter/RuleNode.d.ts +0 -15
  526. package/models/chapter/TableNode.d.ts +0 -37
  527. package/models/chapter/TableNode.test.d.ts +0 -1
  528. package/models/chapter/TextNode.d.ts +0 -36
  529. package/models/chapter/TextNode.test.d.ts +0 -1
  530. package/util/getSubdomain.d.ts +0 -3
  531. package/util/isMobile.d.ts +0 -2
  532. package/util/mineReference.d.ts +0 -4
  533. package/util/scrollToEyeLevel.d.ts +0 -2
@@ -0,0 +1,469 @@
1
+ import { db, functions } from './Firebase';
2
+ import {
3
+ collection,
4
+ getDocs,
5
+ getDoc,
6
+ setDoc,
7
+ doc,
8
+ addDoc,
9
+ query,
10
+ where,
11
+ deleteDoc,
12
+ DocumentReference,
13
+ onSnapshot,
14
+ QueryFieldFilterConstraint,
15
+ } from 'firebase/firestore';
16
+ import { httpsCallable } from 'firebase/functions';
17
+ import Edition from './book/Edition';
18
+ import type { EditionSpecification } from './book/Edition';
19
+ import Book, { type EditionInfo } from './book/Book';
20
+ import type { BookSpecification } from './book/Book';
21
+ import type { Unsubscribe } from 'firebase/auth';
22
+
23
+ function editionPath(bookID: string, editionID: string) {
24
+ return `books/${bookID}/editions/${editionID}`;
25
+ }
26
+
27
+ const NO_DATABASE_CONNECTION = 'Not connected to database';
28
+
29
+ ///////////////
30
+ //// READ BOOKS
31
+ ///////////////
32
+
33
+ function listenToBooks(
34
+ constraint: QueryFieldFilterConstraint,
35
+ react: (books: Book[]) => void
36
+ ): Unsubscribe {
37
+ if (!db) throw NO_DATABASE_CONNECTION;
38
+ try {
39
+ return onSnapshot(
40
+ query(collection(db, 'books'), constraint),
41
+ (snapshot) =>
42
+ react(
43
+ snapshot.empty
44
+ ? []
45
+ : snapshot.docs.map((doc) =>
46
+ Book.fromJSON(
47
+ doc.ref,
48
+ doc.data() as BookSpecification
49
+ )
50
+ )
51
+ )
52
+ );
53
+ } catch (err) {
54
+ throw 'Issue querying database';
55
+ }
56
+ }
57
+
58
+ export function listenToPublishedBooks(
59
+ react: (books: Book[]) => void
60
+ ): Unsubscribe {
61
+ return listenToBooks(where('published', '==', true), react);
62
+ }
63
+
64
+ export function listenToEditableBooks(
65
+ userID: string,
66
+ react: (books: Book[]) => void
67
+ ): Unsubscribe {
68
+ return listenToBooks(where('uids', 'array-contains', userID), react);
69
+ }
70
+
71
+ export function listenToPartiallyEditableBooks(
72
+ userID: string,
73
+ react: (books: Book[]) => void
74
+ ): Unsubscribe {
75
+ return listenToBooks(where('readuids', 'array-contains', userID), react);
76
+ }
77
+
78
+ export function listenToBooksByName(
79
+ name: string,
80
+ react: (book: Book[]) => void
81
+ ): Unsubscribe {
82
+ return listenToBooks(where('domain', '==', name), react);
83
+ }
84
+
85
+ export function listenToBookWithID(
86
+ id: string,
87
+ react: (book: Book | null) => void
88
+ ): Unsubscribe {
89
+ if (!db) throw NO_DATABASE_CONNECTION;
90
+ const ref = doc(db, 'books', id);
91
+ return onSnapshot(doc(db, 'books', id), (doc) => {
92
+ if (!doc.metadata.hasPendingWrites)
93
+ react(
94
+ doc.exists()
95
+ ? Book.fromJSON(ref, doc.data() as BookSpecification)
96
+ : null
97
+ );
98
+ });
99
+ }
100
+
101
+ export function listenToEdition(
102
+ bookID: string,
103
+ editionID: string,
104
+ react: (edition: Edition | null) => void
105
+ ): Unsubscribe {
106
+ if (!db) throw NO_DATABASE_CONNECTION;
107
+
108
+ return onSnapshot(
109
+ doc(db, 'books', bookID, 'editions', editionID),
110
+ (doc) => {
111
+ if (!doc.metadata.hasPendingWrites)
112
+ react(
113
+ doc.exists()
114
+ ? Edition.fromJSON(
115
+ doc.ref,
116
+ doc.data() as EditionSpecification
117
+ )
118
+ : null
119
+ );
120
+ }
121
+ );
122
+ }
123
+
124
+ export function listenToChapters(
125
+ bookID: string,
126
+ editionID: string,
127
+ react: (chapters: [DocumentReference, string][]) => void
128
+ ): Unsubscribe {
129
+ if (!db) throw NO_DATABASE_CONNECTION;
130
+
131
+ return onSnapshot(
132
+ collection(db, 'books', bookID, 'editions', editionID, 'chapters'),
133
+ (docs) => {
134
+ const chapters: [DocumentReference, string][] = [];
135
+ docs.forEach((doc) => {
136
+ chapters.push([doc.ref, doc.data().text]);
137
+ });
138
+ react(chapters);
139
+ }
140
+ );
141
+ }
142
+
143
+ /////////////////
144
+ //// MANAGE USERS
145
+ /////////////////
146
+
147
+ /** Hit the authentication database to get user emails. */
148
+ export async function getUserEmails(
149
+ uids: string[]
150
+ ): Promise<Map<string, string> | null> {
151
+ if (!functions)
152
+ throw Error("Can't publish, no connection to Firebase functions.");
153
+
154
+ const getUserEmails = httpsCallable<
155
+ { uids: string[] },
156
+ Record<string, string>
157
+ >(functions, 'getUserEmails');
158
+
159
+ const result = await getUserEmails({
160
+ uids,
161
+ });
162
+
163
+ return new Map(Object.entries(result.data));
164
+ }
165
+
166
+ export async function createUser(email: string): Promise<string | null> {
167
+ if (!functions)
168
+ throw Error("Can't publish, no connection to Firebase functions.");
169
+
170
+ const createUserWithEmail = httpsCallable<{ email: string }, string>(
171
+ functions,
172
+ 'createUserWithEmail'
173
+ );
174
+
175
+ const result = await createUserWithEmail({
176
+ email,
177
+ });
178
+
179
+ return result.data;
180
+ }
181
+
182
+ export async function createBook(userID: string): Promise<string> {
183
+ if (!db) throw Error("Can't create book, not connected to Firebase.");
184
+
185
+ // Create a new book
186
+ const newBookData: BookSpecification = {
187
+ title: 'Untitled',
188
+ authors: [],
189
+ description: '',
190
+ cover: null,
191
+ published: false,
192
+ domain: null,
193
+ editions: [],
194
+ uids: [userID],
195
+ readuids: [],
196
+ };
197
+
198
+ // Create the book
199
+ const bookRef = await addDoc(collection(db, 'books'), newBookData);
200
+
201
+ // Create a model to store it.
202
+ let book = Book.fromJSON(bookRef, newBookData);
203
+
204
+ // Make a new default edition with a single chapter with this user id.
205
+ let newEdition = new Edition(
206
+ bookRef,
207
+ undefined,
208
+ [],
209
+ 'Untitled',
210
+ [],
211
+ 1,
212
+ '',
213
+ null,
214
+ {},
215
+ '',
216
+ [],
217
+ 'All rights reserved.',
218
+ '',
219
+ [],
220
+ {},
221
+ {},
222
+ {},
223
+ {},
224
+ null,
225
+ null,
226
+ {}
227
+ ).withNewChapter();
228
+
229
+ // Add the edition to the editions collection in the database so we can get an edition ref.
230
+ const editionRef = await addDoc(
231
+ collection(db, 'books', bookRef.id, 'editions'),
232
+ newEdition.toObject()
233
+ );
234
+
235
+ // Remember the ref.
236
+ newEdition = newEdition.withRef(editionRef);
237
+
238
+ // Now replicate the edition info in the book. We dodge type checking here because we know with certainty
239
+ // that the ref was just added the line before.
240
+ const info = newEdition.getInfo();
241
+ if (info) book = book.withEditions([info]);
242
+
243
+ // Update the book with the edition info.
244
+ await updateBook(book);
245
+
246
+ // Update all of the changes to the edition in Firestore, persisting the refs and chapter text.
247
+ await updateEdition(undefined, newEdition);
248
+
249
+ // Return the book id
250
+ return bookRef.id;
251
+ }
252
+
253
+ export async function createNewEdition(book: Book): Promise<Book> {
254
+ if (!db) throw Error("Can't publish draft, no Firebase connection.");
255
+
256
+ // Get the latest draft.
257
+ const latestEditionID = book.getLatestEditionID();
258
+ if (latestEditionID === undefined) throw 'No editions on this book';
259
+
260
+ const latestDraftDoc = await getDoc(
261
+ doc(db, 'books', book.ref.id, 'editions', latestEditionID)
262
+ );
263
+ const latestDraft = latestDraftDoc.exists()
264
+ ? latestDraftDoc.data()
265
+ : undefined;
266
+
267
+ if (latestDraft === undefined) return book;
268
+
269
+ // Make a copy without chapter and edition refs, because we want to create new ones,
270
+ // and with an incremented edition number.
271
+ const newEdition = latestDraft.withoutRefs();
272
+
273
+ // Create a copy of the existing draft as a new edition.
274
+ const newEditionRef = await addDoc(
275
+ collection(db, 'editions'),
276
+ newEdition.toObject()
277
+ );
278
+
279
+ // Create the edition, creating chapter text as necessary, using the edition sync function.
280
+ updateEdition(undefined, newEdition.withRef(newEditionRef));
281
+
282
+ // Put the new edition in the book.
283
+ book = book.withEditions([
284
+ newEdition.getInfo() as EditionInfo,
285
+ ...book.getEditions(),
286
+ ]);
287
+
288
+ // Update the book.
289
+ updateBook(book);
290
+
291
+ return book;
292
+ }
293
+
294
+ export async function updateLock(
295
+ edition: Edition,
296
+ uid: string,
297
+ content: string,
298
+ lock: boolean
299
+ ): Promise<boolean> {
300
+ if (!db) throw NO_DATABASE_CONNECTION;
301
+ if (edition.editionRef === undefined) return false;
302
+
303
+ if (lock && edition.hasLease(uid, content)) return true;
304
+ if (!lock && !edition.hasLease(uid, content)) return true;
305
+
306
+ await setDoc(
307
+ doc(db, editionPath(edition.bookRef.id, edition.editionRef.id)),
308
+ edition.withLock(uid, content, lock).toObject()
309
+ );
310
+ return lock;
311
+ }
312
+
313
+ /**
314
+ * Persists the edition in the database, creating and deleting chapters as necessary.
315
+ * returns a map of DocumentReferences for new chapters so they can be persisted client side.
316
+ */
317
+ export async function updateEdition(
318
+ previousEdition: Edition | undefined,
319
+ newEdition: Edition
320
+ ): Promise<Map<string, DocumentReference>> {
321
+ if (!db) throw Error("Can't update edition, not connected to Firebase.");
322
+
323
+ // Get the reference to the edition, fail if we don't have one.
324
+ const editionRef = newEdition.getEditionRef();
325
+ if (!editionRef) throw Error('Book given has no ID');
326
+
327
+ const newChapterRefs = new Map<string, DocumentReference>();
328
+
329
+ // Create any new chapters that aren't in the current edition, and update text if it changed.
330
+ for (const newChapter of newEdition.chapters) {
331
+ if (newChapter.ref === undefined) {
332
+ // Make the new chapter's text.
333
+ const newChapterRef = await addDoc(
334
+ collection(
335
+ db,
336
+ editionPath(newEdition.bookRef.id, editionRef.id),
337
+ 'chapters'
338
+ ),
339
+ { text: newChapter.text }
340
+ );
341
+
342
+ // Add the ref of the new chapter to the revised chapter.
343
+ newEdition = newEdition.withRevisedChapter(
344
+ newChapter,
345
+ newChapter.withRef(newChapterRef)
346
+ );
347
+
348
+ // Map the chapter ref to it's id.
349
+ newChapterRefs.set(newChapter.id, newChapterRef);
350
+ }
351
+ // If we have a previous version, did the text change? If so, update it.
352
+ else {
353
+ const previousChapter =
354
+ previousEdition === undefined
355
+ ? undefined
356
+ : previousEdition.getChapterByRef(newChapter.ref);
357
+ if (
358
+ previousChapter === undefined ||
359
+ newChapter.text !== previousChapter.text
360
+ ) {
361
+ await setDoc(
362
+ doc(
363
+ db,
364
+ editionPath(newEdition.bookRef.id, editionRef.id),
365
+ 'chapters',
366
+ newChapter.ref.id
367
+ ),
368
+ { text: newChapter.text }
369
+ );
370
+ }
371
+ }
372
+ }
373
+
374
+ // Remove any chapters from Firebase that are removed.
375
+ if (previousEdition) {
376
+ for (const previousChapter of previousEdition.chapters) {
377
+ if (
378
+ previousChapter.ref &&
379
+ newEdition.getChapterByRef(previousChapter.ref) === undefined
380
+ ) {
381
+ await deleteDoc(previousChapter.ref);
382
+ }
383
+ }
384
+ }
385
+
386
+ // If the edition's summary info changed, update it.
387
+ if (previousEdition !== undefined) {
388
+ const previousInfo = previousEdition.getInfo();
389
+ const newInfo = newEdition.getInfo();
390
+ if (previousInfo && newInfo) {
391
+ const previousKeys = Object.keys(
392
+ previousInfo
393
+ ) as (keyof EditionInfo)[];
394
+ const newKeys = Object.keys(newInfo) as (keyof EditionInfo)[];
395
+ if (
396
+ previousKeys.length !== newKeys.length ||
397
+ !previousKeys.every((key) => previousInfo[key] === newInfo[key])
398
+ ) {
399
+ const bookDoc = await getDoc(
400
+ doc(db, 'books', newEdition.bookRef.id)
401
+ );
402
+ if (!bookDoc.exists()) throw Error('Book does not exist');
403
+ const book = Book.fromJSON(
404
+ newEdition.bookRef,
405
+ bookDoc.data() as BookSpecification
406
+ );
407
+ updateBook(
408
+ book.withRevisedEdition(previousEdition, newEdition)
409
+ );
410
+ }
411
+ }
412
+ }
413
+
414
+ // Finally, update the edition's document.
415
+ await setDoc(
416
+ doc(db, editionPath(newEdition.bookRef.id, editionRef.id)),
417
+ newEdition.toObject()
418
+ );
419
+
420
+ return newChapterRefs;
421
+ }
422
+
423
+ export async function updateBook(book: Book): Promise<void> {
424
+ if (!db) throw Error("Can't update book, not connected to Firebase.");
425
+
426
+ await setDoc(doc(db, 'books', book.getRefID()), book.toJSON());
427
+ }
428
+
429
+ export async function isSubdomainAvailable(
430
+ subdomain: string,
431
+ book: Book
432
+ ): Promise<boolean> {
433
+ if (!db) throw Error('Not connected to Firebase.');
434
+
435
+ const matches = await getDocs(
436
+ query(collection(db, 'books'), where('domain', '==', subdomain))
437
+ );
438
+
439
+ return matches.empty || matches.docs[0].id === book.getRefID();
440
+ }
441
+
442
+ export async function publish(
443
+ edition: Edition
444
+ ): Promise<string | { url: string }> {
445
+ if (!db) throw Error('Cannot publish, no database connection');
446
+ if (!functions) throw Error('Cannot publish, no cloud connection');
447
+
448
+ const editionRef = edition.getEditionRef();
449
+ const bookRef = edition.getBookRef();
450
+
451
+ if (editionRef === undefined) return `Cannot publish, no edition ID`;
452
+
453
+ // Get a reference to the publishing function
454
+ const publishEdition = httpsCallable<
455
+ { bookID: string; editionID: string },
456
+ string
457
+ >(functions, 'publishEdition');
458
+
459
+ // Call the function, passing
460
+ const result = await publishEdition({
461
+ bookID: bookRef.id,
462
+ editionID: editionRef.id,
463
+ });
464
+
465
+ return result.data;
466
+
467
+ // Update the edition's published status in the book.
468
+ // await updateBook(book.withEditionAsPublished(true, index));
469
+ }
@@ -3,34 +3,44 @@ import { connectAuthEmulator, getAuth } from 'firebase/auth';
3
3
  import { connectFirestoreEmulator, getFirestore } from 'firebase/firestore';
4
4
  import { connectFunctionsEmulator, getFunctions } from 'firebase/functions';
5
5
  import { connectStorageEmulator, getStorage } from 'firebase/storage';
6
- import { PUBLIC_READER, PUBLIC_CONTEXT, PUBLIC_FIREBASE_API_KEY, PUBLIC_FIREBASE_AUTH_DOMAIN, PUBLIC_FIREBASE_PROJECT_ID, PUBLIC_FIREBASE_STORAGE_BUCKET, PUBLIC_FIREBASE_MESSAGING_SENDER_ID, PUBLIC_FIREBASE_APP_ID, } from '$env/static/public';
6
+ import {
7
+ PUBLIC_READER,
8
+ PUBLIC_CONTEXT,
9
+ PUBLIC_FIREBASE_API_KEY,
10
+ PUBLIC_FIREBASE_AUTH_DOMAIN,
11
+ PUBLIC_FIREBASE_PROJECT_ID,
12
+ PUBLIC_FIREBASE_STORAGE_BUCKET,
13
+ PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
14
+ PUBLIC_FIREBASE_APP_ID,
15
+ } from '$env/static/public';
16
+
7
17
  const isReader = PUBLIC_READER === 'true';
18
+
8
19
  // Some feedback about context
9
20
  if (!isReader && PUBLIC_CONTEXT !== 'prod')
10
21
  console.log(`*** ${PUBLIC_CONTEXT.toLocaleUpperCase()} ***`);
22
+
11
23
  // Initialize Firebase using the environment variables provided at build time.
12
24
  // Only do this if we have environment variables defined. (We won't in the standalone Reader).
13
25
  export const app = isReader
14
26
  ? undefined
15
27
  : initializeApp({
16
- apiKey: PUBLIC_FIREBASE_API_KEY,
17
- authDomain: PUBLIC_FIREBASE_AUTH_DOMAIN,
18
- projectId: PUBLIC_FIREBASE_PROJECT_ID,
19
- storageBucket: PUBLIC_FIREBASE_STORAGE_BUCKET,
20
- messagingSenderId: PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
21
- appId: PUBLIC_FIREBASE_APP_ID,
22
- });
28
+ apiKey: PUBLIC_FIREBASE_API_KEY,
29
+ authDomain: PUBLIC_FIREBASE_AUTH_DOMAIN,
30
+ projectId: PUBLIC_FIREBASE_PROJECT_ID,
31
+ storageBucket: PUBLIC_FIREBASE_STORAGE_BUCKET,
32
+ messagingSenderId: PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
33
+ appId: PUBLIC_FIREBASE_APP_ID,
34
+ });
35
+
23
36
  export const auth = isReader ? undefined : getAuth();
24
37
  export const db = isReader ? undefined : getFirestore();
25
38
  export const storage = isReader ? undefined : getStorage();
26
39
  export const functions = isReader ? undefined : getFunctions();
40
+
27
41
  if (!isReader && PUBLIC_CONTEXT === 'local') {
28
- if (db)
29
- connectFirestoreEmulator(db, 'localhost', 8080);
30
- if (auth)
31
- connectAuthEmulator(auth, 'http://localhost:9099');
32
- if (storage)
33
- connectStorageEmulator(storage, 'localhost', 9199);
34
- if (functions)
35
- connectFunctionsEmulator(functions, 'localhost', 5001);
42
+ if (db) connectFirestoreEmulator(db, 'localhost', 8080);
43
+ if (auth) connectAuthEmulator(auth, 'http://localhost:9099');
44
+ if (storage) connectStorageEmulator(storage, 'localhost', 9199);
45
+ if (functions) connectFunctionsEmulator(functions, 'localhost', 5001);
36
46
  }