├── .devcontainer ├── Dockerfile ├── README.md ├── devcontainer.json └── setup.sh ├── .editorconfig ├── .envrc ├── .github └── workflows │ ├── ci.yml │ └── deploy.yml ├── .gitignore ├── .netlify-env ├── package.json ├── pnpm-lock.yaml └── pnpm-workspace.yaml ├── .npmrc ├── .rustfmt.toml ├── Cargo.lock ├── Cargo.nix ├── Cargo.toml ├── LICENSE ├── README.md ├── biome.json ├── dev-docs ├── .envrc ├── .gitignore ├── README.md ├── assets │ └── .gitignore ├── checksums.txt ├── forest.toml ├── forester ├── serve.sh ├── shell.nix ├── theme │ ├── .gitignore │ ├── LICENSES │ │ ├── CC0-1.0.txt │ │ ├── MIT.txt │ │ └── OFL-1.1.txt │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── bundle-js.sh │ ├── core.xsl │ ├── custom.css │ ├── default.xsl │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ ├── fonts │ │ ├── KaTeX_AMS-Regular.ttf │ │ ├── KaTeX_AMS-Regular.woff │ │ ├── KaTeX_AMS-Regular.woff2 │ │ ├── KaTeX_Caligraphic-Bold.ttf │ │ ├── KaTeX_Caligraphic-Bold.woff │ │ ├── KaTeX_Caligraphic-Bold.woff2 │ │ ├── KaTeX_Caligraphic-Regular.ttf │ │ ├── KaTeX_Caligraphic-Regular.woff │ │ ├── KaTeX_Caligraphic-Regular.woff2 │ │ ├── KaTeX_Fraktur-Bold.ttf │ │ ├── KaTeX_Fraktur-Bold.woff │ │ ├── KaTeX_Fraktur-Bold.woff2 │ │ ├── KaTeX_Fraktur-Regular.ttf │ │ ├── KaTeX_Fraktur-Regular.woff │ │ ├── KaTeX_Fraktur-Regular.woff2 │ │ ├── KaTeX_Main-Bold.ttf │ │ ├── KaTeX_Main-Bold.woff │ │ ├── KaTeX_Main-Bold.woff2 │ │ ├── KaTeX_Main-BoldItalic.ttf │ │ ├── KaTeX_Main-BoldItalic.woff │ │ ├── KaTeX_Main-BoldItalic.woff2 │ │ ├── KaTeX_Main-Italic.ttf │ │ ├── KaTeX_Main-Italic.woff │ │ ├── KaTeX_Main-Italic.woff2 │ │ ├── KaTeX_Main-Regular.ttf │ │ ├── KaTeX_Main-Regular.woff │ │ ├── KaTeX_Main-Regular.woff2 │ │ ├── KaTeX_Math-BoldItalic.ttf │ │ ├── KaTeX_Math-BoldItalic.woff │ │ ├── KaTeX_Math-BoldItalic.woff2 │ │ ├── KaTeX_Math-Italic.ttf │ │ ├── KaTeX_Math-Italic.woff │ │ ├── KaTeX_Math-Italic.woff2 │ │ ├── KaTeX_SansSerif-Bold.ttf │ │ ├── KaTeX_SansSerif-Bold.woff │ │ ├── KaTeX_SansSerif-Bold.woff2 │ │ ├── KaTeX_SansSerif-Italic.ttf │ │ ├── KaTeX_SansSerif-Italic.woff │ │ ├── KaTeX_SansSerif-Italic.woff2 │ │ ├── KaTeX_SansSerif-Regular.ttf │ │ ├── KaTeX_SansSerif-Regular.woff │ │ ├── KaTeX_SansSerif-Regular.woff2 │ │ ├── KaTeX_Script-Regular.ttf │ │ ├── KaTeX_Script-Regular.woff │ │ ├── KaTeX_Script-Regular.woff2 │ │ ├── KaTeX_Size1-Regular.ttf │ │ ├── KaTeX_Size1-Regular.woff │ │ ├── KaTeX_Size1-Regular.woff2 │ │ ├── KaTeX_Size2-Regular.ttf │ │ ├── KaTeX_Size2-Regular.woff │ │ ├── KaTeX_Size2-Regular.woff2 │ │ ├── KaTeX_Size3-Regular.ttf │ │ ├── KaTeX_Size3-Regular.woff │ │ ├── KaTeX_Size3-Regular.woff2 │ │ ├── KaTeX_Size4-Regular.ttf │ │ ├── KaTeX_Size4-Regular.woff │ │ ├── KaTeX_Size4-Regular.woff2 │ │ ├── KaTeX_Typewriter-Regular.ttf │ │ ├── KaTeX_Typewriter-Regular.woff │ │ ├── KaTeX_Typewriter-Regular.woff2 │ │ ├── inria-sans-v14-latin_latin-ext-300.woff2 │ │ ├── inria-sans-v14-latin_latin-ext-300italic.woff2 │ │ ├── inria-sans-v14-latin_latin-ext-700.woff2 │ │ ├── inria-sans-v14-latin_latin-ext-700italic.woff2 │ │ ├── inria-sans-v14-latin_latin-ext-italic.woff2 │ │ └── inria-sans-v14-latin_latin-ext-regular.woff2 │ ├── forester.js │ ├── javascript-source │ │ └── forester.js │ ├── katex.min.css │ ├── links.xsl │ ├── metadata.xsl │ ├── package-lock.json │ ├── package.json │ ├── style.css │ └── tree.xsl ├── trees │ ├── bib-0001.tree │ ├── bib-0002.tree │ ├── bib-0003.tree │ ├── dbl-0001.tree │ ├── dbl-0002.tree │ ├── dbl-0003.tree │ ├── dbl-0004.tree │ ├── dbl-0005.tree │ ├── dbl-0006.tree │ ├── dbl-0007.tree │ ├── dbl-0008.tree │ ├── dbl-0009.tree │ ├── dbl-000A.tree │ ├── dbl-000B.tree │ ├── dbl-000C.tree │ ├── dbl-000D.tree │ ├── dbl-000E.tree │ ├── dbl-000F.tree │ ├── dbl-000G.tree │ ├── dbl-000H.tree │ ├── dbl-000I.tree │ ├── dct-0001.tree │ ├── dct-0002.tree │ ├── dct-0003.tree │ ├── dct-0004.tree │ ├── dct-0005.tree │ ├── dct-0006.tree │ ├── dct-0007.tree │ ├── dct-0008.tree │ ├── dct-0009.tree │ ├── dct-000A.tree │ ├── dct-000B.tree │ ├── dev-0001.tree │ ├── dev-0002.tree │ ├── dev-0003.tree │ ├── dev-0004.tree │ ├── dev-0005.tree │ ├── dev-0006.tree │ ├── dev-0007.tree │ ├── dev-0008.tree │ ├── dev-0009.tree │ ├── dev-000A.tree │ ├── dev-000B.tree │ ├── dev-000C.tree │ ├── dev-000D.tree │ ├── macros.tree │ ├── refs │ │ ├── acsets-2022.tree │ │ ├── alg-databases-2017.tree │ │ ├── baez-pollard-2017.tree │ │ ├── barbrook-johnson-2022.tree │ │ ├── cartesian-double-theories-2024.tree │ │ ├── double-products-2024.tree │ │ ├── grandis-2013-homological.tree │ │ ├── grandis-2019.tree │ │ ├── ologs-2012.tree │ │ ├── pisani-2024.tree │ │ ├── reg-nets-2024.tree │ │ ├── shulman-2008.tree │ │ └── stock-flow-2023.tree │ ├── thy-0001.tree │ ├── thy-0002.tree │ ├── thy-0003.tree │ ├── thy-0004.tree │ ├── thy-0005.tree │ ├── thy-0006.tree │ ├── thy-0007.tree │ ├── thy-0008.tree │ ├── thy-0009.tree │ ├── thy-000A.tree │ └── thy-000B.tree └── watch.sh ├── flake.lock ├── flake.nix ├── infrastructure ├── hosts │ ├── catcolab-next │ │ └── default.nix │ └── catcolab │ │ └── default.nix ├── modules │ ├── backend.nix │ ├── backup.nix │ └── host.nix ├── scripts │ ├── db-utils │ └── db-utils-lib.sh └── secrets │ ├── .env.next.age │ ├── .env.prod.age │ ├── rclone.conf.next.age │ ├── rclone.conf.prod.age │ └── secrets.nix ├── package.json ├── packages ├── algjulia-interop │ ├── .gitignore │ ├── Project.toml │ ├── README.md │ ├── jupyter_server.sh │ ├── make_sysimage.jl │ ├── src │ │ ├── CatColabInterop.jl │ │ ├── decapodes-service │ │ │ ├── DecapodesService.jl │ │ │ ├── analysis │ │ │ │ ├── Analysis.jl │ │ │ │ ├── initial_conditions.jl │ │ │ │ ├── ns_helper.jl │ │ │ │ └── simulation.jl │ │ │ ├── diagram.jl │ │ │ ├── geometry.jl │ │ │ └── model.jl │ │ └── kernel_support.jl │ ├── sysimage_precompile.jl │ └── test │ │ ├── Project.toml │ │ ├── runtests.jl │ │ └── test_jsons │ │ ├── diagrams │ │ ├── diffusivity_constant │ │ │ ├── analysis.json │ │ │ └── diagram.json │ │ ├── inverse_laplacian │ │ │ ├── analysis.json │ │ │ └── diagram.json │ │ ├── inverse_laplacian_longtrip │ │ │ ├── analysis.json │ │ │ └── diagram.json │ │ └── ns_vort │ │ │ ├── analysis.json │ │ │ └── diagram.json │ │ ├── diffconst_payload1.json │ │ ├── models │ │ ├── model_dec.json │ │ └── model_dec_scalar.json │ │ └── payload.json ├── automerge-doc-server │ ├── .gitignore │ ├── README.md │ ├── default.nix │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ │ ├── main.ts │ │ ├── migrations │ │ │ ├── index.ts │ │ │ └── m20250516154702_automerge_storage.ts │ │ ├── postgres_storage_adapter.test.ts │ │ ├── postgres_storage_adapter.ts │ │ ├── server.ts │ │ ├── socket.ts │ │ └── types.ts │ └── tsconfig.json ├── backend │ ├── .gitignore │ ├── .sqlx │ │ ├── query-05183554f0c9207cdd1e89a948d3da5238ede1773a9507446694e9f7b4d2b16c.json │ │ ├── query-1ddd7b172b0db3b5e7818013b6bb9e2d57dc2e2bc13e1d7faa82e48a77964dcc.json │ │ ├── query-3645a86b3df08de865372b02d588272bb950744a38d46079ca18b11e405058a3.json │ │ ├── query-3e2b3e63a36ffa59ce60f8df19157edc1dfcee0d876d4b0c22c2db24feee6a3c.json │ │ ├── query-3e5c74f41ae9d78fc24ffda059fe9de4cc04f075e43aa9f5ae8237c5cda31726.json │ │ ├── query-3e715aa995094feff20f8254dfd27323844efa31ece5d40ce8778122687cdefc.json │ │ ├── query-4f04b1b2b42a310d659df5700aa47b10a291e6e98d2b989036e8d78ee3b00afd.json │ │ ├── query-513719212b96e260e9c4ce840f716b1b6cb43563371fb35f9677fcf949827363.json │ │ ├── query-6425b7d75c5fd6482701adba8011472860299d4fc872194449e18682cfed5bab.json │ │ ├── query-84f34c3f761dbab809edf2af4104e533a26a50310c90d340fdd90d64683b6b55.json │ │ ├── query-92973a6dc72749d528465057e8bd674427db3a290d6db645dea5ac3c540167ef.json │ │ ├── query-a80368dbf3e74206cdbe08744b1d46924d0731475384201d7f2ddaf51e8e3644.json │ │ ├── query-a8934c50209e48af661186c7d1c2ff8d8f23b4d05f1a7f5783baf74165f464f1.json │ │ ├── query-a8cb9f26893bbf784cf8a71090e64c3603e238ea6786d327f64ae04aef205198.json │ │ ├── query-cca19c531258c9500e4c27e139d15f8bfea54d7fd1b08728debfcacd5de174b4.json │ │ ├── query-cd63d277bd2ae2905790e11cddb4b9bcb5b56e952b854a75dc724e1c253afcf5.json │ │ ├── query-e75b5c0a7da4bc3c0f52a62179d15289fd31d08d48d7a99d37cb1a6414656e7d.json │ │ └── query-eea510d03cc559aa11d46aafe38f57789f5c2e791800f78a751602cc8336c84f.json │ ├── Cargo.toml │ ├── README.md │ ├── default.nix │ ├── pkg │ │ ├── package.json │ │ ├── pnpm-lock.yaml │ │ ├── src │ │ │ ├── NewPermissions.ts │ │ │ ├── Paginated.ts │ │ │ ├── PermissionLevel.ts │ │ │ ├── Permissions.ts │ │ │ ├── RefContent.ts │ │ │ ├── RefDoc.ts │ │ │ ├── RefQueryParams.ts │ │ │ ├── RefStub.ts │ │ │ ├── RpcResult.ts │ │ │ ├── UserPermissions.ts │ │ │ ├── UserProfile.ts │ │ │ ├── UserSummary.ts │ │ │ ├── UsernameStatus.ts │ │ │ ├── index.ts │ │ │ └── serde_json │ │ │ │ └── JsonValue.ts │ │ └── tsconfig.json │ └── src │ │ ├── app.rs │ │ ├── auth.rs │ │ ├── document.rs │ │ ├── main.rs │ │ ├── rpc.rs │ │ ├── socket.rs │ │ └── user.rs ├── catlog-wasm │ ├── .gitignore │ ├── Cargo.toml │ ├── README.md │ ├── src │ │ ├── analyses.rs │ │ ├── lib.rs │ │ ├── model.rs │ │ ├── model_diagram.rs │ │ ├── model_morphism.rs │ │ ├── result.rs │ │ ├── theories.rs │ │ └── theory.rs │ └── tests │ │ └── web.rs ├── catlog │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ ├── dbl │ │ ├── category.rs │ │ ├── graph.rs │ │ ├── mod.rs │ │ ├── model.rs │ │ ├── model_diagram.rs │ │ ├── model_morphism.rs │ │ ├── theory.rs │ │ └── tree.rs │ │ ├── egglog_util.rs │ │ ├── lib.rs │ │ ├── one │ │ ├── category.rs │ │ ├── fp_category.rs │ │ ├── graph.rs │ │ ├── graph_algorithms.rs │ │ ├── mod.rs │ │ ├── path.rs │ │ ├── tree.rs │ │ └── tree_algorithms.rs │ │ ├── refs.rs │ │ ├── simulate │ │ ├── mod.rs │ │ └── ode │ │ │ ├── lotka_volterra.rs │ │ │ ├── mod.rs │ │ │ └── polynomial.rs │ │ ├── stdlib │ │ ├── analyses │ │ │ ├── mod.rs │ │ │ └── ode │ │ │ │ ├── lotka_volterra.rs │ │ │ │ ├── mass_action.rs │ │ │ │ └── mod.rs │ │ ├── mod.rs │ │ ├── models.rs │ │ └── theories.rs │ │ ├── validate.rs │ │ └── zero │ │ ├── alg.rs │ │ ├── column.rs │ │ ├── mod.rs │ │ ├── rig.rs │ │ └── set.rs ├── frontend │ ├── .env.development │ ├── .env.production │ ├── .env.staging │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── netlify.toml │ ├── package.json │ ├── pnpm-lock.yaml │ ├── public │ │ └── topos_icon.png │ ├── src │ │ ├── App.tsx │ │ ├── analysis │ │ │ ├── analysis_editor.tsx │ │ │ ├── context.ts │ │ │ ├── document.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── api │ │ │ ├── context.ts │ │ │ ├── document.ts │ │ │ ├── document_rpc.test.ts │ │ │ ├── index.ts │ │ │ ├── rpc.ts │ │ │ ├── types.ts │ │ │ └── user_rpc.test.ts │ │ ├── components │ │ │ ├── alert.css │ │ │ ├── alert.tsx │ │ │ ├── completions.css │ │ │ ├── completions.tsx │ │ │ ├── dialog.css │ │ │ ├── dialog.tsx │ │ │ ├── fixed_table_editor.css │ │ │ ├── fixed_table_editor.tsx │ │ │ ├── foldable.css │ │ │ ├── foldable.tsx │ │ │ ├── form.css │ │ │ ├── form.tsx │ │ │ ├── icon_button.css │ │ │ ├── icon_button.tsx │ │ │ ├── id_input.css │ │ │ ├── id_input.tsx │ │ │ ├── index.ts │ │ │ ├── inline_input.css │ │ │ ├── inline_input.tsx │ │ │ ├── json_import.css │ │ │ ├── json_import.tsx │ │ │ ├── name_input.tsx │ │ │ ├── panel.css │ │ │ ├── panel.tsx │ │ │ ├── resizable.css │ │ │ ├── resizable.tsx │ │ │ ├── rich_text_editor.css │ │ │ ├── rich_text_editor.tsx │ │ │ ├── spinner.css │ │ │ └── spinner.tsx │ │ ├── diagram │ │ │ ├── context.ts │ │ │ ├── diagram_editor.css │ │ │ ├── diagram_editor.tsx │ │ │ ├── document.ts │ │ │ ├── index.ts │ │ │ ├── morphism_cell_editor.css │ │ │ ├── morphism_cell_editor.tsx │ │ │ ├── object_cell_editor.css │ │ │ ├── object_cell_editor.tsx │ │ │ ├── object_input.tsx │ │ │ └── types.ts │ │ ├── help │ │ │ ├── credits.mdx │ │ │ ├── help_container.css │ │ │ ├── help_container.tsx │ │ │ ├── index.mdx │ │ │ ├── quick_intro.mdx │ │ │ ├── routes.ts │ │ │ ├── theories.mdx │ │ │ ├── theories.tsx │ │ │ ├── theory.tsx │ │ │ └── theory │ │ │ │ ├── causal-loop-delays.mdx │ │ │ │ ├── causal-loop.mdx │ │ │ │ ├── empty.mdx │ │ │ │ ├── indeterminate-causal-loop.mdx │ │ │ │ ├── olog.mdx │ │ │ │ ├── reg-net.mdx │ │ │ │ ├── schema.mdx │ │ │ │ ├── stock-flow.mdx │ │ │ │ └── unary-dec.mdx │ │ ├── index.css │ │ ├── index.tsx │ │ ├── model │ │ │ ├── context.ts │ │ │ ├── document.ts │ │ │ ├── index.ts │ │ │ ├── model_editor.css │ │ │ ├── model_editor.tsx │ │ │ ├── morphism_cell_editor.css │ │ │ ├── morphism_cell_editor.tsx │ │ │ ├── morphism_input.tsx │ │ │ ├── object_cell_editor.css │ │ │ ├── object_cell_editor.tsx │ │ │ ├── object_input.tsx │ │ │ ├── theory_selector.css │ │ │ ├── theory_selector.tsx │ │ │ └── types.ts │ │ ├── notebook │ │ │ ├── index.ts │ │ │ ├── notebook_cell.css │ │ │ ├── notebook_cell.tsx │ │ │ ├── notebook_editor.css │ │ │ ├── notebook_editor.tsx │ │ │ └── types.ts │ │ ├── page │ │ │ ├── 404_page.tsx │ │ │ ├── context.ts │ │ │ ├── document_breadcrumbs.css │ │ │ ├── document_breadcrumbs.tsx │ │ │ ├── document_loading_screen.tsx │ │ │ ├── document_menu.tsx │ │ │ ├── import_document.tsx │ │ │ ├── index.ts │ │ │ ├── menubar.css │ │ │ ├── menubar.tsx │ │ │ ├── page_container.tsx │ │ │ ├── toolbar.css │ │ │ └── toolbar.tsx │ │ ├── stdlib │ │ │ ├── analyses │ │ │ │ ├── decapodes.css │ │ │ │ ├── decapodes.tsx │ │ │ │ ├── diagram_graph.tsx │ │ │ │ ├── graph_visualization.css │ │ │ │ ├── graph_visualization.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── jupyter.ts │ │ │ │ ├── lotka_volterra.tsx │ │ │ │ ├── mass_action.tsx │ │ │ │ ├── model_graph.tsx │ │ │ │ ├── simulation.css │ │ │ │ ├── simulation.ts │ │ │ │ ├── stock_flow_diagram.tsx │ │ │ │ ├── submodel_graphs.css │ │ │ │ └── submodel_graphs.tsx │ │ │ ├── arrow_styles.module.css │ │ │ ├── arrow_styles.module.css.d.ts │ │ │ ├── context.ts │ │ │ ├── index.ts │ │ │ ├── styles.module.css │ │ │ ├── styles.module.css.d.ts │ │ │ ├── svg_styles.module.css │ │ │ ├── svg_styles.module.css.d.ts │ │ │ ├── text_styles.module.css │ │ │ ├── text_styles.module.css.d.ts │ │ │ ├── theories.tsx │ │ │ └── types.ts │ │ ├── theory │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── user │ │ │ ├── documents.css │ │ │ ├── documents.tsx │ │ │ ├── index.ts │ │ │ ├── login.css │ │ │ ├── login.tsx │ │ │ ├── permissions.css │ │ │ ├── permissions.tsx │ │ │ ├── profile.tsx │ │ │ ├── username.css │ │ │ └── username.tsx │ │ ├── util │ │ │ ├── assert_exhaustive.ts │ │ │ ├── deepcopy.ts │ │ │ ├── errors.css │ │ │ ├── errors.tsx │ │ │ ├── focus.ts │ │ │ ├── indexing.ts │ │ │ ├── json_export.ts │ │ │ ├── mdx.tsx │ │ │ ├── test_util.ts │ │ │ └── types.ts │ │ ├── visualization │ │ │ ├── echarts.ts │ │ │ ├── export_svg.ts │ │ │ ├── export_svg_components.tsx │ │ │ ├── graph_layout.ts │ │ │ ├── graph_svg.css │ │ │ ├── graph_svg.tsx │ │ │ ├── graphviz.ts │ │ │ ├── graphviz_json.ts │ │ │ ├── graphviz_svg.tsx │ │ │ ├── index.ts │ │ │ ├── ode_plot.tsx │ │ │ ├── pde_plot.tsx │ │ │ └── types.ts │ │ └── vite-env.d.ts │ ├── tsconfig.json │ └── vite.config.ts ├── migrator │ ├── Cargo.toml │ ├── README.md │ ├── default.nix │ └── src │ │ ├── main.rs │ │ └── migrations │ │ ├── m20241004010448_document_refs.rs │ │ ├── m20241025030906_users.rs │ │ ├── m20250409171833_add_permissions_object_subject_idx.rs │ │ ├── m20250516154702_automerge_storage.rs │ │ └── mod.rs └── notebook-types │ ├── Cargo.toml │ ├── README.md │ ├── examples │ └── v0 │ │ ├── An Example Instance.json │ │ ├── CA Cap-and-trade.json │ │ ├── SEIRV.json │ │ ├── Sustainable Peace.json │ │ └── The Ontology of CatColab.json │ └── src │ ├── lib.rs │ └── v0 │ ├── analysis.rs │ ├── api.rs │ ├── cell.rs │ ├── diagram_judgment.rs │ ├── document.rs │ ├── mod.rs │ ├── model.rs │ ├── model_judgment.rs │ ├── notebook.rs │ ├── path.rs │ └── theory.rs ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── rust-toolchain.toml /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use a Debian base image 2 | FROM debian:bullseye-slim AS base 3 | 4 | # Install necessary packages 5 | RUN apt-get update && apt-get install -y \ 6 | curl \ 7 | build-essential \ 8 | && : 9 | 10 | # Install Node.js 18.x 11 | RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \ 12 | && apt-get install -y nodejs 13 | 14 | # Verify Node.js version 15 | #RUN node -v 16 | 17 | # Install Rust 18 | RUN curl https://sh.rustup.rs -sSf | sh -s -- -y \ 19 | && . "$HOME/.cargo/env" \ 20 | && rustup update 21 | 22 | # Ensure the Rust environment is available 23 | ENV PATH="/root/.cargo/bin:${PATH}" 24 | 25 | # Install pnpm globally 26 | RUN npm install -g pnpm 27 | 28 | # Copy project files so that we can install dependencies into the container image. 29 | WORKDIR /app 30 | COPY package.json pnpm-lock.yaml ./ 31 | 32 | # Install project dependencies 33 | RUN pnpm install 34 | 35 | # Pre-build the project (optional) 36 | # RUN pnpm run build 37 | 38 | # # Clean up 39 | # RUN apt-get clean && rm -rf /var/lib/apt/lists/* 40 | 41 | # Debug stage 42 | FROM base AS debug 43 | ARG START_SHELL_ON_FAIL 44 | RUN [ "$START_SHELL_ON_FAIL" = "true" ] && bash || echo "Build continues" 45 | -------------------------------------------------------------------------------- /.devcontainer/README.md: -------------------------------------------------------------------------------- 1 | # CatColab dev container 2 | 3 | CatColab has experimental support for development using a dev container, which 4 | simplifies the setup process by providing a pre-configured environment via a 5 | Dockerfile. This is most useful for developers using [Visual Studio 6 | Code](https://code.visualstudio.com/) or other editors that support the [dev 7 | containers standard](https://containers.dev/). 8 | 9 | To use the dev container: 10 | 11 | 1. Ensure you have a container runtime installed and running on your machine. You can refer to the [Open Container Initiative](https://opencontainers.org/) for more information on container standards and runtimes. For practical guidance, you might consider starting with [Docker's Get Started Guide](https://www.docker.com/get-started). 12 | 2. Open the CatColab repository in VS Code. 13 | 3. Open the VS Code command pallet by pressing `Cmd+Shift+P` on macOS or `Ctrl+Shift+P` on Linux 14 | 4. Issue the command "Dev Containers: Reopen in Container". 15 | 5. Once the container is running, the necessary setup commands will be executed automatically. 16 | 6. VS Code will prompt "Your application running on port 5173 is available. See all forwarded ports". Click the link to open the application in your browser. 17 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CatColab Dev Container", 3 | "build": { 4 | "dockerfile": "Dockerfile", 5 | "context": ".." 6 | }, 7 | "customizations": { 8 | "vscode": { 9 | "extensions": [ 10 | "rust-lang.rust-analyzer", 11 | "esbenp.prettier-vscode", 12 | "dbaeumer.vscode-eslint" 13 | ] 14 | } 15 | }, 16 | "postCreateCommand": ".devcontainer/setup.sh", 17 | "remoteUser": "root" 18 | } 19 | -------------------------------------------------------------------------------- /.devcontainer/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Exit immediately if a command exits with a non-zero status 4 | set -e 5 | 6 | # Install dependencies 7 | pnpm install 8 | 9 | # Build the project 10 | pnpm run build 11 | 12 | # Start the development server with the host option 13 | pnpm run dev 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_style = space 3 | indent_size = 4 4 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | watch_file flake.nix 2 | 3 | use flake 4 | -------------------------------------------------------------------------------- /.netlify-env/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "netlify-cli": "^17.33.4" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.netlify-env/pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "." 3 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shared-workspace-lockfile=false 2 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | array_width = 80 2 | chain_width = 80 3 | fn_call_width = 80 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | 4 | members = [ 5 | "packages/migrator", 6 | "packages/backend", 7 | "packages/catlog", 8 | "packages/catlog-wasm", 9 | "packages/migrator", 10 | "packages/notebook-types", 11 | ] 12 | 13 | [profile.release] 14 | # Tell `rustc` to optimize for small code size. 15 | opt-level = "s" 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Evan Patterson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": { 3 | "ignore": ["dist/**", "docs/**", "catlog-wasm/**", "**/queries.ts"] 4 | }, 5 | "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json", 6 | "organizeImports": { 7 | "enabled": true 8 | }, 9 | "formatter": { 10 | "indentStyle": "space", 11 | "indentWidth": 4, 12 | "lineWidth": 100 13 | }, 14 | "linter": { 15 | "enabled": true, 16 | "rules": { 17 | "a11y": { 18 | "all": false 19 | }, 20 | "recommended": true, 21 | "suspicious": { 22 | "noExplicitAny": "warn", 23 | "noDuplicateTestHooks": { 24 | "level": "off" 25 | } 26 | }, 27 | "complexity": { 28 | "noForEach": "warn", 29 | "useLiteralKeys": { 30 | "level": "off" 31 | } 32 | }, 33 | "style": { 34 | "noParameterAssign": { 35 | "level": "off" 36 | }, 37 | "noUselessElse": { 38 | "level": "off" 39 | } 40 | } 41 | } 42 | }, 43 | "css": { 44 | "formatter": { 45 | "enabled": true 46 | }, 47 | "linter": { 48 | "enabled": true 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /dev-docs/.envrc: -------------------------------------------------------------------------------- 1 | use nix 2 | -------------------------------------------------------------------------------- /dev-docs/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | output/ 3 | -------------------------------------------------------------------------------- /dev-docs/README.md: -------------------------------------------------------------------------------- 1 | # CatColab: Design documents 2 | 3 | This folder contains mathematical and technical design documents for CatColab, 4 | written using [forester](https://sr.ht/~jonsterling/forester/). 5 | 6 | ## Building the forest 7 | 8 | *The following instructions are adapted from the upstream [forest template](https://git.sr.ht/~jonsterling/forest-template).* 9 | 10 | To build this forest, you need to have a working installation of the following software: 11 | 12 | - LaTeX, preferably the _full_ [TeXLive distribution](https://tug.org/texlive/) 13 | 14 | To build the forest, then simply run `./forester build`. To view the forest, run `./serve.sh` and go to `http://localhost:8080/index.xml` in your web browser. Note that you will need python installed for `./serve.sh` to work properly. 15 | 16 | You can run `./watch.sh` to watch for changes to the `trees` directory and rebuild accordingly. 17 | -------------------------------------------------------------------------------- /dev-docs/assets/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/assets/.gitignore -------------------------------------------------------------------------------- /dev-docs/checksums.txt: -------------------------------------------------------------------------------- 1 | 8e03600808a36c35ee70e2522c63566021accff27d6053897d2ca020664e5b57 forester-4.3.1-linux-x86_64.tar.gz 2 | 2d12362094e7c6da31e49a0f2cace7a1f0aff6cdfa8916fc84df84cf147d0055 forester-4.3.1-macos-arm64.tar.gz 3 | e79045ec4571a051a32c5daa531d9df6bfb375c1eb7e351a405e0419c6ef22f9 forester-4.3.1-macos-x86_64.tar.gz 4 | -------------------------------------------------------------------------------- /dev-docs/forest.toml: -------------------------------------------------------------------------------- 1 | [forest] 2 | trees = ["trees"] 3 | assets = ["assets"] 4 | theme = "theme" 5 | root = "dev-0001" 6 | -------------------------------------------------------------------------------- /dev-docs/forester: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | VERSION=4.3.1 4 | 5 | OS_NAME=$(uname) 6 | 7 | if [[ "$OS_NAME" == "Darwin" ]]; then 8 | OS="macos" 9 | elif [[ "$OS_NAME" == "Linux" ]]; then 10 | OS="linux" 11 | else 12 | echo "Unsupported OS $OS_NAME" 13 | exit 1 14 | fi 15 | 16 | ARCH=$(uname -m) 17 | 18 | SPEC="$VERSION-$OS-$ARCH" 19 | 20 | TARFILE="forester-$SPEC.tar.gz" 21 | 22 | FORESTER_URL="http://forester-builds.s3-website.us-east-2.amazonaws.com/$TARFILE" 23 | 24 | FORESTER_DIR="$HOME/.forester/$VERSION" 25 | FORESTER="$FORESTER_DIR/forester" 26 | 27 | if [[ ! -f "$FORESTER" ]]; then 28 | mkdir -p "$FORESTER_DIR" 29 | PREV=$(pwd) 30 | TMP=$(mktemp -d) 31 | cp checksums.txt $TMP 32 | cd $TMP 33 | curl -O $FORESTER_URL 34 | sha256sum -c checksums.txt --ignore-missing 35 | if [[ $? -ne 0 ]]; then 36 | print "invalid checksum" 37 | exit 1 38 | fi 39 | tar -xf $TARFILE 40 | mv forester "$FORESTER_DIR" 41 | cd $PREV 42 | rm -rf $TMP 43 | fi 44 | 45 | $FORESTER $@ 46 | -------------------------------------------------------------------------------- /dev-docs/serve.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo "Open http://localhost:8080/index.xml ..." 3 | echo "" 4 | python3 -m http.server -d output 8080 5 | 6 | -------------------------------------------------------------------------------- /dev-docs/shell.nix: -------------------------------------------------------------------------------- 1 | # shell.nix 2 | { pkgs ? import {} }: 3 | 4 | pkgs.mkShell { 5 | # Swap ‘git’ for whatever you actually need. 6 | buildInputs = [ 7 | pkgs.texlive.combined.scheme-full 8 | pkgs.fswatch 9 | ]; 10 | } 11 | -------------------------------------------------------------------------------- /dev-docs/theme/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /dev-docs/theme/LICENSES/MIT.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2020 Khan Academy and other contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dev-docs/theme/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/android-chrome-192x192.png -------------------------------------------------------------------------------- /dev-docs/theme/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/android-chrome-512x512.png -------------------------------------------------------------------------------- /dev-docs/theme/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/apple-touch-icon.png -------------------------------------------------------------------------------- /dev-docs/theme/bundle-js.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | npm install 4 | 5 | ./node_modules/.bin/esbuild --minify --bundle javascript-source/forester.js --outfile=forester.js 6 | 7 | 8 | -------------------------------------------------------------------------------- /dev-docs/theme/custom.css: -------------------------------------------------------------------------------- 1 | span.nlab > span > a { 2 | color: #226622; 3 | } 4 | 5 | span.wikipedia > span > a { 6 | color: #3366cc; 7 | } 8 | 9 | .centerfigs { 10 | text-align: center; 11 | 12 | & > img { 13 | vertical-align: middle; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /dev-docs/theme/default.xsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /dev-docs/theme/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/favicon-16x16.png -------------------------------------------------------------------------------- /dev-docs/theme/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/favicon-32x32.png -------------------------------------------------------------------------------- /dev-docs/theme/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/favicon.ico -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_AMS-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_AMS-Regular.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_AMS-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_AMS-Regular.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_AMS-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_AMS-Regular.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Caligraphic-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Caligraphic-Bold.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Caligraphic-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Caligraphic-Bold.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Caligraphic-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Caligraphic-Bold.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Caligraphic-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Caligraphic-Regular.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Caligraphic-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Caligraphic-Regular.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Caligraphic-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Caligraphic-Regular.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Fraktur-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Fraktur-Bold.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Fraktur-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Fraktur-Bold.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Fraktur-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Fraktur-Bold.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Fraktur-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Fraktur-Regular.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Fraktur-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Fraktur-Regular.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Fraktur-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Fraktur-Regular.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Main-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Main-Bold.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Main-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Main-Bold.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Main-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Main-Bold.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Main-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Main-BoldItalic.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Main-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Main-BoldItalic.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Main-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Main-BoldItalic.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Main-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Main-Italic.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Main-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Main-Italic.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Main-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Main-Italic.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Main-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Main-Regular.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Main-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Main-Regular.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Main-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Main-Regular.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Math-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Math-BoldItalic.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Math-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Math-BoldItalic.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Math-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Math-BoldItalic.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Math-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Math-Italic.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Math-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Math-Italic.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Math-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Math-Italic.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_SansSerif-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_SansSerif-Bold.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_SansSerif-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_SansSerif-Bold.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_SansSerif-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_SansSerif-Bold.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_SansSerif-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_SansSerif-Italic.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_SansSerif-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_SansSerif-Italic.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_SansSerif-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_SansSerif-Italic.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_SansSerif-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_SansSerif-Regular.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_SansSerif-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_SansSerif-Regular.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_SansSerif-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_SansSerif-Regular.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Script-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Script-Regular.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Script-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Script-Regular.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Script-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Script-Regular.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Size1-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Size1-Regular.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Size1-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Size1-Regular.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Size1-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Size1-Regular.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Size2-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Size2-Regular.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Size2-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Size2-Regular.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Size2-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Size2-Regular.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Size3-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Size3-Regular.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Size3-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Size3-Regular.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Size3-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Size3-Regular.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Size4-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Size4-Regular.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Size4-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Size4-Regular.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Size4-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Size4-Regular.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Typewriter-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Typewriter-Regular.ttf -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Typewriter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Typewriter-Regular.woff -------------------------------------------------------------------------------- /dev-docs/theme/fonts/KaTeX_Typewriter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/KaTeX_Typewriter-Regular.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/inria-sans-v14-latin_latin-ext-300.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/inria-sans-v14-latin_latin-ext-300.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/inria-sans-v14-latin_latin-ext-300italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/inria-sans-v14-latin_latin-ext-300italic.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/inria-sans-v14-latin_latin-ext-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/inria-sans-v14-latin_latin-ext-700.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/inria-sans-v14-latin_latin-ext-700italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/inria-sans-v14-latin_latin-ext-700italic.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/inria-sans-v14-latin_latin-ext-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/inria-sans-v14-latin_latin-ext-italic.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/fonts/inria-sans-v14-latin_latin-ext-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/dev-docs/theme/fonts/inria-sans-v14-latin_latin-ext-regular.woff2 -------------------------------------------------------------------------------- /dev-docs/theme/links.xsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | [ 19 | 21 | ] 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /dev-docs/theme/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "esbuild": "^0.18.15", 4 | "katex": "^0.16.8", 5 | "ninja-keys": "^1.2.2" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /dev-docs/trees/bib-0001.tree: -------------------------------------------------------------------------------- 1 | \title{Mathematical bibliography} 2 | \taxon{bibliography} 3 | 4 | \transclude{bib-0002} 5 | \transclude{bib-0003} 6 | -------------------------------------------------------------------------------- /dev-docs/trees/bib-0002.tree: -------------------------------------------------------------------------------- 1 | \title{Double categories} 2 | \taxon{bibliography} 3 | 4 | \ul{ 5 | \li{General reference: [[grandis-2019]]} 6 | \li{[[cartesian-double-theories-2024]]} 7 | \li{[[double-products-2024]]} 8 | } 9 | -------------------------------------------------------------------------------- /dev-docs/trees/bib-0003.tree: -------------------------------------------------------------------------------- 1 | \title{Modeling frameworks} 2 | \taxon{bibliography} 3 | 4 | \subtree{ 5 | \title{Knowledge and data} 6 | \ul{ 7 | \li{[[ologs-2012]]} 8 | \li{[[alg-databases-2017]]; see also [[acsets-2022]]} 9 | } 10 | } 11 | 12 | \subtree{ 13 | \title{Dynamical systems} 14 | \ul{ 15 | \li{Regulatory networks and causal loop diagrams: [[reg-nets-2024]]} 16 | \li{Stock-flow diagrams: [[stock-flow-2023]]} 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /dev-docs/trees/dbl-0001.tree: -------------------------------------------------------------------------------- 1 | \title{Background on double categories} 2 | 3 | \p{General double category theory: 4 | \ul{ 5 | \li{[[dbl-0002]]} 6 | } 7 | } 8 | 9 | \p{Double theories and models: 10 | \ul{ 11 | \li{[[dbl-0008]]} 12 | \li{[Discrete models](dbl-0005)} 13 | \li{[Free models](dbl-000D)} 14 | \li{[[dbl-000C]]} 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dev-docs/trees/dbl-0003.tree: -------------------------------------------------------------------------------- 1 | \title{Tabulator of span} 2 | \taxon{example} 3 | 4 | \p{The tabulator of a span is the apex of the span. Its two projection arrows 5 | are the legs of the span, and its projection cell is the evident one with 6 | identity map between apexes.} 7 | -------------------------------------------------------------------------------- /dev-docs/trees/dbl-0004.tree: -------------------------------------------------------------------------------- 1 | \title{Tabulator of profunctor} 2 | \taxon{example} 3 | \import{macros} 4 | 5 | \p{The tabulator #{\top P} of a profunctor #{P: \cat{C} \proto \cat{D}} is its 6 | \nlab{category of elements}, defined such that there are \em{covariant} 7 | projection functors #{\top P \to \cat{C}} and #{\top P \to \cat{D}}. Spelling 8 | this out, an object of #{\top P} is a triple #{(c,d,p)} such that #{c \in 9 | \cat{C}}, #{d \in \cat{D}}, and #{p \in P(c,d)}, and a morphism #{(c,d,p) \to 10 | (c',d',p')} in #{\top P} consists of morphisms #{f: c \to c'} and #{g: d \to d'} 11 | such that the square commutes: 12 | 13 | \quiver{ 14 | % https://q.uiver.app/#q=WzAsNCxbMCwwLCJjIl0sWzEsMCwiZCJdLFsxLDEsImQnIl0sWzAsMSwiYyciXSxbMCwxLCJwIiwwLHsic3R5bGUiOnsiYm9keSI6eyJuYW1lIjoiZGFzaGVkIn19fV0sWzEsMiwiZyJdLFswLDMsImYiLDJdLFszLDIsInAnIiwyLHsic3R5bGUiOnsiYm9keSI6eyJuYW1lIjoiZGFzaGVkIn19fV1d 15 | \begin{tikzcd} 16 | c & d \\ 17 | {c'} & {d'} 18 | \arrow["p", dashed, from=1-1, to=1-2] 19 | \arrow["f"', from=1-1, to=2-1] 20 | \arrow["g", from=1-2, to=2-2] 21 | \arrow["{p'}"', dashed, from=2-1, to=2-2] 22 | \end{tikzcd} 23 | }} 24 | 25 | \p{Be warned that this is only one of four possible ways to define the 26 | \nlab{graph of a profunctor}, as discussed on nLab.} 27 | -------------------------------------------------------------------------------- /dev-docs/trees/dbl-0005.tree: -------------------------------------------------------------------------------- 1 | \title{Discrete models of double theories} 2 | \import{macros} 3 | 4 | \p{A model of a double theory is \em{discrete} if it is freely generated by a 5 | set of objects.} 6 | 7 | \subtree{ 8 | \title{Object set} 9 | \taxon{Notation} 10 | 11 | \p{If \dbl{D} is a double category, then #{\dbl{D}_0} is its underlying category 12 | of objects and arrows and #{\dbl{D}_{00} \coloneqq \Ob(\dbl{D}_0)} is its 13 | underlying set of objects ([Grandis 2019](grandis-2019), Sec. 3.2.3).} 14 | } 15 | 16 | \transclude{dbl-0006} 17 | 18 | \p{Discrete models of a cartesian or finite-product double theory can be defined 19 | in much the same way, but since our double theories are usually presented by 20 | generators and relations, we prefer that a discrete model of such a theory be 21 | specified by a set of elements for each \em{generating} object in the theory.} 22 | 23 | \transclude{dbl-0007} 24 | -------------------------------------------------------------------------------- /dev-docs/trees/dbl-0006.tree: -------------------------------------------------------------------------------- 1 | \title{Discrete model of a simple double theory} 2 | \taxon{definition} 3 | \import{macros} 4 | 5 | \p{Let \dbl{T} be a simple double theory. 6 | 7 | The \define{discrete model functor} 8 | 9 | ##{ 10 | \Disc: \cat{Fun}(\dbl{T}_{00}, \Set) \to \cat{Lax}(\dbl{T}, \Span) 11 | } 12 | is the left adjoint to the forgetful functor 13 | 14 | ##{ 15 | \cat{Lax}(\dbl{T}, \Span) \xto{(-)_0} 16 | \cat{Fun}(\dbl{T}_0, \Set) \xto{\varepsilon_{\dbl{T_0}}^*} 17 | \cat{Fun}(\dbl{T}_{00}, \Set), 18 | } 19 | 20 | where #{\varepsilon_{\dbl{T_0}}: \dbl{T}_{00} \hookrightarrow \dbl{T}_0} is the 21 | counit of the adjunction #{\Disc: \Set \rightleftarrows \cat{Cat}: \Ob}.} 22 | 23 | \p{A \define{discrete model} of a simple double theory \dbl{T} is a model of 24 | \dbl{T} in the image of the discrete model functor.} 25 | -------------------------------------------------------------------------------- /dev-docs/trees/dbl-0007.tree: -------------------------------------------------------------------------------- 1 | \title{Discrete model of a double Lawvere theory} 2 | \taxon{definition} 3 | \import{macros} 4 | 5 | \p{Let \dbl{T} be a [double Lawvere theory](dbl-0008) with object sorts 6 | #{\Lambda_0}. 7 | 8 | The \define{discrete model functor} 9 | 10 | ##{ 11 | \Disc: \cat{Fun}(\Lambda_0, \Set) \to \cat{fpLax}(\dbl{T}, \Span) 12 | } 13 | 14 | is the left adjoint to the forgetful functor 15 | 16 | ##{ 17 | \cat{fpLax}(\dbl{T}, \Span) \xto{(-)_0} 18 | \cat{fpFun}(\dbl{T}_0, \Set) \to 19 | \cat{Fun}(\Lambda_0, \Set). 20 | } 21 | 22 | } 23 | 24 | \p{A \define{discrete model} of a double Lawvere theory \dbl{T} is a model of 25 | \dbl{T} in the image of the discrete model functor.} 26 | -------------------------------------------------------------------------------- /dev-docs/trees/dbl-0008.tree: -------------------------------------------------------------------------------- 1 | \title{Double Lawvere theories} 2 | \import{macros} 3 | 4 | \p{A multisorted \nlab{Lawvere theory} is a finite-product theory with a 5 | distinguished set of generating objects/types. This idea can be formulated 6 | precisely in a couple of ways; here is [Todd Trimble's 7 | definition](https://ncatlab.org/toddtrimble/published/multisorted+Lawvere+theories).} 8 | 9 | \transclude{dbl-0009} 10 | 11 | \p{Just as a [finite-product double theory](double-products-2024) is a 12 | categorification of a finite-product theory, so should a "double Lawvere theory" 13 | be a categorification of a Lawvere theory. Since we think of a double theory as 14 | having both object types (its objects) and morphism types (its proarrows), a 15 | multisorted double Lawvere theory ought to have both \em{object sorts} and 16 | \em{morphism sorts}. But stating this definition is more complicated than simply 17 | replacing the family construction with the double family construction, because 18 | the source or target of a morphism sort must be a finite family of object sorts 19 | rather than a single sort. For now we make the following incomplete definition.} 20 | 21 | \transclude{dbl-000A} 22 | -------------------------------------------------------------------------------- /dev-docs/trees/dbl-0009.tree: -------------------------------------------------------------------------------- 1 | \title{Multisorted Lawvere theory} 2 | \taxon{definition} 3 | \import{macros} 4 | 5 | \p{Given a set #{\Lambda}, a \define{Lawvere theory with sorts #{\Lambda}} is a 6 | category #{\cat{T}} with finite products equipped with an identity-on-objects, 7 | finite-product preserving functor 8 | 9 | ##{ 10 | i: \FinFam^*(\Lambda) \to \cat{T}. 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /dev-docs/trees/dbl-000A.tree: -------------------------------------------------------------------------------- 1 | \title{Multisorted double Lawvere theory} 2 | \taxon{definition} 3 | \import{macros} 4 | 5 | \p{Given a set #{\Lambda_0}, a \define{double Lawvere theory with object sorts 6 | #{\Lambda_0}} is a finite-product double theory \dbl{T} equipped with an 7 | identity-on-objects, finite-product preserving functor 8 | 9 | ##{ 10 | i_0: \FinFam^*(\Lambda_0) \to \dbl{T}_0. 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /dev-docs/trees/dbl-000E.tree: -------------------------------------------------------------------------------- 1 | \title{Double graph} 2 | \taxon{definition} 3 | \import{macros} 4 | 5 | \p{A \define{double graph} is a graph object \dbl{G} in \Cat, i.e., an endospan 6 | #{\dbl{G}_0 \xfrom{s} \dbl{G}_1 \xto{t} \dbl{G}_0} of categories.} 7 | -------------------------------------------------------------------------------- /dev-docs/trees/dbl-000F.tree: -------------------------------------------------------------------------------- 1 | \title{Graphs in a 2-category} 2 | \taxon{definition} 3 | \import{macros} 4 | 5 | \p{Let \twocat{K} be a 2-category. In the \define{2-category of graphs in 6 | \twocat{K},} 7 | 8 | \ul{ 9 | 10 | \li{an object \dbl{G} is a graph object #{s,t: \dbl{G}_1 \rightrightarrows 11 | \dbl{G}_0} in \twocat{K}, where #{s} is called the \define{source} map and #{t} 12 | is called the \define{target} map;} 13 | 14 | \li{a morphism #{F: \dbl{G} \to \dbl{H}} is a pair of morphisms #{F_i: \dbl{G}_i 15 | \to \dbl{H}_i}, for #{i = 0,1}, in \twocat{K} that commute with the source and 16 | target maps; and} 17 | 18 | \li{a cell #{\alpha: F \To G} is a pair of cells #{\alpha_i: F_i \To G_i}, for 19 | #{i = 0,1}, in \twocat{K} that commute with whiskering by the source and target 20 | maps.} 21 | 22 | } 23 | 24 | Composition in this 2-category is inherited componentwise from \twocat{K}.} 25 | -------------------------------------------------------------------------------- /dev-docs/trees/dbl-000G.tree: -------------------------------------------------------------------------------- 1 | \title{Cartesian double graph} 2 | \taxon{definition} 3 | \import{macros} 4 | 5 | \p{A [double graph](dbl-000E) \dbl{G} is \define{cartesian} when either of the 6 | following equivalent conditions hold: 7 | 8 | \ul{ 9 | 10 | \li{\dbl{G} is a \nlab{cartesian object} in the [2-category of double 11 | graphs](dbl-000F).} 12 | 13 | \li{The underlying categories #{\dbl{G}_0} and #{\dbl{G}_1} have finite 14 | products, which are preserved by the source and target functors #{s,t: \dbl{G}_1 15 | \rightrightarrows \dbl{G}_0}.} 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /dev-docs/trees/dbl-000H.tree: -------------------------------------------------------------------------------- 1 | \title{Network over a double theory} 2 | \taxon{definition} 3 | \import{macros} 4 | 5 | \p{Let #{\dbl{T}} be a simple or cartesian double theory. A \define{network over 6 | \dbl{T}}, or \define{\dbl{T}-network}, is a morphism of (cartesian) double 7 | graphs 8 | 9 | ##{N: U(\dbl{T}) \to \Span,} 10 | 11 | where #{U} is the forgetful 2-functor and, by a harmless abuse of notation, 12 | \Span also denotes the (cartesian) double graph of spans. 13 | 14 | } 15 | -------------------------------------------------------------------------------- /dev-docs/trees/dbl-000I.tree: -------------------------------------------------------------------------------- 1 | \title{Free model functor} 2 | \taxon{definition} 3 | \import{macros} 4 | 5 | \p{The \define{free model functor} for a simple double theory \dbl{T}, denoted 6 | 7 | ##{F: \cat{Net}_{\dbl{T}} \to \cat{Mod}_{\dbl{T}},} 8 | 9 | is the left adjoint to the forgetful functor 10 | 11 | ##{ 12 | \cat{Mod}_{\dbl{T}} \coloneqq 13 | \twocat{Dbl}_{\mathrm{lax}}(\dbl{T}, \Span) \xto{U} 14 | \twocat{DblGraph}(U(\dbl{T}), \Span) 15 | \eqqcolon \cat{Net}_{\dbl{T}} 16 | } 17 | 18 | given by applying the forgetful 2-functor #{U: \twocat{Dbl}_{\mathrm{lax}} \to 19 | \twocat{DblGph}}. The \define{free model functor} for a cartesian double theory 20 | is defined similarly, inserting the modifier "cartesian" where appropriate.} 21 | -------------------------------------------------------------------------------- /dev-docs/trees/dct-0001.tree: -------------------------------------------------------------------------------- 1 | \title{Categories} 2 | \taxon{doctrine} 3 | \import{macros} 4 | 5 | \p{Categories are the simplest of all doctrines. In the formalism of double 6 | theories, a category is precisely a model of the trivial double theory.} 7 | 8 | \transclude{thy-0001} 9 | -------------------------------------------------------------------------------- /dev-docs/trees/dct-0002.tree: -------------------------------------------------------------------------------- 1 | \title{Signed categories} 2 | \taxon{doctrine} 3 | \import{macros} 4 | 5 | \def\Sgn{#{\operatorname{Sgn}}} 6 | 7 | \p{A [signed category](reg-nets-2024) is a category graded by signs. To be more 8 | precise, let #{\Sgn \coloneqq \{\pm 1\} \cong \Z_2} be the group of nonzero 9 | signs under their usual multiplication.} 10 | 11 | \definition{Signed category}{ 12 | \p{A \define{signed category} a category \cat{A} along 13 | with a functor #{\cat{A} \to \Sgn}, viewing \Sgn as a one-object category.} 14 | \p{These are the objects of the slice category #{\cat{Cat}/\Sgn}, 15 | the \define{category of signed categories}.} 16 | } 17 | 18 | \transclude{thy-0002} 19 | 20 | \proposition{Characterization of signed categories}{The following are equivalent: 21 | \ol{ 22 | \li{a signed category;} 23 | \li{a category \cat{C} equipped with a profunctor #{N: \cat{C} \proto \cat{C}} 24 | and a composition operation ##{\mu: N \odot N \To \Hom_{\cat{C}},} which is 25 | a natural transformation;} 26 | \li{a model of the theory of signed categories.} 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /dev-docs/trees/dct-0004.tree: -------------------------------------------------------------------------------- 1 | \title{Monoids} 2 | \taxon{doctrine} 3 | \import{macros} 4 | 5 | \p{In the formalism of double theories, it is [categories](dct-0001), not 6 | monoids, that are the primitive concept. Nevertheless, monoids can be obtained 7 | as models of a double theory, requiring only a terminal object.} 8 | 9 | \transclude{thy-0004} 10 | -------------------------------------------------------------------------------- /dev-docs/trees/dct-0005.tree: -------------------------------------------------------------------------------- 1 | \title{Monoid actions} 2 | \taxon{doctrine} 3 | \import{macros} 4 | 5 | \p{As categories are more primitive than [monoids](dct-0004) in the formalism of 6 | double theories, so are category actions (presheaves and copresheaves) 7 | more primitive than monoid actions. Nevertheless, monoid actions are models 8 | of a double theory.} 9 | 10 | \transclude{thy-0005} 11 | 12 | \example{Dynamical systems}{ 13 | On one definition, a \nlab{dynamical system} is a monoid action in a concrete 14 | category. Common choice of monoids are the nonnegative natural or real numbers 15 | under addition. 16 | } 17 | 18 | \example{Transition systems}{ 19 | \p{Actions of free monoids can be identified with deterministic, labelled 20 | transition systems, also known as \wikipedia{semiautomata}.} 21 | 22 | \p{When such transition systems are equipped with an output function, one 23 | obtains \nlab{Moore machines} or, more generally, \nlab{Mealy machines}.} 24 | } -------------------------------------------------------------------------------- /dev-docs/trees/dct-0006.tree: -------------------------------------------------------------------------------- 1 | \title{Profunctors} 2 | \taxon{doctrine} 3 | 4 | \p{Profunctors form a doctrine, being the models of the following simple double 5 | theory. Note that profunctors are viewed here as objects rather than morphisms.} 6 | 7 | \transclude{thy-0006} 8 | 9 | \p{Finitely presented profunctors are a simplified version of the database 10 | schemas in Schultz et al's [[alg-databases-2017]], disallowing products on the 11 | type side. Alternatively, they are a slight extension of [acset](acsets-2022) 12 | schemas, allowing unary operations on types.} 13 | -------------------------------------------------------------------------------- /dev-docs/trees/dct-0007.tree: -------------------------------------------------------------------------------- 1 | \title{Nullable signed categories} 2 | \taxon{doctrine} 3 | \import{macros} 4 | 5 | \p{ 6 | A nullable signed category is a category graded by possibly vanishing signs. 7 | 8 | To be more precise: 9 | } 10 | 11 | \subtree{ 12 | \title{Nullable signed category} 13 | \taxon{definition} 14 | 15 | \p{A \define{nullable signed category} is a category sliced over the monoid 16 | #{\{+1,-1,0\}} of signs, including zero, under their usual multiplication.} 17 | 18 | } 19 | 20 | \transclude{thy-0007} 21 | 22 | \p{ 23 | Nullable signed category generalize [signed categories](dct-0002). 24 | 25 | They are examples of "categories with null morphisms" in the sense of 26 | [Grandis](grandis-2013-homological). 27 | } 28 | 29 | \p{From a systems perspective, null morphisms appear in certain flavors of 30 | system map, such as the Participatory System Maps of [Barbrook-Johnson and 31 | Penn](barbrook-johnson-2022). In this context, the null morphisms do not mean 32 | "no effect" but rather an effect with a complex or unknown direction. It then 33 | makes sense that the composite of a null morphism with any other morphism 34 | (positive, negative, or null) is again null.} 35 | -------------------------------------------------------------------------------- /dev-docs/trees/dct-000A.tree: -------------------------------------------------------------------------------- 1 | \title{Multicategories} 2 | \taxon{doctrine} 3 | \import{macros} 4 | 5 | \p{A \nlab{multicategory}, also known as a \em{colored} or \em{typed operad}, is 6 | a model of the following double theory.} 7 | 8 | \transclude{thy-000A} 9 | 10 | \p{A model #{M} of the theory of promonoids maps the object #{x} to the object 11 | set #{M_0 \coloneqq M(x)} of the multicategory and maps the proarrow #{\mu_n} to 12 | the span #{M_0^n\proto M_0} whose preimage at #{((x_i)_1^n,y)} is the set of 13 | multimorphisms #{(x_i)_1^n \to y}.} 14 | -------------------------------------------------------------------------------- /dev-docs/trees/dct-000B.tree: -------------------------------------------------------------------------------- 1 | \title{Delayable signed categories} 2 | \taxon{doctrine} 3 | \import{macros} 4 | 5 | \p{Informally, a delayable signed category is a category graded by signs (plus 6 | or minus) and, independently, by speed (fast or slow).} 7 | 8 | \subtree{ 9 | \title{Delayable signed category} 10 | \taxon{definition} 11 | 12 | \p{A \define{delayable signed category} is a category sliced over the product 13 | monoid #{M \coloneqq\{+1,-1\} \times \{1,0\}}, where both component monoids are 14 | equipped with their usual multiplications.} 15 | 16 | } 17 | 18 | \p{In the second component of #{M}, we interpret the identity element #{1} as 19 | "fast" and the absorbing element #{0} as "slow" or "delayed".} 20 | 21 | \transclude{thy-000B} 22 | 23 | \p{A free model of this double theory a causal loop diagram in which edges can 24 | be optionally marked as delayed. An example is this causal loop diagram for the 25 | [temperature control of a 26 | shower](https://sustainabilitymethods.org/index.php/File:Causal_Loop_Delays.png).} 27 | -------------------------------------------------------------------------------- /dev-docs/trees/dev-0002.tree: -------------------------------------------------------------------------------- 1 | \title{Frontend technology survey} 2 | 3 | \p{A survey of relevant frontend technology for building a structure editor.} 4 | 5 | \transclude{dev-0003} 6 | \transclude{dev-0004} 7 | \transclude{dev-0006} 8 | \transclude{dev-0007} 9 | -------------------------------------------------------------------------------- /dev-docs/trees/dev-0003.tree: -------------------------------------------------------------------------------- 1 | \title{Frontend base} 2 | 3 | \subtree{ 4 | \title{Language} 5 | 6 | \p{The obvious choice is \strong{[TypeScript](https://www.typescriptlang.org/)}. 7 | It is a saner JavaScript and the new industry standard.} 8 | 9 | \p{OCaml, Scala, and Kotlin stand out as modern, statically typed programming 10 | languages with reasonable stories about compiling to JavaScript, but will have 11 | less refined ecosystems and toolchains. [Hazel](https://hazel.org/), a 12 | proof-of-concept structure editor for a functional programming language, is 13 | written in OCaml ([GitHub](https://github.com/hazelgrove/hazel)). Since we do 14 | not aim to innovate in frontend programming, we should stick to the mainstream, 15 | hence JavaScript/TypeScript.} } 16 | 17 | \subtree{ 18 | \title{UI framework} 19 | 20 | \p{The proliferation of web 21 | [UI frameworks](https://bestofjs.org/projects?tags=framework) is notorious. 22 | \strong{React} remains the industry standard and would be a safe choice, 23 | although in past experience it felt a bit clunky and boilerplate-y.} 24 | 25 | \p{\strong{[Solid](https://www.solidjs.com/)} is an appealing newer framework 26 | that is clearly inspired by React but has learned some lessons 27 | ([HN](https://news.ycombinator.com/item?id=30508524)). It ditches the virtual 28 | DOM and has a better story about component updates ("reactivity"), being one 29 | of few frameworks to have proper support for 30 | [nested reactivity](https://www.solidjs.com/tutorial/stores_nested_reactivity).} 31 | } 32 | -------------------------------------------------------------------------------- /dev-docs/trees/dev-0008.tree: -------------------------------------------------------------------------------- 1 | \title{Rust ecosystem survey} 2 | 3 | \transclude{dev-0009} -------------------------------------------------------------------------------- /dev-docs/trees/dev-000B.tree: -------------------------------------------------------------------------------- 1 | \title{Database design} 2 | 3 | \p{The database contains the following tables.} 4 | 5 | \transclude{dev-000C} 6 | 7 | \transclude{dev-000D} 8 | -------------------------------------------------------------------------------- /dev-docs/trees/dev-000C.tree: -------------------------------------------------------------------------------- 1 | \taxon{table} 2 | \title{Snapshots} 3 | 4 | \p{A document snapshot is an arbitrary JSON object stored in binary format. 5 | Every snapshot has a timestamp and is associated with a single [ref](dev-000D).} 6 | 7 | \p{Snapshots are retained for all time unless their associated ref is deleted.} 8 | -------------------------------------------------------------------------------- /dev-docs/trees/dev-000D.tree: -------------------------------------------------------------------------------- 1 | \taxon{table} 2 | \title{Refs} 3 | 4 | \p{A "ref" is a persistent reference to a document. A running CatColab server 5 | maintains an in-memory hash map from refs to Automerge documents; there can be 6 | at most one Automerge document that is "controlling" a ref at a given time.} 7 | 8 | \p{Refs are identified by UUIDs. In the future, they will also have editable 9 | metadata such as taxon, title, author(s), tags, and so on.} 10 | 11 | \p{Additionally, a ref has a \code{head} field that points to a particular 12 | [snapshot](dev-000C) for the ref. The "autosave" mechanism updates the content 13 | of this snapshot every time the Automerge document connected to the ref is 14 | mutated. "Saving" a ref just means creating a new snapshot and making it the 15 | head. The previous head will continue to exist as a snapshot, and can be used to 16 | revert the ref to its state at a previous point in time.} 17 | -------------------------------------------------------------------------------- /dev-docs/trees/refs/acsets-2022.tree: -------------------------------------------------------------------------------- 1 | \title{Categorical data structures for technical computing} 2 | \author{Evan Patterson} 3 | \author{Owen Lynch} 4 | \author{James Fairbanks} 5 | \date{2022} 6 | \taxon{reference} 7 | \meta{external}{https://github.com/AlgebraicJulia/ACSets.jl} 8 | \meta{doi}{10.32408/compositionality-4-5} 9 | \meta{arxiv}{2106.04703} 10 | -------------------------------------------------------------------------------- /dev-docs/trees/refs/alg-databases-2017.tree: -------------------------------------------------------------------------------- 1 | \title{Algebraic databases} 2 | \author{Patrick Schultz} 3 | \author{David I. Spivak} 4 | \author{Christina Vasilakopoulou} 5 | \author{Ryan Wisnesky} 6 | \date{2017} 7 | \taxon{reference} 8 | \meta{external}{http://www.tac.mta.ca/tac/volumes/32/16/32-16abs.html} 9 | \meta{arxiv}{1602.03501} 10 | -------------------------------------------------------------------------------- /dev-docs/trees/refs/baez-pollard-2017.tree: -------------------------------------------------------------------------------- 1 | \title{A compositional framework for reaction networks} 2 | \author{John Baez} 3 | \author{Blake Pollard} 4 | \date{2017} 5 | \taxon{reference} 6 | \meta{arxiv}{1704.02051} 7 | \meta{doi}{10.1142/S0129055X17500283} 8 | -------------------------------------------------------------------------------- /dev-docs/trees/refs/barbrook-johnson-2022.tree: -------------------------------------------------------------------------------- 1 | \title{Systems mapping: How to build use and causal models of systems} 2 | \author{Pete Barbrook-Johnson} 3 | \author{Alexandra S. Penn} 4 | \date{2022} 5 | \taxon{reference} 6 | \meta{doi}{10.1007/978-3-031-01919-7} 7 | -------------------------------------------------------------------------------- /dev-docs/trees/refs/cartesian-double-theories-2024.tree: -------------------------------------------------------------------------------- 1 | \title{Cartesian double theories: A double-categorical framework for categorical doctrines} 2 | \author{Michael Lambert} 3 | \author{Evan Patterson} 4 | \date{2024} 5 | \taxon{reference} 6 | \meta{doi}{10.1016/j.aim.2024.109630} 7 | \meta{arxiv}{2310.05384} 8 | -------------------------------------------------------------------------------- /dev-docs/trees/refs/double-products-2024.tree: -------------------------------------------------------------------------------- 1 | \title{Products in double categories, revisited} 2 | \author{Evan Patterson} 3 | \date{2024} 4 | \taxon{reference} 5 | \meta{arxiv}{2401.08990} 6 | -------------------------------------------------------------------------------- /dev-docs/trees/refs/grandis-2013-homological.tree: -------------------------------------------------------------------------------- 1 | \title{Homological algebra in strongly non-abelian settings} 2 | \author{Marco Grandis} 3 | \date{2013} 4 | \taxon{reference} 5 | -------------------------------------------------------------------------------- /dev-docs/trees/refs/grandis-2019.tree: -------------------------------------------------------------------------------- 1 | \title{Higher dimensional categories: From double to multiple categories} 2 | \author{Marco Grandis} 3 | \date{2019} 4 | \taxon{reference} 5 | \meta{doi}{10.1142/11406} 6 | -------------------------------------------------------------------------------- /dev-docs/trees/refs/ologs-2012.tree: -------------------------------------------------------------------------------- 1 | \title{Ologs: A categorical framework for knowledge representation} 2 | \author{David I. Spivak} 3 | \author{Robert E. Kent} 4 | \date{2012} 5 | \taxon{reference} 6 | \meta{doi}{10.1371/journal.pone.0024274} 7 | \meta{arxiv}{1102.1889} 8 | -------------------------------------------------------------------------------- /dev-docs/trees/refs/pisani-2024.tree: -------------------------------------------------------------------------------- 1 | \title{Unbiased multicategory theory} 2 | \author{Claudio Pisani} 3 | \date{2024} 4 | \taxon{reference} 5 | \meta{doi}{10.48550/arXiv.2409.10150} 6 | \meta{arxiv}{2409.10150} 7 | -------------------------------------------------------------------------------- /dev-docs/trees/refs/reg-nets-2024.tree: -------------------------------------------------------------------------------- 1 | \title{A compositional account of motifs, mechanisms, and dynamics in biochemical regulatory networks} 2 | \author{Rebekah Aduddell} 3 | \author{James Fairbanks} 4 | \author{Amit Kumar} 5 | \author{Pablo S. Ocal} 6 | \author{Evan Patterson} 7 | \author{Brandon T. Shapiro} 8 | \date{2024} 9 | \taxon{reference} 10 | \meta{arxiv}{2301.01445} 11 | \meta{doi}{10.32408/compositionality-6-2} 12 | -------------------------------------------------------------------------------- /dev-docs/trees/refs/shulman-2008.tree: -------------------------------------------------------------------------------- 1 | \title{Framed bicategories and monoidal fibrations} 2 | \author{Michael Shulman} 3 | \date{2008} 4 | \taxon{reference} 5 | \meta{arxiv}{0706.1286} 6 | \meta{external}{http://www.tac.mta.ca/tac/volumes/20/18/20-18abs.html} 7 | -------------------------------------------------------------------------------- /dev-docs/trees/refs/stock-flow-2023.tree: -------------------------------------------------------------------------------- 1 | \title{Compositional modeling with stock and flow diagrams} 2 | \author{John Baez} 3 | \author{Xiaoyan Li} 4 | \author{Sophie Libkind} 5 | \author{Nathaniel Osgood} 6 | \author{Evan Patterson} 7 | \date{2023} 8 | \taxon{reference} 9 | \meta{doi}{10.4204/EPTCS.380.5} 10 | \meta{arxiv}{2205.08373} 11 | -------------------------------------------------------------------------------- /dev-docs/trees/thy-0001.tree: -------------------------------------------------------------------------------- 1 | \title{Categories} 2 | \taxon{theory} 3 | \import{macros} 4 | 5 | \p{The \define{trivial double theory} or \define{theory of categories} is the 6 | terminal double category \dbl{1}.} 7 | 8 | \p{The trivial double theory is a simple double theory, but it can also be 9 | regarded as a finite-product double theory that trivially has products.} 10 | -------------------------------------------------------------------------------- /dev-docs/trees/thy-0002.tree: -------------------------------------------------------------------------------- 1 | \title{Signed categories} 2 | \taxon{theory} 3 | \import{macros} 4 | 5 | \p{The \define{theory of signed categories} is the simple double theory generated by 6 | \ul{ 7 | \li{an object #{c}} 8 | \li{a proarrow #{n: c \proto c}} 9 | } 10 | subject to the equation 11 | ##{n \odot n = \id_c.} 12 | } 13 | -------------------------------------------------------------------------------- /dev-docs/trees/thy-0003.tree: -------------------------------------------------------------------------------- 1 | \title{Categories with links} 2 | \taxon{theory} 3 | \import{macros} 4 | 5 | \p{The \define{theory of categories with links} is the double theory freely generated by 6 | \ul{ 7 | \li{an object #{c}} 8 | \li{a proarrow #{\ell: c \proto \tabulator{\id_c}}.} 9 | }} 10 | 11 | \p{The theory of categories with links is an example of a "simple tabulator 12 | theory," i.e., a small double category with [tabulators](dbl-0002).} 13 | -------------------------------------------------------------------------------- /dev-docs/trees/thy-0004.tree: -------------------------------------------------------------------------------- 1 | \title{Monoids} 2 | \taxon{theory} 3 | \import{macros} 4 | 5 | \p{The \define{theory of semigroups} is the double theory generated by a single 6 | proarrow #{m: 1 \proto 1} subject to the equation ##{m \odot m = m.}} 7 | 8 | \p{The \define{theory of monoids} augments the theory of semigroups with a cell 9 | 10 | \quiver{ 11 | % https://q.uiver.app/#q=WzAsNCxbMCwwLCIxIl0sWzEsMCwiMSJdLFswLDEsIjEiXSxbMSwxLCIxIl0sWzIsMywibSIsMix7InN0eWxlIjp7ImJvZHkiOnsibmFtZSI6ImJhcnJlZCJ9fX1dLFswLDIsIiIsMix7ImxldmVsIjoyLCJzdHlsZSI6eyJoZWFkIjp7Im5hbWUiOiJub25lIn19fV0sWzEsMywiIiwwLHsibGV2ZWwiOjIsInN0eWxlIjp7ImhlYWQiOnsibmFtZSI6Im5vbmUifX19XSxbMCwxLCJcXGlkXzEiLDAseyJzdHlsZSI6eyJib2R5Ijp7Im5hbWUiOiJiYXJyZWQifX19XSxbNyw0LCJcXGV0YSIsMSx7InNob3J0ZW4iOnsic291cmNlIjoyMCwidGFyZ2V0IjoyMH0sInN0eWxlIjp7ImJvZHkiOnsibmFtZSI6Im5vbmUifSwiaGVhZCI6eyJuYW1lIjoibm9uZSJ9fX1dXQ== 12 | \begin{tikzcd}[row sep=scriptsize] 13 | 1 & 1 \\ 14 | 1 & 1 15 | \arrow[""{name=0, anchor=center, inner sep=0}, "{\id_1}", "\shortmid"{marking}, from=1-1, to=1-2] 16 | \arrow[Rightarrow, no head, from=1-1, to=2-1] 17 | \arrow[Rightarrow, no head, from=1-2, to=2-2] 18 | \arrow[""{name=1, anchor=center, inner sep=0}, "m"', "\shortmid"{marking}, from=2-1, to=2-2] 19 | \arrow["\eta"{description}, draw=none, from=0, to=1] 20 | \end{tikzcd} 21 | } 22 | 23 | subject to the equations 24 | 25 | ##{ 26 | %\eta \odot \eta = \eta 27 | %\qquad\text{and}\qquad 28 | 1_m \odot \eta = 1_m = \eta \odot 1_m. 29 | }} 30 | -------------------------------------------------------------------------------- /dev-docs/trees/thy-0005.tree: -------------------------------------------------------------------------------- 1 | \title{Monoid actions} 2 | \taxon{theory} 3 | \import{macros} 4 | 5 | \p{The \define{theory of monoid actions} extends the [theory of monoids](thy-0004) 6 | with another proarrow #{s: 1 \proto 1}, subject to the equations 7 | 8 | ##{ 9 | m \odot s = s \qquad\text{and}\qquad \eta \odot 1_s = 1_s, 10 | } 11 | 12 | endowing with #{s} with a (left) action by #{m}, along with the side equations 13 | 14 | ##{ 15 | s \odot s = \id_1 = s \odot m, 16 | } 17 | 18 | trivializing the implicit self-multiplication on #{s} and right action by #{m}.} 19 | -------------------------------------------------------------------------------- /dev-docs/trees/thy-0006.tree: -------------------------------------------------------------------------------- 1 | \title{Profunctors} 2 | \taxon{theory} 3 | \import{macros} 4 | 5 | \p{The \define{theory of profunctors}, also known as the \define{walking 6 | proarrow} and the \define{theory of simple schemas}, is the double category 7 | freely generated by two distinct objects, say #{0} and #{1}, and a proarrow 8 | #{0 \proto 1}.} 9 | -------------------------------------------------------------------------------- /dev-docs/trees/thy-0007.tree: -------------------------------------------------------------------------------- 1 | \title{Nullable signed categories} 2 | \taxon{theory} 3 | \import{macros} 4 | 5 | \p{ 6 | The \define{theory of nullable signed categories} is the simple double theory 7 | generated by 8 | 9 | \ul{ 10 | \li{an object #{c}} 11 | \li{proarrows #{n: c \proto c} and #{z: c \proto c}} 12 | } 13 | 14 | subject to the equations 15 | ##{ 16 | n \odot n = \id_c, \qquad 17 | z \odot z = n \odot z = z \odot n = z. 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /dev-docs/trees/thy-0008.tree: -------------------------------------------------------------------------------- 1 | \title{Companions} 2 | \taxon{theory} 3 | \import{macros} 4 | 5 | \p{The \define{theory of companion pairs} or \define{walking companion pair} is 6 | the simple double theory generated by 7 | 8 | \ul{ 9 | \li{a pair of objects #{x} and #{y}} 10 | \li{an arrow #{f: x \to y}} 11 | \li{a proarrow #{f_!: x \proto y}} 12 | \li{a pair of cells #{\eta} and #{\varepsilon} shaped as usual} 13 | } 14 | 15 | subject to the equations #{\eta \cdot \varepsilon = \id_f} and #{\eta \odot 16 | \varepsilon = 1_{f_!}}. 17 | 18 | } 19 | -------------------------------------------------------------------------------- /dev-docs/trees/thy-0009.tree: -------------------------------------------------------------------------------- 1 | \title{Conjoints} 2 | \taxon{theory} 3 | \import{macros} 4 | 5 | \p{The \define{theory of conjoint pairs} or \define{walking conjoint pair} is 6 | the simple double theory generated by 7 | 8 | \ul{ 9 | \li{a pair of objects #{x} and #{y}} 10 | \li{an arrow #{f: x \to y}} 11 | \li{a proarrow #{f^*: y \proto x}} 12 | \li{a pair of cells #{\eta} and #{\varepsilon} shaped as usual} 13 | } 14 | 15 | subject to the equations #{\eta \cdot \varepsilon = \id_f} and #{\varepsilon 16 | \odot \eta = 1_{f^*}}. 17 | 18 | } 19 | -------------------------------------------------------------------------------- /dev-docs/trees/thy-000A.tree: -------------------------------------------------------------------------------- 1 | \title{Promonoids} 2 | \taxon{theory} 3 | \import{macros} 4 | 5 | \p{The \define{theory of promonoids} #{\mathbb{T}_{\mathrm{pm}}} is the cartesian double theory generated by an object #{x} 6 | equipped with proarrows #{\mu_2:x^2 \proto x,\mu_0:x^0\proto x}, subject to associativity and unitality conditions. In other words, there is a unique counary proarrow #{\mu_n:x^n \proto x} for every #{n \geq 0}. See ([Lambert & 7 | Patterson 2024](cartesian-double-theories-2024), Theory 6.9).} 8 | 9 | \p{Arbitrary proarrows #{p:x^m\proto x^n} must then be a product of #{n} proarrows 10 | #{\mu_{m_i}:x^{m_i}\proto x} for some partition #{m=m_1+\cdots +m_n} of #{m}. Thus the loose 11 | category of #{\mathbb{T}_{\mathrm{pm}}} is the \nlab{augmented simplex category}, the category 12 | of totally-ordered, possibly-empty finite sets and order-preserving maps between them. This 13 | phenomenon is familiar from the fact that the augmented simplicial category is itself the 14 | strict monoidal category freely generated by a monoid object. Compare [Pisani 2024](pisani-2024) for a theory of multicategories in which the proarrows are instead maps of sets with orders 15 | on the fibers only, for better comparison with symmetric multicategories.} 16 | -------------------------------------------------------------------------------- /dev-docs/trees/thy-000B.tree: -------------------------------------------------------------------------------- 1 | \title{Theory of delayable signed categories} 2 | \taxon{theory} 3 | \import{macros} 4 | 5 | \p{The \define{theory of delayable signed categories} is the simple double 6 | theory with a single object and with proarrows given by the elements of the 7 | monoid #{M} [defined previously](dct-000B).} 8 | -------------------------------------------------------------------------------- /dev-docs/watch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | watch_directory="trees" 4 | build_command="./forester build" 5 | 6 | # Function to use fswatch 7 | use_fswatch() { 8 | echo "Using fswatch to monitor changes..." 9 | fswatch -o -e ".*" -i "\\.tree$" --event Created --event Updated --event Removed --event MovedFrom --event MovedTo "$watch_directory" | while read num; do 10 | $build_command 11 | done 12 | } 13 | 14 | # Function to use inotifywait 15 | use_inotifywait() { 16 | echo "Using inotifywait to monitor changes..." 17 | while inotifywait -e modify,create,delete,move -r "$watch_directory"; do 18 | $build_command 19 | done 20 | } 21 | 22 | # Function to use find/stat method 23 | use_find_stat() { 24 | echo "Using find/stat method to monitor changes..." 25 | last_update=$(date +%s) 26 | while true; do 27 | current_update=$(find "$watch_directory" -type f -newer "$watch_directory" -print -quit | wc -l) 28 | if [ "$current_update" != "0" ]; then 29 | $build_command 30 | last_update=$(date +%s) 31 | fi 32 | sleep 2 33 | done 34 | } 35 | 36 | # Check for available tools and use the appropriate method 37 | $build_command 38 | if command -v fswatch >/dev/null 2>&1; then 39 | use_fswatch 40 | elif command -v inotifywait >/dev/null 2>&1; then 41 | use_inotifywait 42 | else 43 | echo "Neither fswatch nor inotifywait found. Falling back to find/stat method." 44 | use_find_stat 45 | fi 46 | -------------------------------------------------------------------------------- /infrastructure/secrets/.env.next.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/infrastructure/secrets/.env.next.age -------------------------------------------------------------------------------- /infrastructure/secrets/.env.prod.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/infrastructure/secrets/.env.prod.age -------------------------------------------------------------------------------- /infrastructure/secrets/rclone.conf.next.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/infrastructure/secrets/rclone.conf.next.age -------------------------------------------------------------------------------- /infrastructure/secrets/rclone.conf.prod.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/infrastructure/secrets/rclone.conf.prod.age -------------------------------------------------------------------------------- /infrastructure/secrets/secrets.nix: -------------------------------------------------------------------------------- 1 | let 2 | catcolab = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPyxORhhfO+9F2hQZ3I/EiSpfg+caWpG6c8AuG5u1XtK root@ip-172-31-14-38.us-east-2.compute.internal"; 3 | catcolab-next = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBZaycYjvaZ5XhxVIvFr8zXvcy1GrViCKLIZCalZuk1l root@ip-172-31-9-45.us-east-2.compute.internal"; 4 | owen = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF2sBTuqGoEXRWpBRqTBwZZPDdLGGJ0GQcuX5dfIZKb4 o@red-special"; 5 | epatters = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAKXx6wMJSeYKCHNmbyR803RQ72uto9uYsHhAPPWNl2D evan@epatters.org"; 6 | jmoggr = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMiaHaeJ5PQL0mka/lY1yGXIs/bDK85uY1O3mLySnwHd j@jmoggr.com"; 7 | catcolab-next-deployuser = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM7AYg1fZM0zMxb/BuZTSwK4O3ycUIHruApr1tKoO8nJ deployuser@next.catcolab.org"; 8 | in 9 | builtins.mapAttrs (_: publicKeys: { inherit publicKeys; }) ({ 10 | ".env.next.age" = [ 11 | catcolab-next 12 | owen 13 | epatters 14 | jmoggr 15 | catcolab-next-deployuser 16 | ]; 17 | ".env.prod.age" = [ 18 | catcolab 19 | owen 20 | epatters 21 | ]; 22 | "rclone.conf.next.age" = [ 23 | catcolab-next 24 | owen 25 | epatters 26 | jmoggr 27 | catcolab-next-deployuser 28 | ]; 29 | "rclone.conf.prod.age" = [ 30 | catcolab 31 | owen 32 | epatters 33 | ]; 34 | }) 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "catcolab-monorepo", 3 | "version": "0.0.1", 4 | "description": "The catcolab monorepo", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "build": "pnpm --filter ./packages/frontend run build", 8 | "dev": "pnpm --filter ./packages/frontend run dev" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/ToposInstitute/CatColab.git" 13 | }, 14 | "author": "The CatColab Developers", 15 | "license": "MIT", 16 | "bugs": { 17 | "url": "https://github.com/ToposInstitute/CatColab/issues" 18 | }, 19 | "homepage": "https://next.catcolab.org", 20 | "devDependencies": { 21 | "@biomejs/biome": "^1.8.3", 22 | "biome": "^0.3.3", 23 | "depcheck": "^1.4.7", 24 | "tsx": "^4.16.5", 25 | "typedoc": "^0.26.5" 26 | }, 27 | "packageManager": "pnpm@9.12.3" 28 | } 29 | -------------------------------------------------------------------------------- /packages/algjulia-interop/.gitignore: -------------------------------------------------------------------------------- 1 | # Files generated by invoking Julia with --code-coverage 2 | *.jl.cov 3 | *.jl.*.cov 4 | 5 | # Files generated by invoking Julia with --track-allocation 6 | *.jl.mem 7 | 8 | # System-specific files and directories generated by the BinaryProvider and BinDeps packages 9 | # They contain absolute paths specific to the host computer, and so should not be committed 10 | deps/deps.jl 11 | deps/build.log 12 | deps/downloads/ 13 | deps/usr/ 14 | deps/src/ 15 | 16 | # Build artifacts for creating documentation generated by the Documenter package 17 | docs/build/ 18 | docs/site/ 19 | 20 | # File generated by Pkg, the package manager, based on a corresponding Project.toml 21 | # It records a fixed state of all packages used by the project. As such, it should not be 22 | # committed for packages, but should be committed for applications that require a static 23 | # environment. 24 | Manifest.toml 25 | 26 | # Julia sys images 27 | *.so 28 | -------------------------------------------------------------------------------- /packages/algjulia-interop/Project.toml: -------------------------------------------------------------------------------- 1 | name = "CatColabInterop" 2 | uuid = "9ecda8fb-39ab-46a2-a496-7285fa6368c1" 3 | license = "MIT" 4 | authors = ["CatColab team"] 5 | version = "0.1.0" 6 | 7 | [deps] 8 | ACSets = "227ef7b5-1206-438b-ac65-934d6da304b8" 9 | Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" 10 | CombinatorialSpaces = "b1c52339-7909-45ad-8b6a-6e388f7c67f2" 11 | ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66" 12 | CoordRefSystems = "b46f11dc-f210-4604-bfba-323c1ec968cb" 13 | Decapodes = "679ab3ea-c928-4fe6-8d59-fd451142d391" 14 | DiagrammaticEquations = "6f00c28b-6bed-4403-80fa-30e0dc12f317" 15 | Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" 16 | GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" 17 | IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" 18 | JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" 19 | LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" 20 | MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078" 21 | OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" 22 | Reexport = "189a3867-3050-52da-a836-e630ba90ab69" 23 | StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" 24 | 25 | [compat] 26 | ACSets = "0.2.21" 27 | Catlab = "0.16.19" 28 | CombinatorialSpaces = "0.7.4" 29 | ComponentArrays = "0.15" 30 | CoordRefSystems = "0.17.2" 31 | Decapodes = "0.6" 32 | DiagrammaticEquations = "0.1.7" 33 | Distributions = "0.25" 34 | GeometryBasics = "0.5.7" 35 | IJulia = "1.26.0" 36 | JSON3 = "1" 37 | LinearAlgebra = "1" 38 | MLStyle = "0.4" 39 | OrdinaryDiffEq = "6" 40 | Reexport = "1.2.2" 41 | StaticArrays = "1" 42 | -------------------------------------------------------------------------------- /packages/algjulia-interop/jupyter_server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | USAGE=$(cat <<-END 4 | \033[1mUsage:\033[0m 5 | 6 | -k|--kernel: specify the kernel. Defaults to the value of julia-\$(VERSION.major).\$(VERSION.minor). 7 | 8 | -m|--mode: a keyword which specifies the domain/port the Jupyter server is accessible. Valid arguments are 'dev', 'staging', and 'production' (default). 9 | END 10 | ) 11 | 12 | KERNEL=$(julia -e 'print("julia-$(VERSION.major).$(VERSION.minor)")') 13 | ORIGIN="https://catcolab.org" 14 | 15 | while [[ $# -gt 0 ]]; do 16 | case $1 in 17 | -k|--kernel) 18 | KERNEL=$2 19 | shift 20 | shift 21 | ;; 22 | -m|--mode) 23 | case "$2" in 24 | production) 25 | ;; 26 | staging) 27 | ORIGIN="https://next.catcolab.org" 28 | ;; 29 | dev) 30 | ORIGIN="http://localhost:5173" 31 | ;; 32 | *) 33 | echo "$2 is not an eligible mode. Please provide 'production', 'staging', or 'dev'" 34 | exit 1 35 | esac 36 | shift 37 | shift 38 | ;; 39 | -h|--help) 40 | echo -e "$USAGE" 41 | ;; 42 | *) 43 | echo " Unknown option: $1 44 | " 45 | echo -e "$USAGE" 46 | exit 1 47 | ;; 48 | esac 49 | done 50 | 51 | jupyter server \ 52 | --IdentityProvider.token="" \ 53 | --ServerApp.disable_check_xsrf=True \ 54 | --ServerApp.allow_origin="$ORIGIN" \ 55 | --ServerApp.allow_credentials=True \ 56 | --MultiKernelManager.default_kernel_name="$KERNEL" 57 | -------------------------------------------------------------------------------- /packages/algjulia-interop/make_sysimage.jl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env julia 2 | 3 | @info "Verifying PackageCompiler is installed globally" 4 | using Pkg; Pkg.activate(); Pkg.add("PackageCompiler") 5 | using PackageCompiler 6 | 7 | @info "Activating sysimage environment" 8 | Pkg.activate(@__DIR__) 9 | 10 | @info "Creating the sysimage. This may take a while..." 11 | sysimg="CatColabInterop.so" 12 | create_sysimage(["CatColabInterop"], sysimage_path=sysimg, 13 | precompile_execution_file="sysimage_precompile.jl") 14 | sysimg_path=joinpath(@__DIR__, sysimg); 15 | 16 | @info "Adding $sysimg_path to IJulia kernel" 17 | Pkg.activate(); Pkg.add("IJulia") 18 | using IJulia 19 | Pkg.build("IJulia") 20 | 21 | installkernel("Julia CatColab Interop", "--project=@.", "--sysimage=$sysimg_path") 22 | 23 | @info "Done!" 24 | exit() 25 | -------------------------------------------------------------------------------- /packages/algjulia-interop/src/decapodes-service/DecapodesService.jl: -------------------------------------------------------------------------------- 1 | module DecapodesService 2 | 3 | # algebraicjulia dependencies 4 | using ACSets 5 | using DiagrammaticEquations 6 | using Decapodes 7 | using CombinatorialSpaces 8 | 9 | # dependencies 10 | import JSON3 11 | using StaticArrays 12 | using MLStyle 13 | using LinearAlgebra 14 | using ComponentArrays 15 | using Distributions # for initial conditions 16 | 17 | # meshing 18 | using CoordRefSystems 19 | using GeometryBasics: Point2, Point3 20 | Point3D = Point3{Float64}; 21 | 22 | # simulation 23 | using OrdinaryDiffEq 24 | 25 | using ..CatColabInterop 26 | using ..CatColabInterop: AlgebraicJuliaIntegration, AbstractDiagram, AbstractAnalysis 27 | import ..CatColabInterop: Model, to_model 28 | 29 | # necessary to export 30 | export infer_types!, evalsim, default_dec_generate, default_dec_matrix_generate, 31 | DiagonalHodge, ComponentArray 32 | 33 | struct ThDecapode <: AlgebraicJuliaIntegration end 34 | export ThDecapode 35 | 36 | # funcitons for geometry and initial conditions 37 | include("geometry.jl") 38 | include("model.jl") ## model-building 39 | include("diagram.jl") ## diagram-building 40 | include("analysis/Analysis.jl") 41 | 42 | end 43 | -------------------------------------------------------------------------------- /packages/algjulia-interop/src/decapodes-service/analysis/Analysis.jl: -------------------------------------------------------------------------------- 1 | include("ns_helper.jl") 2 | include("initial_conditions.jl") 3 | include("simulation.jl") 4 | -------------------------------------------------------------------------------- /packages/algjulia-interop/src/kernel_support.jl: -------------------------------------------------------------------------------- 1 | import JSON3 2 | 3 | export JsonValue 4 | 5 | """ Container for an arbitrary JSON value. """ 6 | struct JsonValue 7 | value::Any 8 | end 9 | 10 | function Base.show(io::IO, ::MIME"text/plain", json::JsonValue) 11 | print(io, "JsonValue(") 12 | show(IOContext(io, :compact => true), json.value) 13 | print(io, ")") 14 | end 15 | 16 | function Base.show(io::IO, ::MIME"application/json", json::JsonValue) 17 | JSON3.write(io, json.value) 18 | end 19 | -------------------------------------------------------------------------------- /packages/algjulia-interop/sysimage_precompile.jl: -------------------------------------------------------------------------------- 1 | import CatColabInterop 2 | include(joinpath(pkgdir(CatColabInterop), "test", "runtests.jl")) 3 | -------------------------------------------------------------------------------- /packages/algjulia-interop/test/Project.toml: -------------------------------------------------------------------------------- 1 | [deps] 2 | ACSets = "227ef7b5-1206-438b-ac65-934d6da304b8" 3 | CatColabInterop = "9ecda8fb-39ab-46a2-a496-7285fa6368c1" 4 | CombinatorialSpaces = "b1c52339-7909-45ad-8b6a-6e388f7c67f2" 5 | ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66" 6 | Decapodes = "679ab3ea-c928-4fe6-8d59-fd451142d391" 7 | DiagrammaticEquations = "6f00c28b-6bed-4403-80fa-30e0dc12f317" 8 | JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" 9 | LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" 10 | MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078" 11 | OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" 12 | StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" 13 | Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" 14 | -------------------------------------------------------------------------------- /packages/algjulia-interop/test/test_jsons/diagrams/diffusivity_constant/analysis.json: -------------------------------------------------------------------------------- 1 | { 2 | "analysisOf": { 3 | "_id": "0196021c-dee3-75b3-bb79-2f940651a1a1", 4 | "_server": "backend.catcolab.org", 5 | "_version": null, 6 | "type": "analysis-of" 7 | }, 8 | "analysisType": "diagram", 9 | "name": "", 10 | "notebook": { 11 | "cells": [ 12 | { 13 | "content": { 14 | "content": { 15 | "domain": "Plane", 16 | "duration": 10, 17 | "initialConditions": { 18 | "0196021c-f5fe-70f3-ac68-89ae212970ea": "Gaussian", 19 | "0196021d-1aa4-776d-b4fb-05d24d0c6de4": "Gaussian" 20 | }, 21 | "mesh": "Rectangle", 22 | "plotVariables": { 23 | "0196021c-f5fe-70f3-ac68-89ae212970ea": true 24 | }, 25 | "scalars": { 26 | "01960dde-1193-7132-b662-9bf24ed05264": 1 27 | } 28 | }, 29 | "id": "decapodes" 30 | }, 31 | "id": "0196021f-beef-74b0-9103-9ab1982255cf", 32 | "tag": "formal" 33 | }, 34 | { 35 | "content": { 36 | "content": { 37 | "layout": "graphviz-directed" 38 | }, 39 | "id": "graph" 40 | }, 41 | "id": "01960ddd-8fc3-7482-a2c8-a0a59ee85709", 42 | "tag": "formal" 43 | } 44 | ] 45 | }, 46 | "type": "analysis" 47 | } 48 | -------------------------------------------------------------------------------- /packages/algjulia-interop/test/test_jsons/diagrams/inverse_laplacian_longtrip/analysis.json: -------------------------------------------------------------------------------- 1 | {"analysisOf":{"_id":"0195ecdc-cf21-7091-94a3-7644d5103743","_server":"backend.catcolab.org","_version":null,"type":"analysis-of"},"analysisType":"diagram","name":"","notebook":{"cells":[{"id":"0195ed44-aa9e-730d-807d-57cf94417236","tag":"stem"},{"content":{"content":{"domain":"Plane","duration":10,"initialConditions":{"0195ecdc-d7e1-768a-8862-76a47f2f4e06":"Gaussian","0195ecdc-f625-71c8-a044-a6ce2fb3dd31":"Gaussian"},"mesh":"Rectangle","plotVariables":{"0195ecdc-d7e1-768a-8862-76a47f2f4e06":true},"scalars":{}},"id":"decapodes"},"id":"0195ed44-c260-755f-9c1f-80c13253e575","tag":"formal"}]},"type":"analysis"} 2 | -------------------------------------------------------------------------------- /packages/algjulia-interop/test/test_jsons/diagrams/ns_vort/analysis.json: -------------------------------------------------------------------------------- 1 | {"analysisOf":{"_id":"0195ecc4-4c4d-70e2-bee7-18221e6c42e7","_server":"backend.catcolab.org","_version":null,"type":"analysis-of"},"analysisType":"diagram","name":"","notebook":{"cells":[{"content":{"content":{"domain":"Sphere","duration":1,"initialConditions":{"0195ecc5-9eaf-71dd-a9c8-621d888e2add":"TaylorVortex","0195ecc5-b1b0-746e-8a04-ebd359da2bfd":"TaylorVortex","0195ecc5-d39a-72bf-8cd3-236d5211e122":"TaylorVortex"},"mesh":"Icosphere6","plotVariables":{"0195ecc5-9eaf-71dd-a9c8-621d888e2add":true},"scalars":{}},"id":"decapodes"},"id":"0195ecca-f11e-74c8-8fa4-fb8b03a93274","tag":"formal"}]},"type":"analysis"} 2 | -------------------------------------------------------------------------------- /packages/automerge-doc-server/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /packages/automerge-doc-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "automerge-doc-server", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "main": "dist/main.js", 6 | "scripts": { 7 | "main": "tsx src/main.ts", 8 | "format": "biome format --write", 9 | "lint": "biome lint --write && biome check --write" 10 | }, 11 | "author": "CatColab developer team", 12 | "license": "MIT", 13 | "dependencies": { 14 | "@automerge/automerge-repo": "^1.2.1", 15 | "@automerge/automerge-repo-network-websocket": "^1.2.1", 16 | "dotenv": "^16.5.0", 17 | "express": "^4.19.2", 18 | "pg": "^8.16.0", 19 | "socket.io-client": "^4.8.0", 20 | "ws": "^8.18.0" 21 | }, 22 | "devDependencies": { 23 | "@biomejs/biome": "^1.8.3", 24 | "@types/express": "^4.17.21", 25 | "@types/node": "^22.7.4", 26 | "@types/ws": "^8.5.12", 27 | "tsx": "^4.19.1", 28 | "typescript": "^5.6.2" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/automerge-doc-server/src/main.ts: -------------------------------------------------------------------------------- 1 | import { runMigration } from "./migrations/index.js"; 2 | import { AutomergeServer } from "./server.js"; 3 | import { SocketServer } from "./socket.js"; 4 | 5 | async function main() { 6 | const args = process.argv.slice(2); 7 | 8 | if (args[0] === "--migrate") { 9 | const migrationName = args[1]; 10 | if (!migrationName) { 11 | console.error("Missing migration name after --migrate"); 12 | process.exit(1); 13 | } 14 | 15 | await runMigration(migrationName); 16 | process.exit(0); 17 | } 18 | 19 | const internal_port = process.env.AUTOMERGE_INTERNAL_PORT || 3000; 20 | const port = process.env.AUTOMERGE_PORT || 8010; 21 | 22 | const server = new AutomergeServer(port); 23 | const socket_server = new SocketServer(internal_port, server); 24 | 25 | server.handleChange = (refId, content) => socket_server.autosave(refId, content); 26 | 27 | process.once("SIGINT", () => { 28 | socket_server.close(); 29 | server.close(); 30 | }); 31 | 32 | process.once("SIGTERM", () => { 33 | socket_server.close(); 34 | server.close(); 35 | }); 36 | } 37 | 38 | main(); 39 | -------------------------------------------------------------------------------- /packages/automerge-doc-server/src/migrations/index.ts: -------------------------------------------------------------------------------- 1 | import { automergeStorage } from "./m20250516154702_automerge_storage.js"; 2 | 3 | export async function runMigration(name: string) { 4 | switch (name) { 5 | case "automerge_storage": { 6 | await automergeStorage(); 7 | break; 8 | } 9 | default: 10 | console.error(`Unknown migration: ${name}`); 11 | process.exit(1); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/automerge-doc-server/src/migrations/m20250516154702_automerge_storage.ts: -------------------------------------------------------------------------------- 1 | import { Repo, type RepoConfig } from "@automerge/automerge-repo"; 2 | import dotenv from "dotenv"; 3 | import pgPkg from "pg"; 4 | import { PostgresStorageAdapter } from "../postgres_storage_adapter.js"; 5 | 6 | const { Pool } = pgPkg; 7 | 8 | dotenv.config(); 9 | 10 | export async function automergeStorage() { 11 | const pool = new Pool({ 12 | connectionString: process.env.DATABASE_URL, 13 | }); 14 | 15 | const storageAdapter = new PostgresStorageAdapter(pool); 16 | 17 | const config: RepoConfig = { 18 | sharePolicy: async () => false, 19 | storage: storageAdapter, 20 | }; 21 | 22 | const repo = new Repo(config); 23 | 24 | const result = await pool.query("SELECT id, content, doc_id FROM snapshots"); 25 | 26 | for (const { id, content, doc_id } of result.rows) { 27 | if (doc_id) { 28 | continue; 29 | } 30 | 31 | const handle = repo.create(content); 32 | 33 | if (!handle) { 34 | console.error(`Failed to create document for ref ${id}`); 35 | continue; 36 | } 37 | 38 | await pool.query("UPDATE snapshots SET doc_id = $2 WHERE id = $1", [id, handle.documentId]); 39 | 40 | console.log(`created automerge doc for snapshot ${id}`); 41 | } 42 | 43 | console.log("Done!"); 44 | } 45 | -------------------------------------------------------------------------------- /packages/automerge-doc-server/src/types.ts: -------------------------------------------------------------------------------- 1 | export type NewDocSocketResponse = 2 | | { 3 | Ok: { 4 | docId: string; 5 | docJson: any; 6 | }; 7 | } 8 | | { Err: string }; 9 | export type StartListeningSocketResponse = { Ok: null } | { Err: string }; 10 | -------------------------------------------------------------------------------- /packages/automerge-doc-server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "NodeNext", 5 | "moduleResolution": "Node16", 6 | "esModuleInterop": true, 7 | "outDir": "./dist", 8 | 9 | "strict": true, 10 | "skipLibCheck": true, 11 | "noUnusedLocals": true, 12 | "noUnusedParameters": true, 13 | "noUncheckedIndexedAccess": true, 14 | "noFallthroughCasesInSwitch": true 15 | }, 16 | "include": ["src/**/*.ts"] 17 | } 18 | -------------------------------------------------------------------------------- /packages/backend/.gitignore: -------------------------------------------------------------------------------- 1 | *.env 2 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-05183554f0c9207cdd1e89a948d3da5238ede1773a9507446694e9f7b4d2b16c.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "\n WITH snapshot AS (\n INSERT INTO snapshots(for_ref, content, last_updated, doc_id)\n VALUES ($1, $2, NOW(), $3)\n RETURNING id\n )\n UPDATE refs\n SET head = (SELECT id FROM snapshot)\n WHERE id = $1\n ", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Left": [ 8 | "Uuid", 9 | "Jsonb", 10 | "Text" 11 | ] 12 | }, 13 | "nullable": [] 14 | }, 15 | "hash": "05183554f0c9207cdd1e89a948d3da5238ede1773a9507446694e9f7b4d2b16c" 16 | } 17 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-1ddd7b172b0db3b5e7818013b6bb9e2d57dc2e2bc13e1d7faa82e48a77964dcc.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "SELECT 1 FROM refs WHERE id = $1", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "ordinal": 0, 8 | "name": "?column?", 9 | "type_info": "Int4" 10 | } 11 | ], 12 | "parameters": { 13 | "Left": [ 14 | "Uuid" 15 | ] 16 | }, 17 | "nullable": [ 18 | null 19 | ] 20 | }, 21 | "hash": "1ddd7b172b0db3b5e7818013b6bb9e2d57dc2e2bc13e1d7faa82e48a77964dcc" 22 | } 23 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-3645a86b3df08de865372b02d588272bb950744a38d46079ca18b11e405058a3.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "\n SELECT EXISTS (\n SELECT 1 FROM users WHERE id = $1\n )\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "ordinal": 0, 8 | "name": "exists", 9 | "type_info": "Bool" 10 | } 11 | ], 12 | "parameters": { 13 | "Left": [ 14 | "Text" 15 | ] 16 | }, 17 | "nullable": [ 18 | null 19 | ] 20 | }, 21 | "hash": "3645a86b3df08de865372b02d588272bb950744a38d46079ca18b11e405058a3" 22 | } 23 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-3e2b3e63a36ffa59ce60f8df19157edc1dfcee0d876d4b0c22c2db24feee6a3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "\n INSERT INTO users(id, created, signed_in)\n VALUES ($1, NOW(), NOW())\n ON CONFLICT (id) DO UPDATE\n SET signed_in = EXCLUDED.signed_in\n ", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Left": [ 8 | "Text" 9 | ] 10 | }, 11 | "nullable": [] 12 | }, 13 | "hash": "3e2b3e63a36ffa59ce60f8df19157edc1dfcee0d876d4b0c22c2db24feee6a3c" 14 | } 15 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-3e715aa995094feff20f8254dfd27323844efa31ece5d40ce8778122687cdefc.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "\n SELECT id, username, display_name FROM users WHERE username = $1\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "ordinal": 0, 8 | "name": "id", 9 | "type_info": "Text" 10 | }, 11 | { 12 | "ordinal": 1, 13 | "name": "username", 14 | "type_info": "Text" 15 | }, 16 | { 17 | "ordinal": 2, 18 | "name": "display_name", 19 | "type_info": "Text" 20 | } 21 | ], 22 | "parameters": { 23 | "Left": [ 24 | "Text" 25 | ] 26 | }, 27 | "nullable": [ 28 | false, 29 | true, 30 | true 31 | ] 32 | }, 33 | "hash": "3e715aa995094feff20f8254dfd27323844efa31ece5d40ce8778122687cdefc" 34 | } 35 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-4f04b1b2b42a310d659df5700aa47b10a291e6e98d2b989036e8d78ee3b00afd.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "\n UPDATE snapshots\n SET content = $2, last_updated = NOW()\n WHERE id = (SELECT head FROM refs WHERE id = $1)\n ", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Left": [ 8 | "Uuid", 9 | "Jsonb" 10 | ] 11 | }, 12 | "nullable": [] 13 | }, 14 | "hash": "4f04b1b2b42a310d659df5700aa47b10a291e6e98d2b989036e8d78ee3b00afd" 15 | } 16 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-513719212b96e260e9c4ce840f716b1b6cb43563371fb35f9677fcf949827363.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "\n SELECT subject as \"user_id\", username, display_name,\n level as \"level: PermissionLevel\"\n FROM permissions\n LEFT OUTER JOIN users ON id = subject\n WHERE object = $1\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "ordinal": 0, 8 | "name": "user_id", 9 | "type_info": "Text" 10 | }, 11 | { 12 | "ordinal": 1, 13 | "name": "username", 14 | "type_info": "Text" 15 | }, 16 | { 17 | "ordinal": 2, 18 | "name": "display_name", 19 | "type_info": "Text" 20 | }, 21 | { 22 | "ordinal": 3, 23 | "name": "level: PermissionLevel", 24 | "type_info": { 25 | "Custom": { 26 | "name": "permission_level", 27 | "kind": { 28 | "Enum": [ 29 | "read", 30 | "write", 31 | "maintain", 32 | "own" 33 | ] 34 | } 35 | } 36 | } 37 | } 38 | ], 39 | "parameters": { 40 | "Left": [ 41 | "Uuid" 42 | ] 43 | }, 44 | "nullable": [ 45 | true, 46 | true, 47 | true, 48 | false 49 | ] 50 | }, 51 | "hash": "513719212b96e260e9c4ce840f716b1b6cb43563371fb35f9677fcf949827363" 52 | } 53 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-6425b7d75c5fd6482701adba8011472860299d4fc872194449e18682cfed5bab.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "\n SELECT doc_id FROM snapshots\n WHERE id = (SELECT head FROM refs WHERE id = $1)\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "ordinal": 0, 8 | "name": "doc_id", 9 | "type_info": "Text" 10 | } 11 | ], 12 | "parameters": { 13 | "Left": [ 14 | "Uuid" 15 | ] 16 | }, 17 | "nullable": [ 18 | false 19 | ] 20 | }, 21 | "hash": "6425b7d75c5fd6482701adba8011472860299d4fc872194449e18682cfed5bab" 22 | } 23 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-84f34c3f761dbab809edf2af4104e533a26a50310c90d340fdd90d64683b6b55.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "\n SELECT username, display_name FROM users\n WHERE id = $1\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "ordinal": 0, 8 | "name": "username", 9 | "type_info": "Text" 10 | }, 11 | { 12 | "ordinal": 1, 13 | "name": "display_name", 14 | "type_info": "Text" 15 | } 16 | ], 17 | "parameters": { 18 | "Left": [ 19 | "Text" 20 | ] 21 | }, 22 | "nullable": [ 23 | true, 24 | true 25 | ] 26 | }, 27 | "hash": "84f34c3f761dbab809edf2af4104e533a26a50310c90d340fdd90d64683b6b55" 28 | } 29 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-92973a6dc72749d528465057e8bd674427db3a290d6db645dea5ac3c540167ef.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "\n SELECT content FROM snapshots\n WHERE id = (SELECT head FROM refs WHERE id = $1)\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "ordinal": 0, 8 | "name": "content", 9 | "type_info": "Jsonb" 10 | } 11 | ], 12 | "parameters": { 13 | "Left": [ 14 | "Uuid" 15 | ] 16 | }, 17 | "nullable": [ 18 | false 19 | ] 20 | }, 21 | "hash": "92973a6dc72749d528465057e8bd674427db3a290d6db645dea5ac3c540167ef" 22 | } 23 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-a80368dbf3e74206cdbe08744b1d46924d0731475384201d7f2ddaf51e8e3644.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "SELECT 1 FROM users WHERE username = $1", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "ordinal": 0, 8 | "name": "?column?", 9 | "type_info": "Int4" 10 | } 11 | ], 12 | "parameters": { 13 | "Left": [ 14 | "Text" 15 | ] 16 | }, 17 | "nullable": [ 18 | null 19 | ] 20 | }, 21 | "hash": "a80368dbf3e74206cdbe08744b1d46924d0731475384201d7f2ddaf51e8e3644" 22 | } 23 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-a8934c50209e48af661186c7d1c2ff8d8f23b4d05f1a7f5783baf74165f464f1.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "\n UPDATE users SET username = COALESCE($2, username), display_name = $3\n WHERE id = $1\n ", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Left": [ 8 | "Text", 9 | "Text", 10 | "Text" 11 | ] 12 | }, 13 | "nullable": [] 14 | }, 15 | "hash": "a8934c50209e48af661186c7d1c2ff8d8f23b4d05f1a7f5783baf74165f464f1" 16 | } 17 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-a8cb9f26893bbf784cf8a71090e64c3603e238ea6786d327f64ae04aef205198.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "\n WITH snapshot AS (\n INSERT INTO snapshots(for_ref, content, last_updated, doc_id)\n VALUES ($1, $2, NOW(), $3)\n RETURNING id\n )\n INSERT INTO refs(id, head, created)\n VALUES ($1, (SELECT id FROM snapshot), NOW())\n ", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Left": [ 8 | "Uuid", 9 | "Jsonb", 10 | "Text" 11 | ] 12 | }, 13 | "nullable": [] 14 | }, 15 | "hash": "a8cb9f26893bbf784cf8a71090e64c3603e238ea6786d327f64ae04aef205198" 16 | } 17 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-cca19c531258c9500e4c27e139d15f8bfea54d7fd1b08728debfcacd5de174b4.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "\n INSERT INTO permissions(subject, object, level)\n VALUES ($1, $2, 'own')\n ", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Left": [ 8 | "Text", 9 | "Uuid" 10 | ] 11 | }, 12 | "nullable": [] 13 | }, 14 | "hash": "cca19c531258c9500e4c27e139d15f8bfea54d7fd1b08728debfcacd5de174b4" 15 | } 16 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-cd63d277bd2ae2905790e11cddb4b9bcb5b56e952b854a75dc724e1c253afcf5.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "\n DELETE FROM permissions WHERE object = $1 AND level < 'own'\n ", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Left": [ 8 | "Uuid" 9 | ] 10 | }, 11 | "nullable": [] 12 | }, 13 | "hash": "cd63d277bd2ae2905790e11cddb4b9bcb5b56e952b854a75dc724e1c253afcf5" 14 | } 15 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-e75b5c0a7da4bc3c0f52a62179d15289fd31d08d48d7a99d37cb1a6414656e7d.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "\n SELECT MAX(level) AS \"max: PermissionLevel\" FROM permissions\n WHERE object = $1 AND (subject IS NULL OR subject = $2)\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "ordinal": 0, 8 | "name": "max: PermissionLevel", 9 | "type_info": { 10 | "Custom": { 11 | "name": "permission_level", 12 | "kind": { 13 | "Enum": [ 14 | "read", 15 | "write", 16 | "maintain", 17 | "own" 18 | ] 19 | } 20 | } 21 | } 22 | } 23 | ], 24 | "parameters": { 25 | "Left": [ 26 | "Uuid", 27 | "Text" 28 | ] 29 | }, 30 | "nullable": [ 31 | null 32 | ] 33 | }, 34 | "hash": "e75b5c0a7da4bc3c0f52a62179d15289fd31d08d48d7a99d37cb1a6414656e7d" 35 | } 36 | -------------------------------------------------------------------------------- /packages/backend/.sqlx/query-eea510d03cc559aa11d46aafe38f57789f5c2e791800f78a751602cc8336c84f.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "PostgreSQL", 3 | "query": "\n INSERT INTO permissions(subject, object, level)\n SELECT * FROM UNNEST($1::text[], $2::uuid[], $3::permission_level[])\n ", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Left": [ 8 | "TextArray", 9 | "UuidArray", 10 | { 11 | "Custom": { 12 | "name": "permission_level[]", 13 | "kind": { 14 | "Array": { 15 | "Custom": { 16 | "name": "permission_level", 17 | "kind": { 18 | "Enum": [ 19 | "read", 20 | "write", 21 | "maintain", 22 | "own" 23 | ] 24 | } 25 | } 26 | } 27 | } 28 | } 29 | } 30 | ] 31 | }, 32 | "nullable": [] 33 | }, 34 | "hash": "eea510d03cc559aa11d46aafe38f57789f5c2e791800f78a751602cc8336c84f" 35 | } 36 | -------------------------------------------------------------------------------- /packages/backend/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "catcolab-backend" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | axum = "0.7.7" 8 | chrono = { version = "0.4.40", features = ["serde"] } 9 | dotenvy = "0.15.7" 10 | firebase-auth = { version = "0.4.3", default-features = false } 11 | http = "1.1.0" 12 | hyper = { version = "1.4.1", features = ["server"] } 13 | jsonrpsee = "0.24.6" 14 | jsonrpsee-server = "0.24.6" 15 | qubit = "0.10.2" 16 | regex = "1.11.1" 17 | serde = { version = "1.0.210", features = ["derive"] } 18 | serde_json = "1.0.128" 19 | socketioxide = { version = "0.14.1", features = ["tracing"] } 20 | sqlx = { version = "0.8.2", features = [ 21 | "runtime-tokio", 22 | "tls-native-tls", 23 | "postgres", 24 | "uuid", 25 | "json", 26 | "chrono", 27 | ] } 28 | thiserror = "1.0.64" 29 | tokio = { version = "1.40.0", features = ["full"] } 30 | tower = { version = "0.5.1", features = ["util"] } 31 | tower-http = { version = "0.6.1", features = ["cors", "trace"] } 32 | tracing = "0.1.40" 33 | tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } 34 | ts-rs = { version = "10.1.0", features = [ 35 | "serde-json-impl", 36 | "uuid-impl", 37 | "chrono-impl", 38 | ] } 39 | uuid = { version = "1.10.0", features = ["v7", "serde"] } 40 | -------------------------------------------------------------------------------- /packages/backend/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | rustToolchain, 4 | ... 5 | }: 6 | let 7 | # Why do this instaed of creating a global overlay for rustc and cargo? 8 | # 9 | # Fenix can provide a rustc and cargo, however they are derivations, which means they are lacking many 10 | # of the attributes that other packages expect them to have. So creating an overlay with the fenix rustc 11 | # and cargo will cause other packages to break. 12 | # 13 | # The correct way to handle this is to use fenix to configure pkgs.rustPlatform, which other packages 14 | # should be using. However crate2nix does not use this API and instaed uses the older pkgs.buildRustCrate. 15 | # As a result we need to manually pass the rust toolchain to the cargoNix callsite. 16 | buildRustCrateForPkgs = 17 | crate: 18 | pkgs.buildRustCrate.override { 19 | rustc = rustToolchain; 20 | cargo = rustToolchain; 21 | }; 22 | 23 | cargoNix = import ../../Cargo.nix { inherit pkgs buildRustCrateForPkgs; }; 24 | backend = cargoNix.workspaceMembers.catcolab-backend.build; 25 | in 26 | backend 27 | -------------------------------------------------------------------------------- /packages/backend/pkg/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "catcolab-api", 3 | "version": "0.1.0", 4 | "author": "Evan Patterson ", 5 | "license": "MIT", 6 | "main": "src/index.ts", 7 | "scripts": { 8 | "build": "tsc -b" 9 | }, 10 | "dependencies": { 11 | "@qubit-rs/client": "^0.4.4", 12 | "typescript": "^5.6.3" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/backend/pkg/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | '@qubit-rs/client': 12 | specifier: ^0.4.4 13 | version: 0.4.4 14 | typescript: 15 | specifier: ^5.6.3 16 | version: 5.6.3 17 | 18 | packages: 19 | 20 | '@qubit-rs/client@0.4.4': 21 | resolution: {integrity: sha512-AdaF25aGRU4YkYYxxARH3eYlezzHhGECTFGZ5/zEc9y+iPxdIaaWf4/m8uEtdbzjMEsGaA4vVVd1kuriK6sDzQ==} 22 | 23 | typescript@5.6.3: 24 | resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} 25 | engines: {node: '>=14.17'} 26 | hasBin: true 27 | 28 | snapshots: 29 | 30 | '@qubit-rs/client@0.4.4': {} 31 | 32 | typescript@5.6.3: {} 33 | -------------------------------------------------------------------------------- /packages/backend/pkg/src/NewPermissions.ts: -------------------------------------------------------------------------------- 1 | // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. 2 | import type { PermissionLevel } from "./PermissionLevel"; 3 | 4 | /** 5 | * A new set of permissions to assign to a document. 6 | */ 7 | export type NewPermissions = { 8 | /** 9 | * Base permission level for any person, logged in or not. 10 | */ 11 | anyone: PermissionLevel | null, 12 | /** Permission levels for users. 13 | 14 | A mapping from user IDs to permission levels. 15 | */ 16 | users: { [key in string]?: PermissionLevel }, }; 17 | -------------------------------------------------------------------------------- /packages/backend/pkg/src/Paginated.ts: -------------------------------------------------------------------------------- 1 | // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. 2 | 3 | /** 4 | * A page of items along with pagination metadata. 5 | */ 6 | export type Paginated = { 7 | /** 8 | * The total number of items matching the query criteria. 9 | */ 10 | total: number, 11 | /** 12 | * The number of items skipped. 13 | */ 14 | offset: number, 15 | /** 16 | * The items in the current page. 17 | */ 18 | items: Array, }; 19 | -------------------------------------------------------------------------------- /packages/backend/pkg/src/PermissionLevel.ts: -------------------------------------------------------------------------------- 1 | // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. 2 | 3 | /** 4 | * Levels of permission that a user can have on a document. 5 | */ 6 | export type PermissionLevel = "Read" | "Write" | "Maintain" | "Own"; 7 | -------------------------------------------------------------------------------- /packages/backend/pkg/src/Permissions.ts: -------------------------------------------------------------------------------- 1 | // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. 2 | import type { PermissionLevel } from "./PermissionLevel"; 3 | import type { UserPermissions } from "./UserPermissions"; 4 | 5 | /** 6 | * Permissions set on a document. 7 | */ 8 | export type Permissions = { 9 | /** 10 | * Base permission level for any person, logged in or not. 11 | */ 12 | anyone: PermissionLevel | null, 13 | /** 14 | * Permission level for the current user. 15 | */ 16 | user: PermissionLevel | null, 17 | /** Permission levels for all other users. 18 | 19 | Only owners of the document have access to this information. 20 | */ 21 | users: Array | null, }; 22 | -------------------------------------------------------------------------------- /packages/backend/pkg/src/RefContent.ts: -------------------------------------------------------------------------------- 1 | // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. 2 | import type { JsonValue } from "./serde_json/JsonValue"; 3 | 4 | /** 5 | * A document ref along with its content. 6 | */ 7 | export type RefContent = { refId: string, content: JsonValue, }; 8 | -------------------------------------------------------------------------------- /packages/backend/pkg/src/RefDoc.ts: -------------------------------------------------------------------------------- 1 | // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. 2 | import type { JsonValue } from "./serde_json/JsonValue"; 3 | import type { Permissions } from "./Permissions"; 4 | 5 | /** 6 | * Document identified by a ref. 7 | */ 8 | export type RefDoc = { "tag": "Readonly", content: JsonValue, permissions: Permissions, } | { "tag": "Live", docId: string, permissions: Permissions, }; 9 | -------------------------------------------------------------------------------- /packages/backend/pkg/src/RefQueryParams.ts: -------------------------------------------------------------------------------- 1 | // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. 2 | import type { PermissionLevel } from "./PermissionLevel"; 3 | 4 | /** 5 | * Parameters for filtering a search of refs 6 | */ 7 | export type RefQueryParams = { ownerUsernameQuery: string | null, refNameQuery: string | null, searcherMinLevel: PermissionLevel | null, includePublicDocuments: boolean | null, limit: number | null, offset: number | null, }; 8 | -------------------------------------------------------------------------------- /packages/backend/pkg/src/RefStub.ts: -------------------------------------------------------------------------------- 1 | // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. 2 | import type { PermissionLevel } from "./PermissionLevel"; 3 | import type { UserSummary } from "./UserSummary"; 4 | 5 | /** 6 | * A subset of user relevant information about a ref. Used for showing 7 | * users information on a variety of refs without having to load whole 8 | * refs. 9 | */ 10 | export type RefStub = { name: string, typeName: string, refId: string, permissionLevel: PermissionLevel, owner: UserSummary | null, createdAt: string, }; 11 | -------------------------------------------------------------------------------- /packages/backend/pkg/src/RpcResult.ts: -------------------------------------------------------------------------------- 1 | // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. 2 | 3 | /** 4 | * Result returned by an RPC handler. 5 | */ 6 | export type RpcResult = { "tag": "Ok", content: T, } | { "tag": "Err", code: number, message: string, }; 7 | -------------------------------------------------------------------------------- /packages/backend/pkg/src/UserPermissions.ts: -------------------------------------------------------------------------------- 1 | // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. 2 | import type { PermissionLevel } from "./PermissionLevel"; 3 | import type { UserSummary } from "./UserSummary"; 4 | 5 | /** 6 | * Permissions of a user on a document. 7 | */ 8 | export type UserPermissions = { user: UserSummary, level: PermissionLevel, }; 9 | -------------------------------------------------------------------------------- /packages/backend/pkg/src/UserProfile.ts: -------------------------------------------------------------------------------- 1 | // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. 2 | 3 | /** 4 | * Data of a user profile. 5 | */ 6 | export type UserProfile = { username: string | null, displayName: string | null, }; 7 | -------------------------------------------------------------------------------- /packages/backend/pkg/src/UserSummary.ts: -------------------------------------------------------------------------------- 1 | // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. 2 | 3 | /** Summary of a user. 4 | 5 | The minimal information needed to uniquely identify a user and display the user 6 | in human-readable form. 7 | */ 8 | export type UserSummary = { id: string, username: string | null, displayName: string | null, }; 9 | -------------------------------------------------------------------------------- /packages/backend/pkg/src/UsernameStatus.ts: -------------------------------------------------------------------------------- 1 | // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. 2 | 3 | /** 4 | * Status of a username. 5 | */ 6 | export type UsernameStatus = "Available" | "Unavailable" | "Invalid"; 7 | -------------------------------------------------------------------------------- /packages/backend/pkg/src/serde_json/JsonValue.ts: -------------------------------------------------------------------------------- 1 | // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. 2 | 3 | export type JsonValue = number | string | boolean | Array | { [key in string]?: JsonValue } | null; 4 | -------------------------------------------------------------------------------- /packages/backend/pkg/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "NodeNext", 5 | "moduleResolution": "Node16", 6 | "esModuleInterop": true, 7 | "noEmit": true, 8 | "allowImportingTsExtensions": true, 9 | "outDir": "./dist", 10 | 11 | "strict": true, 12 | "skipLibCheck": true, 13 | "noUnusedLocals": true, 14 | "noUnusedParameters": true, 15 | "noUncheckedIndexedAccess": true, 16 | "noFallthroughCasesInSwitch": true 17 | }, 18 | "include": ["src/**/*.ts"] 19 | } 20 | -------------------------------------------------------------------------------- /packages/backend/src/socket.rs: -------------------------------------------------------------------------------- 1 | use socketioxide::extract::{Data, SocketRef}; 2 | use tracing::{error, info}; 3 | 4 | use super::app::AppState; 5 | use super::document as doc; 6 | 7 | /// Set up the socket that communicates with the Automerge doc server. 8 | pub fn setup_automerge_socket(state: AppState) { 9 | let io = state.automerge_io.clone(); 10 | 11 | io.ns("/", |socket: SocketRef| { 12 | info!("Automerge socket connected at namespace {}", socket.ns()); 13 | 14 | socket.on("autosave", |_: SocketRef, Data::(data)| async move { 15 | if let Err(err) = doc::autosave(state, data).await { 16 | error!("Autosave failed with error: {}", err); 17 | } 18 | }); 19 | }); 20 | } 21 | -------------------------------------------------------------------------------- /packages/catlog-wasm/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | bin/ 4 | pkg/ 5 | wasm-pack.log 6 | -------------------------------------------------------------------------------- /packages/catlog-wasm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "catlog-wasm" 3 | version = "0.1.0" 4 | authors = ["Evan Patterson "] 5 | edition = "2024" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "rlib"] 9 | 10 | [features] 11 | default = ["console_error_panic_hook"] 12 | 13 | [dependencies] 14 | all-the-same = "1.1.0" 15 | catlog = { path = "../catlog", features = ["ode", "serde-wasm"] } 16 | console_error_panic_hook = { version = "0.1.7", optional = true } 17 | derive_more = { version = "1", features = ["from", "try_into"] } 18 | egglog = { version = "0.4", default-features = false, features = [ 19 | "wasm-bindgen", 20 | ] } 21 | getrandom = { version = "0.2", features = ["js"] } 22 | js-sys = "0.3.77" 23 | nonempty = { version = "0.10", features = ["serialize"] } 24 | notebook-types = { version = "0.1.0", path = "../notebook-types" } 25 | serde = { version = "1", features = ["derive"] } 26 | tsify = { version = "0.5", features = ["js"] } 27 | ustr = "1" 28 | uuid = { version = "=1.11", features = ["v7", "serde", "js"] } 29 | wasm-bindgen = "0.2.100" 30 | 31 | [dev-dependencies] 32 | wasm-bindgen-test = "0.3.50" 33 | -------------------------------------------------------------------------------- /packages/catlog-wasm/src/analyses.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use tsify::Tsify; 3 | use uuid::Uuid; 4 | 5 | use super::result::JsResult; 6 | use catlog::stdlib::analyses; 7 | 8 | #[derive(Serialize, Deserialize, Tsify)] 9 | #[tsify(into_wasm_abi, from_wasm_abi)] 10 | pub struct ODEResult(pub JsResult, String>); 11 | 12 | #[derive(Serialize, Deserialize, Tsify)] 13 | #[tsify(into_wasm_abi, from_wasm_abi)] 14 | pub struct LotkaVolterraModelData(pub analyses::ode::LotkaVolterraProblemData); 15 | 16 | #[derive(Serialize, Deserialize, Tsify)] 17 | #[tsify(into_wasm_abi, from_wasm_abi)] 18 | pub struct MassActionModelData(pub analyses::ode::MassActionProblemData); 19 | -------------------------------------------------------------------------------- /packages/catlog-wasm/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod result; 2 | 3 | pub mod model; 4 | pub mod model_diagram; 5 | pub mod model_morphism; 6 | pub mod theory; 7 | 8 | pub mod analyses; 9 | #[allow(clippy::new_without_default)] 10 | pub mod theories; 11 | 12 | use wasm_bindgen::prelude::*; 13 | 14 | /** Produce type defs for dependencies supporting `serde` but not `tsify`. 15 | 16 | Somewhat amazingly, the type system in TypeScript can express the constraint 17 | that an array be nonempty, with certain usage caveats: 18 | 19 | https://stackoverflow.com/q/56006111 20 | 21 | For now, though, we will not attempt to enforce this in the TypeScript layer. 22 | */ 23 | #[wasm_bindgen(typescript_custom_section)] 24 | const TS_APPEND_CONTENT: &'static str = r#" 25 | export type Uuid = string; 26 | export type Ustr = string; 27 | 28 | export type NonEmpty = Array; 29 | "#; 30 | 31 | #[wasm_bindgen] 32 | pub fn set_panic_hook() { 33 | // When the `console_error_panic_hook` feature is enabled, we can call the 34 | // `set_panic_hook` function at least once during initialization, and then 35 | // we will get better error messages if our code ever panics. 36 | // 37 | // For more details see 38 | // https://github.com/rustwasm/console_error_panic_hook#readme 39 | #[cfg(feature = "console_error_panic_hook")] 40 | console_error_panic_hook::set_once(); 41 | } 42 | -------------------------------------------------------------------------------- /packages/catlog-wasm/src/result.rs: -------------------------------------------------------------------------------- 1 | //! Result of fallible computation that translates to/from JavaScript. 2 | 3 | use serde::{Deserialize, Serialize}; 4 | use tsify::Tsify; 5 | 6 | /** A `Result`-like type that translates to/from JavaScript. 7 | 8 | In `wasm-bindgen`, returning a [`Result`] raises an exception in JavaScript when 9 | the `Err` variant is given: 10 | 11 | 12 | 13 | When an error should be handled in the UI, it is often more convenient to return 14 | an error value than to raise an exception. That's what this enum does. 15 | */ 16 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Tsify)] 17 | #[serde(tag = "tag", content = "content")] 18 | #[tsify(into_wasm_abi, from_wasm_abi)] 19 | pub enum JsResult { 20 | /// Contains the success value 21 | Ok(T), 22 | 23 | /// Contains the error value 24 | Err(E), 25 | } 26 | 27 | impl From> for JsResult { 28 | fn from(value: Result) -> Self { 29 | match value { 30 | Result::Ok(x) => JsResult::Ok(x), 31 | Result::Err(x) => JsResult::Err(x), 32 | } 33 | } 34 | } 35 | 36 | impl From> for JsResult { 37 | fn from(value: Option) -> Self { 38 | match value { 39 | Option::Some(x) => JsResult::Ok(x), 40 | Option::None => JsResult::Err(()), 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/catlog-wasm/tests/web.rs: -------------------------------------------------------------------------------- 1 | //! Test suite for the Web and headless browsers. 2 | 3 | #![cfg(target_arch = "wasm32")] 4 | 5 | extern crate wasm_bindgen_test; 6 | use wasm_bindgen_test::*; 7 | 8 | wasm_bindgen_test_configure!(run_in_browser); 9 | 10 | #[wasm_bindgen_test] 11 | fn pass() { 12 | assert_eq!(1 + 1, 2); 13 | } 14 | -------------------------------------------------------------------------------- /packages/catlog/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | # MSVC Windows builds of rustc generate these, which store debugging information 13 | *.pdb 14 | -------------------------------------------------------------------------------- /packages/catlog/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "catlog" 3 | description = "A toolbox for catgorical logic based on double theories" 4 | authors = ["Evan Patterson"] 5 | version = "0.1.0" 6 | edition = "2024" 7 | 8 | [features] 9 | ode = ["dep:ode_solvers", "dep:nalgebra"] 10 | serde = ["dep:serde", "nonempty/serialize", "ustr/serde"] 11 | serde-wasm = ["serde", "dep:wasm-bindgen", "dep:tsify"] 12 | 13 | [dependencies] 14 | derivative = "2" 15 | derive_more = { version = "1", features = ["from", "into"] } 16 | duplicate = "2" 17 | egglog = { version = "0.4", default-features = false } 18 | ego-tree = "0.10" 19 | itertools = "0.14" 20 | nalgebra = { version = "0.33", optional = true } 21 | nonempty = "0.10" 22 | num-traits = "0.2" 23 | ode_solvers = { version = "0.5.0", optional = true } 24 | ref-cast = "1" 25 | serde = { version = "1", features = ["derive"], optional = true } 26 | thiserror = "1" 27 | tsify = { version = "0.5", features = ["js"], optional = true } 28 | ustr = "1" 29 | uuid = { version = "=1.11", optional = true } 30 | wasm-bindgen = { version = "0.2.100", optional = true } 31 | 32 | [dev-dependencies] 33 | expect-test = "1.5" 34 | textplots = "0.8.6" 35 | -------------------------------------------------------------------------------- /packages/catlog/src/dbl/mod.rs: -------------------------------------------------------------------------------- 1 | //! Double category theory and two-dimensional categorical logic. 2 | 3 | pub mod category; 4 | pub mod graph; 5 | pub mod tree; 6 | 7 | pub mod model; 8 | pub mod model_diagram; 9 | pub mod model_morphism; 10 | pub mod theory; 11 | -------------------------------------------------------------------------------- /packages/catlog/src/lib.rs: -------------------------------------------------------------------------------- 1 | /*! A toolbox for categorical logic based on double-categorical theories. 2 | 3 | # Organization 4 | 5 | While the purpose of this package is to implement double theories and their 6 | models and morphisms, a certain amount of lower-dimensional category theory is 7 | necessary as background. The package is organized into top-level modules 8 | according to dimensionality: 9 | 10 | 0. [`zero`]: Sets and mappings, known semi-seriously as zero-dimensional 11 | category theory, and a bit of abstract algebra. 12 | 1. [`one`]: Ordinary, or one-dimensional, category theory. 13 | 2. [`dbl`]: Double category theory. 14 | 15 | The prerequisite modules make no pretence to completeness, but if they become 16 | sufficiently useful in their own right, they may be spun off into their own 17 | crates. 18 | */ 19 | 20 | // Unicode identifiers. 21 | #![allow(mixed_script_confusables)] 22 | #![allow(confusable_idents)] 23 | #![warn(missing_docs)] 24 | 25 | #[cfg(doc)] 26 | pub mod refs; 27 | 28 | pub mod egglog_util; 29 | pub mod validate; 30 | 31 | pub mod dbl; 32 | pub mod one; 33 | pub mod simulate; 34 | pub mod stdlib; 35 | pub mod zero; 36 | -------------------------------------------------------------------------------- /packages/catlog/src/one/mod.rs: -------------------------------------------------------------------------------- 1 | //! Category theory in dimension one. 2 | 3 | pub mod category; 4 | pub mod fp_category; 5 | pub mod graph; 6 | pub mod graph_algorithms; 7 | pub mod path; 8 | pub mod tree; 9 | pub mod tree_algorithms; 10 | 11 | pub use self::category::*; 12 | pub use self::graph::*; 13 | pub use self::path::*; 14 | -------------------------------------------------------------------------------- /packages/catlog/src/simulate/mod.rs: -------------------------------------------------------------------------------- 1 | /*! Simulation of dynamical systems. 2 | 3 | "Modeling and simulation" is a major part of science and engineering. The 4 | purpose of the `catlog` crate is to specify models using the machinery of 5 | double-categorical logic. This module simulates dynamical systems derived from 6 | models. It is intended as a stopgap pending interoperation with a language 7 | having a better scientific computing ecosystem than Rust, such as Julia. 8 | However, if it does stick around it should eventually become its own crate. For 9 | now it's convenient to keep everything in the same place. 10 | */ 11 | 12 | #[cfg(feature = "ode")] 13 | pub mod ode; 14 | -------------------------------------------------------------------------------- /packages/catlog/src/stdlib/analyses/mod.rs: -------------------------------------------------------------------------------- 1 | //! Various analyses that can be performed on models. 2 | 3 | #[cfg(feature = "ode")] 4 | pub mod ode; 5 | -------------------------------------------------------------------------------- /packages/catlog/src/stdlib/mod.rs: -------------------------------------------------------------------------------- 1 | //! Standard library of double theories, models, and analyses. 2 | 3 | pub mod models; 4 | pub mod theories; 5 | 6 | pub mod analyses; 7 | 8 | pub use models::*; 9 | pub use theories::*; 10 | -------------------------------------------------------------------------------- /packages/catlog/src/zero/mod.rs: -------------------------------------------------------------------------------- 1 | //! Sets and functions, and a little abstract algebra. 2 | 3 | pub mod alg; 4 | pub mod column; 5 | pub mod rig; 6 | pub mod set; 7 | 8 | pub use self::column::*; 9 | pub use self::set::*; 10 | -------------------------------------------------------------------------------- /packages/frontend/.env.development: -------------------------------------------------------------------------------- 1 | VITE_APP_TITLE="CatColab [dev]" 2 | 3 | VITE_SERVER_URL=http://127.0.0.1:8000 4 | VITE_AUTOMERGE_REPO_URL=ws://127.0.0.1:8010 5 | 6 | VITE_FIREBASE_OPTIONS='{ 7 | "apiKey": "AIzaSyAsFvrzQg_V8cVhGi9PNkZiueGF0iDH9Ws", 8 | "authDomain": "catcolab-next.firebaseapp.com", 9 | "projectId": "catcolab-next", 10 | "storageBucket": "catcolab-next.appspot.com", 11 | "messagingSenderId": "666779369059", 12 | "appId": "1:666779369059:web:f0319c1513d77996650256", 13 | "measurementId": "G-WKFYSTDYLF" 14 | }' 15 | -------------------------------------------------------------------------------- /packages/frontend/.env.production: -------------------------------------------------------------------------------- 1 | VITE_APP_TITLE="CatColab" 2 | 3 | VITE_SERVER_URL=https://backend.catcolab.org 4 | VITE_AUTOMERGE_REPO_URL=wss://automerge.catcolab.org 5 | 6 | VITE_FIREBASE_OPTIONS='{ 7 | "apiKey": "AIzaSyA9zb9RPri76DXB0Bnq3LZYa2u61l-K9oA", 8 | "authDomain": "catcolab-prod.firebaseapp.com", 9 | "projectId": "catcolab-prod", 10 | "storageBucket": "catcolab-prod.firebasestorage.app", 11 | "messagingSenderId": "192417001062", 12 | "appId": "1:192417001062:web:9089adb3abceac686187a7", 13 | "measurementId": "G-TQXNCW7D84" 14 | }' 15 | -------------------------------------------------------------------------------- /packages/frontend/.env.staging: -------------------------------------------------------------------------------- 1 | VITE_APP_TITLE="CatColab [next]" 2 | 3 | VITE_SERVER_URL=https://backend-next.catcolab.org 4 | VITE_AUTOMERGE_REPO_URL=wss://automerge-next.catcolab.org 5 | 6 | VITE_FIREBASE_OPTIONS='{ 7 | "apiKey": "AIzaSyAsFvrzQg_V8cVhGi9PNkZiueGF0iDH9Ws", 8 | "authDomain": "catcolab-next.firebaseapp.com", 9 | "projectId": "catcolab-next", 10 | "storageBucket": "catcolab-next.appspot.com", 11 | "messagingSenderId": "666779369059", 12 | "appId": "1:666779369059:web:f0319c1513d77996650256", 13 | "measurementId": "G-WKFYSTDYLF" 14 | }' 15 | -------------------------------------------------------------------------------- /packages/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /packages/frontend/README.md: -------------------------------------------------------------------------------- 1 | # CatColab frontend 2 | 3 | This directory contains the web frontend for the CatColab application, written 4 | in TypeScript using the framework [Solid.js](https://www.solidjs.com/). 5 | 6 | ## Setup 7 | 8 | Install Rust and [pnpm](https://pnpm.io/), then run 9 | 10 | ```sh 11 | cd packages/frontend 12 | pnpm install 13 | pnpm run build 14 | ``` 15 | 16 | This command compiles the Rust dependencies to WebAssembly and then builds the 17 | frontend bundle. 18 | 19 | ## Usage 20 | 21 | To develop the frontend locally, run 22 | 23 | ```sh 24 | pnpm run dev --mode $MODE 25 | ``` 26 | 27 | where `$MODE` is replaced with one of the following: 28 | 29 | - `development`: assumes that the [backend](../backend/) is running locally (the 30 | default if `--mode` is omitted) 31 | - `staging`: uses the staging deployment of CatColab at `next.catcolab.org` 32 | (recommended for fronten dev) 33 | - `production`: uses the production deployment of CatColab at `catcolab.org` 34 | (*not* recommended) 35 | -------------------------------------------------------------------------------- /packages/frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %VITE_APP_TITLE% 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/frontend/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | publish = "dist/" 3 | command = "rustup toolchain install stable && rustup target add wasm32-unknown-unknown && npm run build" 4 | 5 | [build.environment] 6 | RUST_VERSION = "1.81.0" 7 | -------------------------------------------------------------------------------- /packages/frontend/public/topos_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ToposInstitute/CatColab/8e6e52655f51b402d22d43a52807a3529e131402/packages/frontend/public/topos_icon.png -------------------------------------------------------------------------------- /packages/frontend/src/analysis/context.ts: -------------------------------------------------------------------------------- 1 | import { type Accessor, createContext } from "solid-js"; 2 | 3 | import type { LiveAnalysisDocument } from "./document"; 4 | 5 | /** Context for a live analysis. */ 6 | export const LiveAnalysisContext = createContext>(); 7 | -------------------------------------------------------------------------------- /packages/frontend/src/analysis/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./types"; 2 | export * from "./document"; 3 | export * from "./context"; 4 | -------------------------------------------------------------------------------- /packages/frontend/src/api/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from "solid-js"; 2 | import invariant from "tiny-invariant"; 3 | 4 | import type { Api } from "./types"; 5 | 6 | /** Context for the CatColab API. */ 7 | export const ApiContext = createContext(); 8 | 9 | /** Retrieve CatColab API from application context. */ 10 | export function useApi(): Api { 11 | const api = useContext(ApiContext); 12 | invariant(api, "CatColab API should be provided as context"); 13 | return api; 14 | } 15 | -------------------------------------------------------------------------------- /packages/frontend/src/api/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./context"; 2 | export * from "./document"; 3 | export * from "./rpc"; 4 | export * from "./types"; 5 | -------------------------------------------------------------------------------- /packages/frontend/src/components/alert.css: -------------------------------------------------------------------------------- 1 | .alert { 2 | --alert-color: black; 3 | 4 | box-sizing: border-box; 5 | border-left: 4px solid var(--alert-color); 6 | border-radius: 4px; 7 | padding-left: 1ex; 8 | } 9 | 10 | .alert-heading { 11 | display: flex; 12 | flex-direction: row; 13 | align-items: center; 14 | gap: 5px; 15 | 16 | color: var(--alert-color); 17 | font-weight: 500; 18 | } 19 | 20 | .alert-warning { 21 | --alert-color: rgb(102, 77, 3); 22 | } 23 | 24 | .alert-error { 25 | --alert-color: maroon; 26 | } 27 | -------------------------------------------------------------------------------- /packages/frontend/src/components/alert.tsx: -------------------------------------------------------------------------------- 1 | import { Alert } from "@kobalte/core/alert"; 2 | import type { JSX } from "solid-js"; 3 | 4 | import OctagonX from "lucide-solid/icons/octagon-x"; 5 | import TriangleAlert from "lucide-solid/icons/triangle-alert"; 6 | 7 | import "./alert.css"; 8 | 9 | /** Props for an alert component. */ 10 | export type AlertProps = { 11 | /** Title for the alert. */ 12 | title?: string; 13 | 14 | children?: JSX.Element; 15 | }; 16 | 17 | /** A warning alert. */ 18 | export const Warning = (props: AlertProps) => ( 19 | 20 |
21 | 22 | {props.title ?? "Warning"} 23 |
24 | {props.children} 25 |
26 | ); 27 | 28 | /** An error alert. 29 | 30 | Not called `Error` to avoid shadowing that name in JavaScript. 31 | */ 32 | export const ErrorAlert = (props: AlertProps) => ( 33 | 34 |
35 | 36 | {props.title ?? "Error"} 37 |
38 | {props.children} 39 |
40 | ); 41 | -------------------------------------------------------------------------------- /packages/frontend/src/components/completions.css: -------------------------------------------------------------------------------- 1 | .completion-list { 2 | list-style: none; 3 | padding: 0; 4 | margin: 0; 5 | } 6 | 7 | .completion-list li { 8 | cursor: pointer; 9 | padding: 5px; 10 | } 11 | 12 | .completion-list li.active { 13 | background: #f1f5f9; 14 | } 15 | 16 | .completion-head { 17 | display: flex; 18 | gap: 0.25em; 19 | justify-content: space-between; 20 | } 21 | 22 | .completion-description { 23 | font-size: 0.75em; 24 | color: dimgray; 25 | } 26 | 27 | .completion-shortcut { 28 | font-size: 0.9em; 29 | padding-left: 2ex; 30 | } 31 | 32 | .completion-empty { 33 | font-size: 0.75em; 34 | color: dimgray; 35 | } 36 | 37 | kbd.shortcut { 38 | display: flex; 39 | gap: 0.5em; 40 | } 41 | -------------------------------------------------------------------------------- /packages/frontend/src/components/dialog.css: -------------------------------------------------------------------------------- 1 | [data-corvu-dialog-overlay] { 2 | position: fixed; 3 | inset: 0px; 4 | } 5 | 6 | [data-corvu-dialog-content] { 7 | position: fixed; 8 | left: 50%; 9 | top: 50%; 10 | transform: translate(-50%, -50%); 11 | 12 | &.popup { 13 | padding: 1rem; 14 | } 15 | 16 | & .title-bar { 17 | display: flex; 18 | flex-direction: row; 19 | justify-content: space-between; 20 | padding-bottom: 0.5rem; 21 | } 22 | } 23 | 24 | [data-corvu-dialog-label] { 25 | font-size: larger; 26 | } 27 | 28 | [data-corvu-dialog-close] { 29 | & .lucide { 30 | color: dimgray; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/frontend/src/components/fixed_table_editor.css: -------------------------------------------------------------------------------- 1 | .fixed-table-editor { 2 | background: white; 3 | --border-color: lightgray; 4 | --cell-padding: 5px; 5 | 6 | border-collapse: collapse; 7 | 8 | & tr { 9 | border-top: 1px solid var(--border-color); 10 | border-bottom: 1px solid var(--border-color); 11 | } 12 | & td { 13 | padding: var(--cell-padding); 14 | border-left: 1px solid var(--border-color); 15 | } 16 | & th { 17 | font-weight: normal; 18 | padding: var(--cell-padding); 19 | } 20 | & th[scope="col"] { 21 | font-weight: 500; 22 | border-right: 1px solid var(--border-color); 23 | } 24 | & th[scope="col"]:last-child { 25 | border-right: none; 26 | } 27 | } 28 | 29 | .fixed-table-cell-input { 30 | background: transparent; 31 | border: none; 32 | outline: none; 33 | font: inherit; 34 | 35 | width: 100%; 36 | } 37 | 38 | .fixed-table-cell-input.invalid { 39 | background: #f8d7da; 40 | } 41 | -------------------------------------------------------------------------------- /packages/frontend/src/components/foldable.css: -------------------------------------------------------------------------------- 1 | .foldable-trigger { 2 | background: none; 3 | border: none; 4 | cursor: pointer; 5 | outline: none; 6 | font: inherit; 7 | padding: 0; 8 | 9 | display: flex; 10 | flex-direction: row; 11 | align-items: center; 12 | 13 | & .lucide { 14 | color: darkgray; 15 | } 16 | } 17 | 18 | [data-corvu-disclosure-content] { 19 | overflow: hidden; 20 | } 21 | [data-corvu-disclosure-content][data-collapsed] { 22 | animation: collapse 200ms linear; 23 | } 24 | [data-corvu-disclosure-content][data-expanded] { 25 | animation: expand 200ms linear; 26 | } 27 | 28 | @keyframes collapse { 29 | 0% { 30 | height: var(--corvu-disclosure-content-height); 31 | } 32 | 100% { 33 | height: 0px; 34 | } 35 | } 36 | 37 | @keyframes expand { 38 | 0% { 39 | height: 0px; 40 | } 41 | 100% { 42 | height: var(--corvu-disclosure-content-height); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/frontend/src/components/icon_button.css: -------------------------------------------------------------------------------- 1 | .icon-button { 2 | display: flex; 3 | flex-direction: row; 4 | justify-content: center; 5 | align-items: center; 6 | gap: 0.25rem; 7 | 8 | background: none; 9 | border: none; 10 | cursor: pointer; 11 | padding: 0; 12 | font-size: 1rem; 13 | 14 | &:hover:enabled { 15 | background: whitesmoke; 16 | border-radius: 5px; 17 | } 18 | } 19 | 20 | .tooltip-content { 21 | border-radius: 0.5rem; 22 | color: white; 23 | background-color: hsl(251, 9%, 23%); 24 | padding: 0.5rem; 25 | font-size: smaller; 26 | 27 | & p:first-child { 28 | margin-top: 0; 29 | } 30 | 31 | & p:last-child { 32 | margin-bottom: 0; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/frontend/src/components/id_input.css: -------------------------------------------------------------------------------- 1 | .id-input.anonymous { 2 | background-color: color-mix(in srgb, lightsteelblue, black 10%); 3 | color: white; 4 | font-variant-numeric: tabular-nums; 5 | 6 | padding: 3px; 7 | border-radius: 10px; 8 | } 9 | -------------------------------------------------------------------------------- /packages/frontend/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./alert"; 2 | export * from "./completions"; 3 | export * from "./dialog"; 4 | export * from "./fixed_table_editor"; 5 | export * from "./foldable"; 6 | export * from "./form"; 7 | export * from "./icon_button"; 8 | export * from "./id_input"; 9 | export * from "./inline_input"; 10 | export * from "./name_input"; 11 | export * from "./panel"; 12 | export * from "./resizable"; 13 | export * from "./rich_text_editor"; 14 | export * from "./json_import"; 15 | -------------------------------------------------------------------------------- /packages/frontend/src/components/inline_input.css: -------------------------------------------------------------------------------- 1 | .inline-input-container { 2 | display: inline-block; 3 | position: relative; 4 | } 5 | 6 | .inline-input-filler, 7 | .inline-input { 8 | border: none; 9 | border-bottom: 3px solid transparent; 10 | } 11 | 12 | .inline-input-filler { 13 | display: inline-block; 14 | visibility: hidden; 15 | white-space-collapse: preserve; 16 | padding-left: 5px; 17 | padding-right: 5px; 18 | min-width: 1ex; 19 | } 20 | 21 | .inline-input { 22 | position: absolute; 23 | top: 0; 24 | left: 0; 25 | right: 0; 26 | bottom: 0; 27 | 28 | background: transparent; 29 | outline: none; 30 | padding-left: 5px; 31 | padding-right: 5px; 32 | font: inherit; 33 | color: inherit; 34 | 35 | &.incomplete { 36 | border-bottom: 3px solid sandybrown; 37 | } 38 | &.invalid { 39 | border-bottom: 3px solid indianred; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/frontend/src/components/json_import.css: -------------------------------------------------------------------------------- 1 | .json_import { 2 | min-width: 20em; 3 | max-width: 80vw; 4 | margin: 0 auto; 5 | width: auto; 6 | } 7 | 8 | .json_import textarea { 9 | font-family: monospace; 10 | } 11 | -------------------------------------------------------------------------------- /packages/frontend/src/components/name_input.tsx: -------------------------------------------------------------------------------- 1 | import { createEffect, createSignal, splitProps } from "solid-js"; 2 | 3 | import { InlineInput, type InlineInputErrorStatus, type InlineInputOptions } from "./inline_input"; 4 | 5 | /** Input a human-readable name for a formal element. 6 | 7 | In CatColab, a valid name is any string that is *not* a decimal numeral, since 8 | the latter are used as anonymous identifiers. See the `IdInput` component. 9 | */ 10 | export function NameInput( 11 | allProps: { 12 | name: string; 13 | setName: (name: string) => void; 14 | } & Omit, 15 | ) { 16 | const [props, inputProps] = splitProps(allProps, ["name", "setName"]); 17 | 18 | const [text, setText] = createSignal(""); 19 | 20 | createEffect(() => setText(props.name)); 21 | 22 | const status = (): InlineInputErrorStatus => (text() === props.name ? null : "invalid"); 23 | 24 | const handleNewText = (text: string) => { 25 | if (!/^\d+$/.test(text)) { 26 | props.setName(text); 27 | } 28 | setText(text); 29 | }; 30 | 31 | return ; 32 | } 33 | -------------------------------------------------------------------------------- /packages/frontend/src/components/panel.css: -------------------------------------------------------------------------------- 1 | .panel-header { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | width: 100%; 6 | 7 | & .filler { 8 | flex: 1; 9 | } 10 | 11 | & .title { 12 | font-weight: 450; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/frontend/src/components/panel.tsx: -------------------------------------------------------------------------------- 1 | import { type JSX, Show } from "solid-js"; 2 | 3 | import "./panel.css"; 4 | 5 | /** Header for a panel with a title. 6 | */ 7 | export function PanelHeader(props: { 8 | /** Title shown at the top of the panel. */ 9 | title: string | JSX.Element; 10 | /** Additional header content. */ 11 | children?: JSX.Element; 12 | }) { 13 | return ( 14 |
15 | {props.title} 16 | 17 | 18 | {props.children} 19 | 20 |
21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /packages/frontend/src/components/resizable.css: -------------------------------------------------------------------------------- 1 | .resizable-handle { 2 | background: none; 3 | border: none; 4 | border-radius: 6px; 5 | padding: 3px; 6 | 7 | &.active { 8 | background: gray; 9 | } 10 | 11 | &:hover { 12 | background: gray; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/frontend/src/components/resizable.tsx: -------------------------------------------------------------------------------- 1 | import Resizable from "@corvu/resizable"; 2 | import { createSignal } from "solid-js"; 3 | 4 | import "./resizable.css"; 5 | 6 | type ResizableHandleProps = Parameters[0]["props"]; 7 | 8 | /** A styled wrapper for corvu's `Resizable.Handle`. 9 | */ 10 | export const ResizableHandle = (props: ResizableHandleProps) => { 11 | const [isResizing, setIsResizing] = createSignal(false); 12 | 13 | return ( 14 | setIsResizing(true)} 20 | onHandleDragEnd={() => setIsResizing(false)} 21 | {...props} 22 | /> 23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /packages/frontend/src/components/rich_text_editor.css: -------------------------------------------------------------------------------- 1 | /* ProseMirror CSS seems not to be documented, but see the following sources: 2 | 3 | - https://github.com/ProseMirror/prosemirror-view/blob/master/style/prosemirror.css 4 | - https://github.com/ProseMirror/prosemirror-example-setup/blob/master/style/style.css 5 | */ 6 | 7 | .ProseMirror { 8 | background: transparent; 9 | } 10 | 11 | .ProseMirror-focused { 12 | outline: none; 13 | } 14 | 15 | .ProseMirror[data-placeholder]::before { 16 | color: darkgray; 17 | position: absolute; 18 | content: attr(data-placeholder); 19 | pointer-events: none; 20 | } 21 | -------------------------------------------------------------------------------- /packages/frontend/src/components/spinner.css: -------------------------------------------------------------------------------- 1 | .spinner { 2 | border: 4px solid rgba(0, 0, 0, 0.1); 3 | border-top-color: #333; 4 | border-radius: 50%; 5 | width: 24px; 6 | height: 24px; 7 | margin: auto; 8 | animation: spin 1s linear infinite; 9 | will-change: transform; 10 | } 11 | 12 | @keyframes spin { 13 | to { 14 | transform: rotate(360deg); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/frontend/src/components/spinner.tsx: -------------------------------------------------------------------------------- 1 | import "./spinner.css"; 2 | 3 | export function Spinner() { 4 | return
; 5 | } 6 | -------------------------------------------------------------------------------- /packages/frontend/src/diagram/context.ts: -------------------------------------------------------------------------------- 1 | import { type Accessor, createContext } from "solid-js"; 2 | 3 | import type { LiveDiagramDocument } from "./document"; 4 | 5 | /** Context for a live diagram in a model. */ 6 | export const LiveDiagramContext = createContext>(); 7 | -------------------------------------------------------------------------------- /packages/frontend/src/diagram/diagram_editor.css: -------------------------------------------------------------------------------- 1 | .diagram-head { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | justify-content: space-between; 6 | 7 | & .title { 8 | font-size: var(--h1-font-size); 9 | } 10 | 11 | & .instance-of { 12 | font-size: var(--h4-font-size); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/frontend/src/diagram/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./types"; 2 | export * from "./document"; 3 | export * from "./context"; 4 | -------------------------------------------------------------------------------- /packages/frontend/src/diagram/morphism_cell_editor.css: -------------------------------------------------------------------------------- 1 | .diagram-morphism-decl { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | gap: 1ex; 6 | } 7 | -------------------------------------------------------------------------------- /packages/frontend/src/diagram/object_cell_editor.css: -------------------------------------------------------------------------------- 1 | .diagram-object-decl { 2 | display: flex; 3 | flex-direction: row; 4 | gap: 1ex; 5 | align-items: baseline; 6 | 7 | & .is-a:before { 8 | content: ":"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/frontend/src/diagram/object_input.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from "solid-js"; 2 | import invariant from "tiny-invariant"; 3 | 4 | import type { Ob, ObType } from "catlog-wasm"; 5 | import { type IdInputOptions, ObIdInput } from "../components"; 6 | import { LiveDiagramContext } from "./context"; 7 | 8 | /** Input a basic object in a diagram via its human-readable name. 9 | */ 10 | export function BasicObInput( 11 | props: { 12 | ob: Ob | null; 13 | setOb: (ob: Ob | null) => void; 14 | obType?: ObType; 15 | } & IdInputOptions, 16 | ) { 17 | const liveDiagram = useContext(LiveDiagramContext); 18 | invariant(liveDiagram, "Live diagram should be provided as context"); 19 | 20 | const completions = (): Ob[] | undefined => 21 | props.obType && liveDiagram().validatedDiagram()?.diagram.objectsWithType(props.obType); 22 | 23 | return ( 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /packages/frontend/src/help/help_container.css: -------------------------------------------------------------------------------- 1 | .help-container { 2 | & a { 3 | color: #007481; 4 | text-decoration: none; 5 | } 6 | 7 | & h1 { 8 | margin: 0.5em 0; 9 | } 10 | & h1:first-child { 11 | /* Title heading for page. */ 12 | margin-top: 0; 13 | } 14 | 15 | & h2 { 16 | margin: 0.67em 0; 17 | } 18 | 19 | & li:not(:last-child) { 20 | margin-bottom: 0.2em; 21 | } 22 | 23 | & dt { 24 | font-weight: bold; 25 | } 26 | & dd { 27 | margin-left: 0; 28 | } 29 | & dd:not(:last-child) { 30 | margin-bottom: 0.67em; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/frontend/src/help/help_container.tsx: -------------------------------------------------------------------------------- 1 | import type { JSX } from "solid-js"; 2 | 3 | import { BrandedToolbar } from "../page/toolbar"; 4 | 5 | import "./help_container.css"; 6 | 7 | export default function HelpContainer(props: { 8 | children?: JSX.Element; 9 | }) { 10 | return ( 11 |
12 | 13 |
{props.children}
14 |
15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /packages/frontend/src/help/quick_intro.mdx: -------------------------------------------------------------------------------- 1 | # Quick introduction 2 | 3 | Here are a few models created for a quick introduction to CatColab. 4 | 5 | To visualize any of these models, open the menu in the upper-left 6 | of their page, click "new analysis", click the + symbol on the new pane that appears, and select "Visualization." 7 | 8 | These models are view-only, which means that while you can edit them, your edits will not be saved. If you duplicate 9 | the model in the same menu, you'll get a copy you (if you're logged in) own and can edit, save, and re-permission as you like. 10 | 11 | - [The ontology of CatColab](https://catcolab.org/model/0194fbf4-fddf-7a12-b88b-33015d17d8e7) 12 | - [An exemplar instance of this ontology](https://catcolab.org/diagram/0194fbf9-8d8f-7330-8a51-5e9da2ce31bc) 13 | - [A large causal loop diagram](https://catcolab.org/model/0194cf7f-e59a-7281-a0d9-dce4c68114e4) 14 | - [A causal loop diagram with delays](https://catcolab.org/model/0194d7b1-2a7d-7be2-a338-b607c61bf0d4) 15 | - [An SEIRV stock-flow model](https://catcolab.org/model/0195001d-3c7d-7cb3-9019-2f411cfa2663) 16 | -------------------------------------------------------------------------------- /packages/frontend/src/help/routes.ts: -------------------------------------------------------------------------------- 1 | import type { RouteDefinition } from "@solidjs/router"; 2 | import { lazy } from "solid-js"; 3 | 4 | import { stdTheories } from "../stdlib"; 5 | import { lazyMdx } from "../util/mdx"; 6 | 7 | const theoryWithIdFilter = { 8 | id: (id: string) => stdTheories.has(id), 9 | }; 10 | 11 | export const helpRoutes: RouteDefinition[] = [ 12 | { 13 | path: "/", 14 | component: lazyMdx(() => import("./index.mdx")), 15 | }, 16 | { 17 | path: "/credits", 18 | component: lazyMdx(() => import("./credits.mdx")), 19 | }, 20 | { 21 | path: "/theories", 22 | component: lazy(() => import("./theories")), 23 | }, 24 | { 25 | path: "/theory/:id", 26 | matchFilters: theoryWithIdFilter, 27 | component: lazy(() => import("./theory")), 28 | }, 29 | { 30 | path: "/quick-intro", 31 | component: lazyMdx(() => import("./quick_intro.mdx")), 32 | }, 33 | ]; 34 | -------------------------------------------------------------------------------- /packages/frontend/src/help/theories.mdx: -------------------------------------------------------------------------------- 1 | # Logics 2 | 3 | Every model in CatColab is relative to a *logic*. The logic defines what kinds 4 | of objects and arrows you can specify in the model. A logic also comes with a 5 | set of built-in analyses that can be performed on its models. 6 | 7 | Here is the list of logics currently supported by CatColab, grouped by the 8 | domain to which each logic applies. 9 | -------------------------------------------------------------------------------- /packages/frontend/src/help/theory/causal-loop-delays.mdx: -------------------------------------------------------------------------------- 1 | import { A } from "@solidjs/router"; 2 | 3 | ## Description 4 | 5 | Causal loop diagrams with delays allow for delays or caesuras in the flow of 6 | causality, extending the basic notion of causal loop 7 | diagram. We expect to implement a delay differential equation-based 8 | semantics, but that is not standard in the literature. 9 | 10 | ## Further Reading 11 | 12 | - "The Systems Thinker" on [Balancing loops with 13 | delays](https://thesystemsthinker.com/balancing-loops-with-delays/) and 14 | [Guidelines for drawing causal loop 15 | diagrams](https://thesystemsthinker.com/guidelines-for-drawing-causal-loop-diagrams/) 16 | - Series of blog posts by John Baez on variants of causal loop diagrams using 17 | different monoids of *polarities* for the edges, starting 18 | [here](https://johncarlosbaez.wordpress.com/2024/11/02/polarities/) 19 | -------------------------------------------------------------------------------- /packages/frontend/src/help/theory/causal-loop.mdx: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | A causal loop diagram is a fundamental gadget in systems dynamics, 4 | representing a system of causally interacting variables. Variables 5 | can encourage or discourage each other according to positively, 6 | respectively, negatively signed edges. 7 | 8 | It's important in systems dynamics research to find feedback loops in 9 | causal loop diagrams. Positive feedback loops tend to produce unstable behavior, 10 | while negative feedback loops are stabilizing. CatColab supports this analysis 11 | by searching for morphisms from the causal loop diagram given by a free loop. 12 | This is the first demonstration in the tool of the general principle that edges in 13 | CatColab models can actually be composed as in a category, rather than forming 14 | a mere graph. 15 | 16 | Causal loop diagrams do not currently support instances, though we'd be 17 | curious to learn more about how they might be used in practice. 18 | 19 | ## Examples 20 | 21 | [Sustainable peace](https://catcolab.org/model/0194cf7f-e59a-7281-a0d9-dce4c68114e4) 22 | 23 | ## Further Reading 24 | 25 | - Wikipedia: [Causal loop diagram](https://en.wikipedia.org/wiki/Causal_loop_diagram) 26 | - Barbrook-Johnson, Penn, *Causal Loop Diagrams*, in *Systems Mapping*, 2022. [DOI:10.1007/978-3-031-01919-7](doi.org/10.1007/978-3-031-01919-7 27 | ) 28 | - Baez, Li, Libkind, et al, *A Categorical Framework for Modeling with Stock and Flow Diagrams*, [arXiv:2211.01290](https://arxiv.org/abs/2211.01290) -------------------------------------------------------------------------------- /packages/frontend/src/help/theory/empty.mdx: -------------------------------------------------------------------------------- 1 | import { A } from "@solidjs/router"; 2 | 3 | ## Description 4 | 5 | A model relative to the empty logic is called **informal** because it contains 6 | no formal content, only the rich text allowed in any model notebook. 7 | 8 | When you create a new model in CatColab, it will by default belong to this 9 | logic. You can start typing right away, but to add any structured content, 10 | you'll need to migrate to a nontrivial logic. Read more 11 | about the logics in CatColab 12 | -------------------------------------------------------------------------------- /packages/frontend/src/help/theory/indeterminate-causal-loop.mdx: -------------------------------------------------------------------------------- 1 | import { A } from "@solidjs/router"; 2 | 3 | ## Description 4 | 5 | Causal loop diagrams with indeterminates allow for causalities of unspecified or 6 | unknown sign, extending the basic notion of causal loop 7 | diagram. 8 | 9 | ## Further Reading 10 | 11 | - Series of blog posts by John Baez on variants of causal loop diagrams using 12 | different monoids of *polarities* for the edges, starting 13 | [here](https://johncarlosbaez.wordpress.com/2024/11/02/polarities/) 14 | -------------------------------------------------------------------------------- /packages/frontend/src/help/theory/olog.mdx: -------------------------------------------------------------------------------- 1 | import { A } from "@solidjs/router"; 2 | 3 | ## Description 4 | 5 | An **ontology log**, or **olog** for short, is a semi-formal representation of 6 | knowledge or a viewpoint. Ologs are expressed in a diagrammatic language based 7 | on boxes, known as **types**, and arrows, known as **aspects** of types. An olog 8 | is *semi*-formal because, while its types and aspects are formal structure, 9 | convention says that these should be labeled with natural text such that an 10 | arrow can be read from left to right as a grammatical sentence. 11 | 12 | Ologs are a simple language that is easy to get started with. An olog can be 13 | used as a stepping stone toward a more precise model, such as a database schema. 15 | 16 | An instance of an olog populate the types with particular entities, and thus 17 | defines a dataset. 18 | 19 | ## Examples 20 | 21 | - [Novels and novelists](https://catcolab.org/model/0194d356-a82a-7362-afd2-72e30864ba9d) 22 | - A diagram in the above ontology: [Some realist novels](https://catcolab.org/diagram/0194d361-d31b-76e3-be2c-ce1c1e6eade5) 23 | 24 | ## Further reading 25 | 26 | - Wikipedia: [Olog](https://en.wikipedia.org/wiki/Olog) 27 | - David I. Spivak and Robert E. Kent, 2012. 28 | Ologs: A categorical framework for knowledge representation. 29 | [arXiv:1102.1889](https://arxiv.org/abs/1102.1889) 30 | [DOI:10.1371/journal.pone.0024274](https://doi.org/10.1371/journal.pone.0024274) 31 | -------------------------------------------------------------------------------- /packages/frontend/src/help/theory/stock-flow.mdx: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Stock-flow diagrams are the crown jewel of systems dynamics, a rich language 4 | allowing the scientist to model a system of stocks of various quantities and 5 | flows between them, with the rate of the flows depending in complex ways on 6 | various stocks via *links*. 7 | 8 | In CatColab, we implement what we call *primitive* stock-flow diagrams, which do 9 | not allow for the auxiliary variables permitting flows to be arbitrary functions 10 | of the stocks that are characteristic in systems dynamics. We expect to 11 | implement this richer semantics in the future; meanwhile, primitive stock-flow 12 | diagrams already admit an interesting ODE semantics based on mass action 13 | kinetics. 14 | 15 | ## Further Reading 16 | 17 | - Wikipedia: [Stock and flow](https://en.wikipedia.org/wiki/Stock_and_flow) 18 | - Barbrook-Johnson, Penn, *System Dynamics*, in *Systems Mapping*, 2022. [DOI:10.1007/978-3-031-01919-7](https://doi.org/10.1007/978-3-031-01919-7) 19 | - Baez, Li, Libkind, et al, *A Categorical Framework for Modeling with Stock and Flow Diagrams*, [arXiv:2211.01290](https://arxiv.org/abs/2211.01290) 20 | -------------------------------------------------------------------------------- /packages/frontend/src/help/theory/unary-dec.mdx: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | The unary discrete exterior calculus (DEC) is an implementation of the unary part of 4 | the *discrete exterior calculus*, an approach to discrete differential geometry due initially 5 | to Anil Hirani. The Topos Institute and collaborators have a substantial DEC library 6 | called Decapodes implemented in the AlgebraicJulia project. The main purpose of the DEC in 7 | CatColab is to permit the user to build a PDE system via a structure editor which can then 8 | be solved in Decapodes, with the result animated right inside of CatColab. 9 | 10 | This workflow has been completed in some proofs of concept, but the need to run a Julia kernel 11 | means it's not particularly convenient for non-Julia users at this time. Instructions on 12 | the process to do so for those who like are available [on GitHub.](https://github.com/ToposInstitute/CatColab/tree/main/packages/algjulia-service) 13 | 14 | ## Examples 15 | 16 | An inviscid Navier-Stokes [equation](https://catcolab.org/analysis/0194d3b8-087b-7130-9c60-68edceff0848) on the sphere. 17 | 18 | ## Further Reading 19 | 20 | - Hirani's [PhD thesis](http://www.cs.jhu.edu/~misha/Fall09/Hirani03.pdf) 21 | - The [Decapodes](https://algebraicjulia.github.io/Decapodes.jl/dev/) documentation has many worked examples using AlgebraicJulia syntax directly 22 | -------------------------------------------------------------------------------- /packages/frontend/src/index.tsx: -------------------------------------------------------------------------------- 1 | /* @refresh reload */ 2 | import { render } from "solid-js/web"; 3 | 4 | import * as catlog from "catlog-wasm"; 5 | import App from "./App"; 6 | 7 | import "./index.css"; 8 | 9 | // Set panic hook for nice tracebacks from Rust core. 10 | catlog.set_panic_hook(); 11 | 12 | const root = document.getElementById("root"); 13 | 14 | // biome-ignore lint/style/noNonNullAssertion: we know that root exists 15 | render(() => , root!); 16 | -------------------------------------------------------------------------------- /packages/frontend/src/model/context.ts: -------------------------------------------------------------------------------- 1 | import { type Accessor, createContext } from "solid-js"; 2 | 3 | import type { LiveModelDocument } from "./document"; 4 | 5 | /** Context for a live model. */ 6 | export const LiveModelContext = createContext>(); 7 | -------------------------------------------------------------------------------- /packages/frontend/src/model/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./document"; 2 | export * from "./context"; 3 | export * from "./types"; 4 | -------------------------------------------------------------------------------- /packages/frontend/src/model/model_editor.css: -------------------------------------------------------------------------------- 1 | .model-head { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | justify-content: space-between; 6 | 7 | & .title { 8 | font-size: var(--h1-font-size); 9 | } 10 | 11 | & .theory-selector-trigger { 12 | font-size: var(--h4-font-size); 13 | max-width: 25%; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/frontend/src/model/morphism_cell_editor.css: -------------------------------------------------------------------------------- 1 | .morphism-decl { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | gap: 1ex; 6 | } 7 | -------------------------------------------------------------------------------- /packages/frontend/src/model/morphism_input.tsx: -------------------------------------------------------------------------------- 1 | import { splitProps, useContext } from "solid-js"; 2 | import invariant from "tiny-invariant"; 3 | 4 | import type { Mor, MorType } from "catlog-wasm"; 5 | import { type IdInputOptions, MorIdInput } from "../components"; 6 | import { LiveModelContext } from "./context"; 7 | 8 | /** Input a basic morphism via its human-readable name. 9 | */ 10 | export function BasicMorInput( 11 | allProps: { 12 | mor: Mor | null; 13 | setMor: (mor: Mor | null) => void; 14 | morType?: MorType; 15 | } & IdInputOptions, 16 | ) { 17 | const [props, otherProps] = splitProps(allProps, ["morType"]); 18 | 19 | const liveModel = useContext(LiveModelContext); 20 | invariant(liveModel, "Live model should be provided as context"); 21 | 22 | const completions = (): Mor[] | undefined => 23 | props.morType && liveModel().validatedModel()?.model.morphismsWithType(props.morType); 24 | 25 | return ( 26 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /packages/frontend/src/model/object_cell_editor.css: -------------------------------------------------------------------------------- 1 | .object-decl { 2 | width: fit-content; 3 | } 4 | -------------------------------------------------------------------------------- /packages/frontend/src/model/theory_selector.css: -------------------------------------------------------------------------------- 1 | .theory-selector { 2 | display: flex; 3 | flex-direction: column; 4 | gap: 10px; 5 | 6 | background-color: transparent; 7 | text-align: left; 8 | border-top: transparent; 9 | border-left: transparent; 10 | min-height: 30vh; 11 | 12 | & input[type="radio"] { 13 | position: absolute; 14 | opacity: 0; 15 | } 16 | 17 | & label:hover { 18 | color: var(--topos-color); 19 | cursor: pointer; 20 | } 21 | 22 | & .group { 23 | display: flex; 24 | flex-direction: column; 25 | gap: 5px; 26 | } 27 | 28 | & .group-name { 29 | font-weight: 500; 30 | padding-bottom: 1px; 31 | opacity: 35%; 32 | } 33 | 34 | & .theory { 35 | margin-left: 2ex; 36 | } 37 | 38 | & .description { 39 | color: rgb(106, 106, 106); 40 | font-size: 11px; 41 | text-align: left; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/frontend/src/model/types.ts: -------------------------------------------------------------------------------- 1 | import { v7 } from "uuid"; 2 | 3 | import type { ModelJudgment, MorType, ObType } from "catlog-wasm"; 4 | import { deepCopyJSON } from "../util/deepcopy"; 5 | 6 | /** Declaration of an object in a model. */ 7 | export type ObjectDecl = ModelJudgment & { 8 | tag: "object"; 9 | }; 10 | 11 | /** Create a new object declaration with the given object type. */ 12 | export const newObjectDecl = (obType: ObType): ObjectDecl => ({ 13 | tag: "object", 14 | id: v7(), 15 | name: "", 16 | obType, 17 | }); 18 | 19 | /** Declaration of a morphim in a model. */ 20 | export type MorphismDecl = ModelJudgment & { 21 | tag: "morphism"; 22 | }; 23 | 24 | /** Create a new morphism declaration with the given morphism type. */ 25 | export const newMorphismDecl = (morType: MorType): MorphismDecl => ({ 26 | tag: "morphism", 27 | id: v7(), 28 | name: "", 29 | morType, 30 | dom: null, 31 | cod: null, 32 | }); 33 | 34 | /** Duplicate a model judgment, creating a fresh UUID when applicable. */ 35 | export const duplicateModelJudgment = (jgmt: ModelJudgment): ModelJudgment => ({ 36 | ...deepCopyJSON(jgmt), 37 | id: v7(), 38 | }); 39 | -------------------------------------------------------------------------------- /packages/frontend/src/notebook/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./types"; 2 | export * from "./notebook_cell"; 3 | export * from "./notebook_editor"; 4 | -------------------------------------------------------------------------------- /packages/frontend/src/notebook/notebook_cell.css: -------------------------------------------------------------------------------- 1 | .cell { 2 | position: relative; 3 | margin: 0.25em 0; 4 | display: flex; 5 | flex-direction: row; 6 | align-items: baseline; 7 | justify-content: space-between; 8 | } 9 | 10 | .cell-gutter { 11 | position: absolute; 12 | top: 50%; 13 | transform: translate(-100%, -50%); 14 | left: 0; 15 | 16 | display: flex; 17 | flex-direction: row; 18 | 19 | & .lucide { 20 | color: darkgray; 21 | } 22 | } 23 | 24 | .cell-tag { 25 | color: darkgray; 26 | font-size: 11pt; 27 | } 28 | 29 | .cell-content { 30 | flex-grow: 1; 31 | height: auto; 32 | max-width: 100%; 33 | } 34 | -------------------------------------------------------------------------------- /packages/frontend/src/notebook/notebook_editor.css: -------------------------------------------------------------------------------- 1 | .notebook-container { 2 | --gutter-width: 50px; 3 | 4 | max-width: calc(100ex + var(--gutter-width)); 5 | margin: 0 auto; 6 | padding-left: var(--gutter-width); 7 | padding-right: 5px; 8 | } 9 | 10 | .notebook-cells { 11 | list-style: none; 12 | margin: 1rem 0; 13 | padding: 0; 14 | } 15 | 16 | .notebook-empty { 17 | display: flex; 18 | flex-direction: row; 19 | align-items: center; 20 | column-gap: 0.5ex; 21 | margin: 1rem 0; 22 | } 23 | 24 | .notebook .placeholder { 25 | color: darkgray; 26 | & .lucide { 27 | color: darkgray; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/frontend/src/notebook/types.ts: -------------------------------------------------------------------------------- 1 | import { v7 } from "uuid"; 2 | 3 | import type { Cell, Notebook } from "catlog-wasm"; 4 | 5 | /** Creates an empty notebook. */ 6 | export const newNotebook = (): Notebook => ({ 7 | cells: [], 8 | }); 9 | 10 | /** A cell containing rich text. */ 11 | export type RichTextCell = Cell & { tag: "rich-text" }; 12 | 13 | /** Creates a rich text cell with the given content. */ 14 | export const newRichTextCell = (content?: string): RichTextCell => ({ 15 | tag: "rich-text", 16 | id: v7(), 17 | content: content ?? "", 18 | }); 19 | 20 | /** A cell containing custom data, usually a formal object. */ 21 | export type FormalCell = Cell & { tag: "formal" }; 22 | 23 | /** Creates a formal cell with the given content. */ 24 | export const newFormalCell = (content: T): FormalCell => ({ 25 | tag: "formal", 26 | id: v7(), 27 | content: content, 28 | }); 29 | 30 | /** A stem cell is a placeholder which will be converted into another cell. 31 | 32 | Stem cells are created when the user opens the "new cell" menu and are destroyed 33 | and replaced when a type for the new cell is selected. 34 | */ 35 | export type StemCell = Cell & { tag: "stem" }; 36 | 37 | /** Creates a new stem cell. */ 38 | export const newStemCell = (): StemCell => ({ 39 | tag: "stem", 40 | id: v7(), 41 | }); 42 | -------------------------------------------------------------------------------- /packages/frontend/src/page/404_page.tsx: -------------------------------------------------------------------------------- 1 | import { BrandedToolbar } from "./toolbar"; 2 | 3 | export default function NotFoundPage() { 4 | return ( 5 |
6 | 7 |
8 |

404

9 |

{"Sorry, we couldn't find this page."}

10 |
11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /packages/frontend/src/page/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from "solid-js"; 2 | 3 | /** Actions that can be performed from any page. */ 4 | export type PageActions = { 5 | /** Show a dialog to log-in or signup. */ 6 | showLoginDialog: () => void; 7 | 8 | /** Show a dialog to import a document. */ 9 | showImportDialog: () => void; 10 | }; 11 | 12 | /** Context for actions performable on any page. */ 13 | export const PageActionsContext = createContext(); 14 | -------------------------------------------------------------------------------- /packages/frontend/src/page/document_breadcrumbs.css: -------------------------------------------------------------------------------- 1 | .breadcrumb-spacer { 2 | padding-left: 5px; 3 | padding-right: 5px; 4 | } 5 | 6 | .breadcrumb-link { 7 | text-decoration: none; 8 | } 9 | 10 | .breadcrumb-link:hover { 11 | text-decoration: underline; 12 | } 13 | 14 | .breadcrumbs-wrapper { 15 | display: flex; 16 | align-items: center; 17 | padding-left: 1em; 18 | } 19 | -------------------------------------------------------------------------------- /packages/frontend/src/page/document_loading_screen.tsx: -------------------------------------------------------------------------------- 1 | import { HamburgerMenu } from "./menubar"; 2 | import { TheoryHelpButton, Toolbar } from "./toolbar"; 3 | 4 | export function DocumentLoadingScreen() { 5 | return ( 6 |
7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 |
15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /packages/frontend/src/page/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./document_loading_screen"; 2 | export * from "./document_menu"; 3 | export * from "./menubar"; 4 | export * from "./toolbar"; 5 | export * from "./document_breadcrumbs"; 6 | -------------------------------------------------------------------------------- /packages/frontend/src/page/menubar.css: -------------------------------------------------------------------------------- 1 | .menu div[role="menuitem"] { 2 | display: flex; 3 | flex-direction: row; 4 | gap: 1ex; 5 | align-items: center; 6 | 7 | padding: 0.5ex; 8 | cursor: pointer; 9 | 10 | &[data-highlighted] { 11 | background: #f1f5f9; 12 | } 13 | 14 | & .lucide { 15 | color: dimgray; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/frontend/src/page/toolbar.css: -------------------------------------------------------------------------------- 1 | .toolbar { 2 | position: sticky; 3 | top: 0; 4 | display: flex; 5 | flex-direction: row; 6 | gap: 5px; 7 | padding: 5px; 8 | 9 | & .filler { 10 | flex: 1; 11 | } 12 | 13 | & .lucide { 14 | color: dimgray; 15 | } 16 | } 17 | 18 | @media (max-width: 1100px) { 19 | .toolbar { 20 | position: static; 21 | } 22 | } 23 | 24 | .brand { 25 | display: flex; 26 | flex-direction: row; 27 | align-items: center; 28 | gap: 5px; 29 | 30 | color: dimgray; 31 | font-size: 1.3rem; 32 | text-decoration: none; 33 | 34 | &:hover { 35 | background: whitesmoke; 36 | border-radius: 5px; 37 | } 38 | 39 | & img { 40 | width: 24px; 41 | height: 24px; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/frontend/src/stdlib/analyses/decapodes.css: -------------------------------------------------------------------------------- 1 | .decapodes-domain { 2 | display: flex; 3 | flex-direction: row; 4 | gap: 1ex; 5 | margin-bottom: 1ex; 6 | } 7 | -------------------------------------------------------------------------------- /packages/frontend/src/stdlib/analyses/graph_visualization.css: -------------------------------------------------------------------------------- 1 | .graph-visualization { 2 | overflow-x: auto; 3 | } 4 | 5 | g.link path { 6 | stroke: blue; 7 | } 8 | -------------------------------------------------------------------------------- /packages/frontend/src/stdlib/analyses/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./decapodes"; 2 | export * from "./diagram_graph"; 3 | export * from "./lotka_volterra"; 4 | export * from "./mass_action"; 5 | export * from "./model_graph"; 6 | export * from "./stock_flow_diagram"; 7 | export * from "./submodel_graphs"; 8 | -------------------------------------------------------------------------------- /packages/frontend/src/stdlib/analyses/simulation.css: -------------------------------------------------------------------------------- 1 | .simulation { 2 | width: 100%; 3 | } 4 | 5 | .parameters { 6 | display: flex; 7 | flex-direction: row; 8 | flex-wrap: wrap; 9 | gap: 1em; 10 | align-items: flex-start; 11 | justify-content: space-around; 12 | padding-bottom: 1em; 13 | } 14 | 15 | .simulation .plot { 16 | width: 100%; 17 | height: 400px; 18 | } 19 | -------------------------------------------------------------------------------- /packages/frontend/src/stdlib/analyses/submodel_graphs.css: -------------------------------------------------------------------------------- 1 | .submodel-graphs .index-buttons { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | gap: 1ex; 6 | margin: 1em 1ex; 7 | } 8 | -------------------------------------------------------------------------------- /packages/frontend/src/stdlib/arrow_styles.module.css.d.ts: -------------------------------------------------------------------------------- 1 | declare const styles: { 2 | readonly arrow: string; 3 | readonly arrowContainer: string; 4 | readonly arrowName: string; 5 | readonly arrowWithName: string; 6 | readonly default: string; 7 | readonly double: string; 8 | readonly flat: string; 9 | readonly indeterminate: string; 10 | readonly minus: string; 11 | readonly minusCaesura: string; 12 | readonly plus: string; 13 | readonly plusCaesura: string; 14 | readonly scalar: string; 15 | }; 16 | export = styles; 17 | -------------------------------------------------------------------------------- /packages/frontend/src/stdlib/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from "solid-js"; 2 | 3 | import type { TheoryLibrary } from "./types"; 4 | 5 | /** Context for the active library of double theories. */ 6 | export const TheoryLibraryContext = createContext(); 7 | -------------------------------------------------------------------------------- /packages/frontend/src/stdlib/index.ts: -------------------------------------------------------------------------------- 1 | /** Standard library of domain-specific logics. 2 | 3 | This module specifies the domain-specific logics that ship with Catcolab. 4 | Eventually it will be possible to extend Catcolab with user-specified logics but 5 | at present this is the complete set of logics available in the application. 6 | 7 | @module 8 | */ 9 | 10 | export * from "./types"; 11 | export * from "./context"; 12 | export { stdTheories } from "./theories"; 13 | -------------------------------------------------------------------------------- /packages/frontend/src/stdlib/styles.module.css: -------------------------------------------------------------------------------- 1 | .box { 2 | border: 1px solid black; 3 | padding: 2px; 4 | } 5 | 6 | .cornerBox { 7 | border: 1px solid black; 8 | padding: 2px; 9 | 10 | /* Source: https://stackoverflow.com/a/61913549 */ 11 | --corner: 8px; 12 | -webkit-mask: conic-gradient(at var(--corner) var(--corner), #0000 75%, #000 0) 0 0 / 13 | calc(100% - var(--corner)) calc(100% - var(--corner)), linear-gradient(#000 0 0) content-box; 14 | } 15 | -------------------------------------------------------------------------------- /packages/frontend/src/stdlib/styles.module.css.d.ts: -------------------------------------------------------------------------------- 1 | declare const styles: { 2 | readonly box: string; 3 | readonly cornerBox: string; 4 | }; 5 | export = styles; 6 | -------------------------------------------------------------------------------- /packages/frontend/src/stdlib/svg_styles.module.css: -------------------------------------------------------------------------------- 1 | .box rect { 2 | fill: white; 3 | stroke: black; 4 | } 5 | -------------------------------------------------------------------------------- /packages/frontend/src/stdlib/svg_styles.module.css.d.ts: -------------------------------------------------------------------------------- 1 | declare const styles: { 2 | readonly box: string; 3 | }; 4 | export = styles; 5 | -------------------------------------------------------------------------------- /packages/frontend/src/stdlib/text_styles.module.css: -------------------------------------------------------------------------------- 1 | .code { 2 | font-family: var(--mono-font); 3 | } 4 | -------------------------------------------------------------------------------- /packages/frontend/src/stdlib/text_styles.module.css.d.ts: -------------------------------------------------------------------------------- 1 | declare const styles: { 2 | readonly code: string; 3 | }; 4 | export = styles; 5 | -------------------------------------------------------------------------------- /packages/frontend/src/theory/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./types"; 2 | -------------------------------------------------------------------------------- /packages/frontend/src/user/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./login"; 2 | export * from "./permissions"; 3 | -------------------------------------------------------------------------------- /packages/frontend/src/user/login.css: -------------------------------------------------------------------------------- 1 | .login { 2 | min-width: 20em; 3 | 4 | & form { 5 | display: flex; 6 | flex-direction: column; 7 | gap: 1rem; 8 | } 9 | 10 | & form .buttons { 11 | display: flex; 12 | flex-direction: row; 13 | justify-content: space-between; 14 | } 15 | 16 | & .provider-list { 17 | display: flex; 18 | flex-direction: row; 19 | justify-content: center; 20 | gap: 2rem; 21 | } 22 | 23 | & .separator { 24 | margin: 1rem 0; 25 | } 26 | } 27 | 28 | .separator { 29 | display: flex; 30 | align-items: center; 31 | text-align: center; 32 | } 33 | 34 | .separator::before, 35 | .separator::after { 36 | content: ""; 37 | flex: 1; 38 | border-bottom: 2px solid gray; 39 | } 40 | 41 | .separator:not(:empty)::before { 42 | margin-right: 0.5em; 43 | } 44 | 45 | .separator:not(:empty)::after { 46 | margin-left: 0.5em; 47 | } 48 | 49 | .login-gate { 50 | max-width: 30em; 51 | margin: 0 auto; 52 | } 53 | -------------------------------------------------------------------------------- /packages/frontend/src/user/permissions.css: -------------------------------------------------------------------------------- 1 | .permissions { 2 | min-width: 50ex; 3 | 4 | & .alert { 5 | font-size: smaller; 6 | } 7 | } 8 | 9 | .permission-entry { 10 | display: flex; 11 | flex-direction: row; 12 | justify-content: space-between; 13 | align-items: center; 14 | gap: 5em; 15 | } 16 | -------------------------------------------------------------------------------- /packages/frontend/src/user/username.css: -------------------------------------------------------------------------------- 1 | .name-user { 2 | display: flex; 3 | flex-direction: row; 4 | gap: 1ex; 5 | align-items: center; 6 | 7 | & .username { 8 | font-weight: bold; 9 | } 10 | 11 | & .display-name { 12 | font-size: smaller; 13 | color: dimgray; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/frontend/src/util/assert_exhaustive.ts: -------------------------------------------------------------------------------- 1 | export function assertExhaustive(value: never): never { 2 | throw new Error(`Unhandled case: ${JSON.stringify(value)}`); 3 | } 4 | -------------------------------------------------------------------------------- /packages/frontend/src/util/deepcopy.ts: -------------------------------------------------------------------------------- 1 | /** Make a deep copy of a JSON object. 2 | 3 | The new-ish function `structuredClone` in the HTML DOM API seems not to work 4 | with the proxy objects used by Solid, so we resort to the classic 5 | stringify-then-parse method. Is there a less hacky method? 6 | */ 7 | export function deepCopyJSON(value: unknown) { 8 | return JSON.parse(JSON.stringify(value)); 9 | } 10 | -------------------------------------------------------------------------------- /packages/frontend/src/util/errors.css: -------------------------------------------------------------------------------- 1 | .error-dialog { 2 | & h3 { 3 | color: #dc2626; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/frontend/src/util/errors.tsx: -------------------------------------------------------------------------------- 1 | import Dialog, { Content, Portal } from "@corvu/dialog"; 2 | 3 | import "./errors.css"; 4 | 5 | export class PermissionsError extends Error { 6 | constructor(message: string) { 7 | super(message); 8 | this.name = "AuthorizationError"; 9 | } 10 | } 11 | 12 | export function ErrorBoundaryDialog(props: { error: Error }) { 13 | console.error(props.error); 14 | 15 | let heading: string; 16 | let message: string; 17 | 18 | if (props.error instanceof PermissionsError) { 19 | heading = "Permissions Error"; 20 | message = "You are not permitted to view this resource."; 21 | } else { 22 | heading = "Error"; 23 | message = "An unknown error occurred."; 24 | } 25 | 26 | return ( 27 | 28 | 29 | 30 |

{heading}

31 |

{message}

32 |
33 |
34 |
35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /packages/frontend/src/util/focus.ts: -------------------------------------------------------------------------------- 1 | import { type Accessor, createEffect } from "solid-js"; 2 | 3 | /** Focus an input component when a condition holds. */ 4 | export function focusInputWhen( 5 | ref: Accessor, 6 | when: Accessor, 7 | ) { 8 | createEffect(() => { 9 | const el = ref(); 10 | if (el && when()) { 11 | el.focus(); 12 | // Move cursor to end of input. 13 | el.selectionStart = el.selectionEnd = el.value.length; 14 | } 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /packages/frontend/src/util/json_export.ts: -------------------------------------------------------------------------------- 1 | // JsonExport.tsx 2 | 3 | export function downloadJson(data: string, filename = "export.json") { 4 | const blob = new Blob([data], { type: "application/json" }); 5 | const url = URL.createObjectURL(blob); 6 | 7 | try { 8 | const link = document.createElement("a"); 9 | link.href = url; 10 | link.download = filename; 11 | link.click(); 12 | } finally { 13 | URL.revokeObjectURL(url); 14 | } 15 | } 16 | 17 | export async function copyToClipboard(data: string): Promise { 18 | await navigator.clipboard.writeText(data); 19 | } 20 | -------------------------------------------------------------------------------- /packages/frontend/src/util/mdx.tsx: -------------------------------------------------------------------------------- 1 | import type { MDXProps } from "mdx/types"; 2 | import { type Component, lazy } from "solid-js"; 3 | 4 | export function lazyMdx(fn: () => Promise<{ default: Component }>) { 5 | const MDXPage = lazy(fn); 6 | return () => ; 7 | } 8 | -------------------------------------------------------------------------------- /packages/frontend/src/util/test_util.ts: -------------------------------------------------------------------------------- 1 | import { FirebaseError } from "firebase/app"; 2 | import { 3 | type Auth, 4 | createUserWithEmailAndPassword, 5 | signInWithEmailAndPassword, 6 | } from "firebase/auth"; 7 | 8 | /** Initialize a test user in Firebase auth. */ 9 | export async function initTestUserAuth(auth: Auth, email: string, password: string) { 10 | try { 11 | await createUserWithEmailAndPassword(auth, email, password); 12 | } catch (err) { 13 | if (err instanceof FirebaseError && err.code === "auth/email-already-in-use") { 14 | await signInWithEmailAndPassword(auth, email, password); 15 | } else { 16 | throw err; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/frontend/src/util/types.ts: -------------------------------------------------------------------------------- 1 | /** Utility type that treats an `interface` like a `type`. 2 | 3 | We need this because we'd prefer to work with types (which, unlike interfaces, 4 | cannot be extended) but currently `tsify` generates interfaces instead (see 5 | https://github.com/madonoharu/tsify/issues/61). 6 | 7 | Borrowed from here: https://stackoverflow.com/a/78441681 8 | */ 9 | export type InterfaceToType = { 10 | [K in keyof T]: InterfaceToType; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/frontend/src/visualization/echarts.ts: -------------------------------------------------------------------------------- 1 | /** Wrapper module around `echarts-solid` to facilitate lazy loading. 2 | 3 | @module 4 | */ 5 | 6 | // XXX: Prevent echarts from being tree-shaken: 7 | // https://apache.github.io/echarts-handbook/en/basics/import/ 8 | import * as echarts from "echarts"; 9 | echarts; 10 | 11 | import { EChartsAutoSize } from "echarts-solid"; 12 | 13 | export default EChartsAutoSize; 14 | -------------------------------------------------------------------------------- /packages/frontend/src/visualization/export_svg_components.tsx: -------------------------------------------------------------------------------- 1 | import type { JSX } from "solid-js"; 2 | 3 | import { IconButton } from "../components"; 4 | import { downloadSVG } from "./export_svg"; 5 | 6 | import Download from "lucide-solid/icons/download"; 7 | 8 | /** Button to download an SVG. */ 9 | export function DownloadSVGButton(props: { 10 | svg?: SVGSVGElement; 11 | filename?: string; 12 | tooltip?: JSX.Element | string; 13 | size?: number; 14 | }) { 15 | const download = () => { 16 | props.svg && downloadSVG(props.svg, props.filename ?? "export.svg"); 17 | }; 18 | 19 | return ( 20 | 21 | 22 | 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /packages/frontend/src/visualization/graph_svg.css: -------------------------------------------------------------------------------- 1 | .graph { 2 | display: block; 3 | margin: auto; 4 | overflow: visible; /* Graph layouts can clip borders. */ 5 | } 6 | 7 | .node rect { 8 | fill: transparent; 9 | } 10 | 11 | .edge line, 12 | .edge path { 13 | fill: none; 14 | stroke: black; 15 | stroke-width: 1.5; 16 | } 17 | 18 | .edge path.double-outer { 19 | stroke-width: 6; 20 | stroke-linecap: round; 21 | } 22 | .edge path.double-inner { 23 | stroke: white; 24 | stroke-width: 3.5; 25 | stroke-linecap: round; 26 | } 27 | .edge path.double-marker { 28 | stroke: white; 29 | stroke-width: 1.5; 30 | } 31 | 32 | #arrowhead-vee, 33 | #arrowhead-flat, 34 | #arrowhead-double { 35 | fill: none; 36 | stroke: black; 37 | } 38 | 39 | #arrowhead-flat { 40 | stroke-width: 2; 41 | } 42 | -------------------------------------------------------------------------------- /packages/frontend/src/visualization/graphviz_svg.tsx: -------------------------------------------------------------------------------- 1 | import type * as Viz from "@viz-js/viz"; 2 | import { type JSX, Suspense, createResource } from "solid-js"; 3 | 4 | import { GraphSVG } from "./graph_svg"; 5 | import { loadViz, parseGraphvizJSON, vizRenderJSON0 } from "./graphviz"; 6 | import type * as GraphvizJSON from "./graphviz_json"; 7 | import type { SVGRefProp } from "./types"; 8 | 9 | /** Visualize a graph using Graphviz and SVG. 10 | 11 | The layout is performed by Graphviz and then the rendering is done by custom SVG 12 | rather than Graphviz's own SVG backend. 13 | */ 14 | export function GraphvizSVG(props: { 15 | graph?: Viz.Graph; 16 | options?: Viz.RenderOptions; 17 | fallback?: JSX.Element; 18 | ref?: SVGRefProp; 19 | }) { 20 | const [vizResource] = createResource(loadViz); 21 | 22 | const render = () => { 23 | const viz = vizResource(); 24 | return viz && props.graph && vizRenderJSON0(viz, props.graph, props.options); 25 | }; 26 | 27 | return ( 28 | 29 | 30 | 31 | ); 32 | } 33 | 34 | function GraphvizOutputSVG(props: { 35 | graph?: GraphvizJSON.Graph; 36 | ref?: SVGRefProp; 37 | }) { 38 | return ; 39 | } 40 | -------------------------------------------------------------------------------- /packages/frontend/src/visualization/index.ts: -------------------------------------------------------------------------------- 1 | /** Generic tools for graph layout and visualization. 2 | 3 | These tools are applied visualize models in the `analysis` module. 4 | 5 | @module 6 | */ 7 | 8 | export * from "./types"; 9 | export * from "./export_svg"; 10 | export * from "./export_svg_components"; 11 | export * from "./graph_svg"; 12 | export * from "./graphviz"; 13 | export * from "./graphviz_svg"; 14 | export * from "./ode_plot"; 15 | export * from "./pde_plot"; 16 | 17 | export type * as GraphLayout from "./graph_layout"; 18 | export type * as GraphvizJSON from "./graphviz_json"; 19 | -------------------------------------------------------------------------------- /packages/frontend/src/visualization/types.ts: -------------------------------------------------------------------------------- 1 | import type { Setter } from "solid-js"; 2 | 3 | /** Style of arrow. 4 | 5 | Each arrow style has support to be rendered in HTML/CSS and SVG. 6 | */ 7 | export type ArrowStyle = 8 | | "default" 9 | | "double" 10 | | "flat" 11 | | "plus" 12 | | "minus" 13 | | "indeterminate" 14 | | "plusCaesura" 15 | | "minusCaesura" 16 | | "scalar"; 17 | 18 | /** Prop for forwarding a ref to an `` element. 19 | */ 20 | export type SVGRefProp = SVGSVGElement | Setter; 21 | -------------------------------------------------------------------------------- /packages/frontend/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | interface ImportMetaEnv { 4 | readonly VITE_APP_TITLE: string; 5 | readonly VITE_SERVER_URL: string; 6 | readonly VITE_AUTOMERGE_REPO_URL: string; 7 | readonly VITE_FIREBASE_OPTIONS: string; 8 | } 9 | 10 | interface ImportMeta { 11 | readonly env: ImportMetaEnv; 12 | } 13 | -------------------------------------------------------------------------------- /packages/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 5 | "target": "ES2020", 6 | "useDefineForClassFields": true, 7 | "module": "ESNext", 8 | "lib": ["ES2022", "DOM", "DOM.Iterable"], 9 | "skipLibCheck": true, 10 | 11 | "moduleResolution": "bundler", 12 | "allowImportingTsExtensions": true, 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "moduleDetection": "force", 16 | "noEmit": true, 17 | "jsx": "preserve", 18 | "jsxImportSource": "solid-js", 19 | 20 | "strict": true, 21 | "noUnusedLocals": true, 22 | "noUnusedParameters": true, 23 | "noUncheckedIndexedAccess": true, 24 | "noFallthroughCasesInSwitch": true 25 | }, 26 | "include": ["src", "vite.config.ts"] 27 | } 28 | -------------------------------------------------------------------------------- /packages/frontend/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { nodeTypes } from "@mdx-js/mdx"; 2 | import rehypeRaw from "rehype-raw"; 3 | import { defineConfig } from "vite"; 4 | import solid from "vite-plugin-solid"; 5 | import wasm from "vite-plugin-wasm"; 6 | 7 | // @ts-expect-error Types are missing. 8 | // *Also*, this plugin causes Vite 5 to complain about CJS. 9 | // https://github.com/nksaraf/vinxi/issues/289 10 | import pkg from "@vinxi/plugin-mdx"; 11 | const { default: mdx } = pkg; 12 | 13 | export default defineConfig({ 14 | plugins: [ 15 | wasm(), 16 | mdx.withImports({})({ 17 | jsx: true, 18 | jsxImportSource: "solid-js", 19 | providerImportSource: "solid-mdx", 20 | rehypePlugins: [[rehypeRaw, { passThrough: nodeTypes }]], 21 | }), 22 | solid({ 23 | extensions: [".mdx", ".md"], 24 | }), 25 | ], 26 | build: { 27 | chunkSizeWarningLimit: 2000, 28 | sourcemap: true, 29 | target: "es2022", 30 | }, 31 | server: { 32 | proxy: { 33 | "/api": { 34 | target: "http://localhost:8000", 35 | ws: true, 36 | changeOrigin: true, 37 | rewrite: (path) => path.replace(/^\/api/, ""), 38 | }, 39 | }, 40 | watch: { 41 | usePolling: true, // polling may be more reliable within the container 42 | }, 43 | }, 44 | }); 45 | -------------------------------------------------------------------------------- /packages/migrator/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "migrator" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | async-trait = "0.1.88" 8 | sqlx_migrator = { version = "0.17.0", features = ["postgres"] } 9 | tokio = { version = "1.40.0", features = ["full"] } 10 | sqlx = { version = "0.8.2", features = [ 11 | "runtime-tokio", 12 | "tls-native-tls", 13 | "postgres", 14 | "uuid", 15 | "json", 16 | "chrono", 17 | ] } 18 | -------------------------------------------------------------------------------- /packages/migrator/README.md: -------------------------------------------------------------------------------- 1 | # CatColab migrator 2 | 3 | This directory contains the tool for managing migraitions of the CatColab database, written in Rust using 4 | the framework [sqlx_migrator](https://github.com/iamsauravsharma/sqlx_migrator). 5 | 6 | ## Usage 7 | The migrator tool can be run from this directory using `cargo run` or from anywhere else in the 8 | repo using `cargo run -p migrator`. The migrator tool uses the default CLI interface provided by 9 | `sqlx_migrator`, which is very similar to the `sqlx` CLI. 10 | 11 | The `DATABASE_URL` environment variable must be set for the target database. This is typically configured 12 | automatically by the Nix dev shell defined in the repository's `flake.nix`. 13 | 14 | To view available commands, run 15 | 16 | ```sh 17 | cargo run -p migrator help 18 | ``` 19 | 20 | To apply allmigrations, run 21 | 22 | ```sh 23 | cargo run -p migrator apply 24 | ``` 25 | 26 | ## Writing new migrations 27 | For migrations that consist solely of SQL statements, the easiest way to get started is to copy the first 28 | migration file: `src/migrations/m20241004010448_document_refs.rs` and modify it as needed. 29 | 30 | Be sure to register your new migration in `src/migrations/mod.rs`. 31 | 32 | To generate a timestamp for the migration filename, run: 33 | 34 | ```sh 35 | date -u +"%Y%m%d%H%M%S" 36 | ``` 37 | -------------------------------------------------------------------------------- /packages/migrator/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | rustToolchain, 4 | ... 5 | }: 6 | let 7 | # see comment in packages/backend/default.nix 8 | buildRustCrateForPkgs = 9 | crate: 10 | pkgs.buildRustCrate.override { 11 | rustc = rustToolchain; 12 | cargo = rustToolchain; 13 | }; 14 | 15 | cargoNix = import ../../Cargo.nix { inherit pkgs buildRustCrateForPkgs; }; 16 | migrator = cargoNix.workspaceMembers.migrator.build; 17 | in 18 | migrator 19 | -------------------------------------------------------------------------------- /packages/migrator/src/main.rs: -------------------------------------------------------------------------------- 1 | use sqlx::{Connection, PgConnection}; 2 | use sqlx_migrator::Info; 3 | use sqlx_migrator::cli::MigrationCommand; 4 | use sqlx_migrator::migrator::Migrator; 5 | 6 | mod migrations; 7 | 8 | #[tokio::main] 9 | async fn main() { 10 | let database_url = std::env::var("DATABASE_URL").expect("`DATABASE_URL` must be set"); 11 | 12 | let mut migrator = Migrator::default(); 13 | migrator 14 | .add_migrations(migrations::migrations()) 15 | .expect("Failed to load migrations"); 16 | 17 | let mut conn = PgConnection::connect(&database_url) 18 | .await 19 | .expect("Failed to connect to database"); 20 | 21 | MigrationCommand::parse_and_run(&mut conn, Box::new(migrator)).await.unwrap(); 22 | } 23 | -------------------------------------------------------------------------------- /packages/migrator/src/migrations/mod.rs: -------------------------------------------------------------------------------- 1 | use sqlx::Postgres; 2 | use sqlx_migrator::migration::Migration; 3 | use sqlx_migrator::vec_box; 4 | 5 | mod m20241004010448_document_refs; 6 | mod m20241025030906_users; 7 | mod m20250409171833_add_permissions_object_subject_idx; 8 | mod m20250516154702_automerge_storage; 9 | 10 | pub fn migrations() -> Vec>> { 11 | vec_box![ 12 | m20241004010448_document_refs::DocumentRefs, 13 | m20241025030906_users::Users, 14 | m20250409171833_add_permissions_object_subject_idx::AddPermissionsObjectSubjectIdx, 15 | m20250516154702_automerge_storage::AutomergeStorage, 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /packages/notebook-types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "notebook-types" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [lib] 7 | crate-type = ["cdylib", "rlib"] 8 | 9 | [dependencies] 10 | nonempty = { version = "0.10", features = ["serialize"] } 11 | serde = { version = "1.0.219", features = ["derive"] } 12 | serde_json = "1.0.140" 13 | tsify = { version = "0.5", features = ["js"] } 14 | ustr = { version = "1.1.0", features = ["serde"] } 15 | uuid = { version = "1.11", features = ["serde", "v7", "js"] } 16 | wasm-bindgen = "0.2.100" 17 | -------------------------------------------------------------------------------- /packages/notebook-types/README.md: -------------------------------------------------------------------------------- 1 | # Notebook Types 2 | 3 | This package defines all versions of notebook types that we have used in CatColab. 4 | 5 | We start with `v0`, which is meant to be fully compatible with the JSON types that were stored in Automerge when they were defined in Javascript. This is the last version which does not declare its version number. Each successive version will be stored alongside a version number, and a migration function from the previous version. 6 | 7 | Versions are identified by a single incrementing integer. Versions may import type definitions from past versions. The last version is aliased as "current". We make a sum type over all versions with a `.to_current()` method which upgrades from any previous version to the current version. 8 | 9 | Version may undergo changes in types only during development; once a version has been committed to `main`, it is frozen. This is so that we don't have to ever purge notebooks from the development server. However, adding a new version shouldn't be too onerous, so this is not a huge limitation in practice. 10 | -------------------------------------------------------------------------------- /packages/notebook-types/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod v0; 2 | 3 | pub mod current { 4 | // this should always track the latest version, and is the only version 5 | // that is exported from notebook-types 6 | pub use crate::v0::*; 7 | } 8 | -------------------------------------------------------------------------------- /packages/notebook-types/src/v0/analysis.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use serde_json::Value; 3 | use tsify::Tsify; 4 | 5 | #[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Tsify)] 6 | #[tsify(into_wasm_abi, from_wasm_abi)] 7 | pub struct Analysis { 8 | id: String, 9 | content: Value, 10 | } 11 | -------------------------------------------------------------------------------- /packages/notebook-types/src/v0/api.rs: -------------------------------------------------------------------------------- 1 | use uuid::Uuid; 2 | 3 | use serde::{Deserialize, Serialize}; 4 | use tsify::Tsify; 5 | 6 | #[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Tsify)] 7 | #[tsify(into_wasm_abi, from_wasm_abi)] 8 | #[tsify(missing_as_null)] 9 | pub struct StableRef { 10 | #[serde(rename = "_id")] 11 | pub id: Uuid, 12 | #[serde(rename = "_version")] 13 | pub version: Option, 14 | #[serde(rename = "_server")] 15 | pub server: String, 16 | } 17 | 18 | #[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Tsify)] 19 | #[tsify(into_wasm_abi, from_wasm_abi)] 20 | pub struct Link { 21 | #[serde(flatten)] 22 | pub stable_ref: StableRef, 23 | pub r#type: String, 24 | } 25 | -------------------------------------------------------------------------------- /packages/notebook-types/src/v0/cell.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use tsify::{Tsify, declare}; 3 | use uuid::Uuid; 4 | 5 | #[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Tsify)] 6 | #[serde(tag = "tag")] 7 | #[tsify(into_wasm_abi, from_wasm_abi)] 8 | pub enum NotebookCell { 9 | #[serde(rename = "rich-text")] 10 | RichText { id: Uuid, content: String }, 11 | #[serde(rename = "formal")] 12 | Formal { id: Uuid, content: T }, 13 | #[serde(rename = "stem")] 14 | Stem { id: Uuid }, 15 | } 16 | 17 | #[declare] 18 | pub type Cell = NotebookCell; 19 | -------------------------------------------------------------------------------- /packages/notebook-types/src/v0/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod analysis; 2 | pub mod api; 3 | pub mod cell; 4 | pub mod diagram_judgment; 5 | pub mod document; 6 | pub mod model; 7 | pub mod model_judgment; 8 | pub mod notebook; 9 | pub mod path; 10 | pub mod theory; 11 | 12 | pub use analysis::*; 13 | pub use api::*; 14 | pub use cell::*; 15 | pub use diagram_judgment::*; 16 | pub use document::*; 17 | pub use model::*; 18 | pub use model_judgment::*; 19 | pub use notebook::*; 20 | pub use theory::*; 21 | 22 | #[cfg(test)] 23 | mod test { 24 | use super::document::Document; 25 | use serde_json; 26 | use std::fs; 27 | 28 | #[test] 29 | fn test_v0_examples() { 30 | let mut errored = false; 31 | for f in fs::read_dir("examples/v0").unwrap() { 32 | if let Ok(e) = f { 33 | if let Ok(s) = fs::read_to_string(e.path()) { 34 | match serde_json::from_str::(&s) { 35 | Ok(_) => {} 36 | Err(err) => { 37 | eprintln!("got {err} when reading {}", e.path().to_str().unwrap()); 38 | errored = true; 39 | } 40 | } 41 | } else { 42 | eprintln!("couldn't read {}", e.path().to_str().unwrap()); 43 | errored = true; 44 | } 45 | } 46 | } 47 | if errored { 48 | panic!() 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/notebook-types/src/v0/model.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use tsify::Tsify; 3 | 4 | use super::path::Path; 5 | use uuid::Uuid; 6 | 7 | /// An object in a model of a double theory. 8 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Tsify)] 9 | #[serde(tag = "tag", content = "content")] 10 | #[tsify(into_wasm_abi, from_wasm_abi)] 11 | pub enum Ob { 12 | /// Basic or generating object. 13 | Basic(Uuid), 14 | 15 | /// Morphism viewed as an object of a tabulator. 16 | Tabulated(Mor), 17 | } 18 | 19 | /// A morphism in a model of a double theory. 20 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Tsify)] 21 | #[serde(tag = "tag", content = "content")] 22 | #[tsify(into_wasm_abi, from_wasm_abi)] 23 | pub enum Mor { 24 | /// Basic or generating morphism. 25 | Basic(Uuid), 26 | 27 | /// Composite of morphisms. 28 | Composite(Box>), 29 | 30 | /// Morphism between tabulated morphisms, a commutative square. 31 | TabulatorSquare { 32 | dom: Box, 33 | cod: Box, 34 | pre: Box, 35 | post: Box, 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /packages/notebook-types/src/v0/notebook.rs: -------------------------------------------------------------------------------- 1 | use super::cell::NotebookCell; 2 | 3 | use serde::{Deserialize, Serialize}; 4 | use tsify::Tsify; 5 | 6 | #[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Tsify)] 7 | #[tsify(into_wasm_abi, from_wasm_abi)] 8 | pub struct Notebook { 9 | pub cells: Vec>, 10 | } 11 | -------------------------------------------------------------------------------- /packages/notebook-types/src/v0/path.rs: -------------------------------------------------------------------------------- 1 | use nonempty::NonEmpty; 2 | use serde::{Deserialize, Serialize}; 3 | use tsify::Tsify; 4 | 5 | #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Tsify)] 6 | #[serde(tag = "tag", content = "content")] 7 | #[tsify(into_wasm_abi, from_wasm_abi)] 8 | pub enum Path { 9 | Id(V), 10 | Seq(NonEmpty), 11 | } 12 | -------------------------------------------------------------------------------- /packages/notebook-types/src/v0/theory.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use tsify::Tsify; 3 | 4 | use ustr::Ustr; 5 | 6 | /// Object type in a double theory. 7 | #[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Tsify)] 8 | #[serde(tag = "tag", content = "content")] 9 | #[tsify(into_wasm_abi, from_wasm_abi)] 10 | pub enum ObType { 11 | /// Basic or generating object type. 12 | Basic(Ustr), 13 | 14 | /// Tabulator of a morphism type. 15 | Tabulator(Box), 16 | } 17 | 18 | /// Morphism type in a double theory. 19 | #[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Tsify)] 20 | #[serde(tag = "tag", content = "content")] 21 | #[tsify(into_wasm_abi, from_wasm_abi)] 22 | pub enum MorType { 23 | /// Basic or generating morphism type. 24 | Basic(Ustr), 25 | 26 | /// Hom type on an object type. 27 | Hom(Box), 28 | } 29 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "packages/automerge-doc-server" 3 | - "packages/backend/pkg" 4 | - "packages/frontend" 5 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.87.0" 3 | components = ["rustfmt", "clippy", "rust-analyzer"] 4 | --------------------------------------------------------------------------------