This commit is contained in:
Michael Zhang 2024-07-01 04:47:23 -05:00
parent 710b783ca7
commit 397e456983
25 changed files with 3292 additions and 9401 deletions

1
.gitignore vendored
View file

@ -6,3 +6,4 @@ target
test.db* test.db*
.env .env
.direnv .direnv
/proto/generated

View file

@ -1,6 +1,6 @@
deploy-docs: deploy-docs:
mdbook build docs (cd docs; BASE_URL=/panorama bun run build) || true
rsync -azrP docs/book/ root@veil:/home/blogDeploy/public/panorama rsync -azrP docs/dist/ root@veil:/home/blogDeploy/public/panorama
JOURNAL_SOURCES := $(shell find . apps/journal -name "*.rs" -not -path "./target/*") JOURNAL_SOURCES := $(shell find . apps/journal -name "*.rs" -not -path "./target/*")
journal: $(JOURNAL_SOURCES) journal: $(JOURNAL_SOURCES)
@ -10,4 +10,4 @@ journal: $(JOURNAL_SOURCES)
--target=wasm32-unknown-unknown --target=wasm32-unknown-unknown
test-install-apps: journal test-install-apps: journal
cargo test -p panorama-core -- tests::test_install_apps cargo test -p panorama-core -- tests::test_install_apps

View file

@ -1,27 +1,33 @@
import { defineConfig } from 'astro/config'; import { defineConfig } from "astro/config";
import starlight from '@astrojs/starlight'; import starlight from "@astrojs/starlight";
import rehypeKatex from "rehype-katex";
import remarkMath from "remark-math";
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
base: process.env.BASE_URL ?? "/",
integrations: [ integrations: [
starlight({ starlight({
title: 'My Docs', title: "Panorama",
social: { social: {
github: 'https://github.com/withastro/starlight', github: "https://git.mzhang.io/michael/panorama",
}, },
sidebar: [ sidebar: [
{ label: "The panorama dream", link: "/dream" },
{ {
label: 'Guides', label: "High Level Design",
items: [ autogenerate: { directory: "high-level-design" },
// Each item here is one entry in the navigation menu.
{ label: 'Example Guide', link: '/guides/example/' },
],
}, },
{ {
label: 'Reference', label: "Technical Docs",
autogenerate: { directory: 'reference' }, autogenerate: { directory: "technical-docs" },
}, },
], ],
customCss: ["./node_modules/katex/dist/katex.min.css"],
}), }),
], ],
markdown: {
remarkPlugins: [remarkMath],
rehypePlugins: [rehypeKatex],
},
}); });

BIN
docs/bun.lockb Executable file

Binary file not shown.

7721
docs/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -10,10 +10,13 @@
"astro": "astro" "astro": "astro"
}, },
"dependencies": { "dependencies": {
"@astrojs/check": "^0.7.0",
"@astrojs/starlight": "^0.24.5", "@astrojs/starlight": "^0.24.5",
"astro": "^4.10.2", "astro": "^4.10.2",
"katex": "^0.16.10",
"rehype-katex": "^7.0.0",
"remark-math": "^6.0.0",
"sharp": "^0.32.5", "sharp": "^0.32.5",
"@astrojs/check": "^0.7.0",
"typescript": "^5.5.2" "typescript": "^5.5.2"
} }
} }

View file

@ -1,5 +1,5 @@
import { defineCollection } from 'astro:content'; import { defineCollection } from "astro:content";
import { docsSchema } from '@astrojs/starlight/schema'; import { docsSchema } from "@astrojs/starlight/schema";
export const collections = { export const collections = {
docs: defineCollection({ schema: docsSchema() }), docs: defineCollection({ schema: docsSchema() }),

View file

@ -0,0 +1,63 @@
---
title: The panorama dream
---
In the ideal world, you're reading this via panorama right now.
The panorama dream is to have an "everything" app that is fully managed by the user.
This page describes the vision for the app.
Almost everything on this list is something that I self host, or want to self
host, but hosts its own database separately. I want to unify the data source in
a very flexible way so that it can be shared among apps.
This app takes inspiration from many similar apps, such as Anytype, Logseq, Notion, etc.
## Features I want
- Graph view
- Instantly share/publish anything
- Full text+OCR search
- IFTTT workflows
- Notifications
- Multiuser
- Google docs like interface for docs / typst
## Custom Apps List
- File Backup
- Object storage
- Archivebox like system, bookmarking
- Journal
- Block-based editor
- Embed any node type into journal
- Food
- Recipe tracker
- Grocery list (adds to my todo list)
- Meal planner
- Food blogging
- Health+Fitness
- Running progress (incl. saving GPS waypoints)
- Workout log for various workouts
- Weight tracking
- Connect to smartwatch?
- Pictures
- Face recognition
- Map view
- Coding
- Code tracking like Wakatime
- Git forge???
- Calendar
- Calendly-like appointment booking system
- Social
- Store people into people app
- Email+matrix chat
- Video conferencing?
- Feed readers / RSS
- Media
- Music and video hosting / streaming i.e Navidrome
- Money tracking
- Education
- Anki flashcards
- Canvas???
- Dashboards

View file

@ -1,11 +0,0 @@
---
title: Example Guide
description: A guide in my new Starlight docs site.
---
Guides lead a user through a specific task they want to accomplish, often with a sequence of steps.
Writing a good guide requires thinking about what your users are trying to do.
## Further reading
- Read [about how-to guides](https://diataxis.fr/how-to-guides/) in the Diátaxis framework

View file

@ -0,0 +1,11 @@
---
title: Attributes
---
The core idea behind panorama is that apps can choose to define attributes, which you can think of as slots.
The slots have some particular type, which can be filled with some node.
:::caution
The absence of an attribute is different from the existence of the $\textsf{None}$ value.
:::

View file

@ -0,0 +1,10 @@
---
title: Indexing
---
There are several types of indexes in panorama.
Some are the database kind that updates immediately.
Others are the search kind that updates asynchronously.
Custom app authors can specify how their attributes should be indexed.
Then, whenever

View file

@ -0,0 +1,21 @@
---
title: Nodes
---
Everything is organized into nodes.
Each app (journal, mail, etc.) creates nodes to represent their information.
These nodes are linked to each other through attributes.
When retrieving its contents, a closure-like query is conducted and all the
nodes reachable through its attributes are returned.
Think of a node as being represented like this:
```ts
interface Node {
id: string;
type: string;
attributes: string[];
}
```

View file

@ -0,0 +1,10 @@
---
title: Permissions
---
## Goals
- Apps should probably not be allowed to read attributes they didn't explicitly request access to
- (there should be an option "Unless they created the node")
## Design

View file

@ -0,0 +1,20 @@
---
title: Sync
---
:::caution
This is documentation for a feature that is in development.
Almost none of this is implemented and most of it will probably change in the future.
:::
This **only** deals with syncing nodes and files between devices owned by the same person. Permissions are not considered here.
## Design notes
-
Devices need to have some kind of knowledge of each other's existence. This may not necessarily be exposed to apps, but the thing that's responsible for syncing needs to know which nodes have which files.
-
Slow internet connections and largely offline usage patterns need to be considered.
-
**TODO:** does this need to be deeply integrated within the panorama daemon itself or is there a way to expose enough APIs for this to just be an app?

View file

@ -0,0 +1,71 @@
---
title: Types
---
Types exist to ensure that apps are treating data properly.
## Formal definition
A node's type can be one of the following:
$\tau :\equiv$
- $c$ (constant)
- $\alpha$ (type variable)
- $\mu \alpha . \tau$ (inductive type)
- $( \ell_k : \tau_k )_k$ (record type)
- $\{ \ell_k : \tau_k \}_k$ (sum type)
- $\#n$ (singleton type)
Constants may be node references, unit, unsigned/signed integers, decimal,
strings, booleans, instant (or timezone-aware timestamp), or URL
It is possible in the future that node references are also made using URLs, but
the URL format will need to be decided upon by then.
## Notes
- All nodes must belong to _closed_ types.
This means type variables cannot exist at the top-level.
- When shown in the panorama UI, the constant type will not be shown as a separate type.
Instead the actual type itself will be inlined.
- The type registry doesn't canonically exist in the database (it may exist in the form of system logs).
Instead, apps register their types on boot.
Everything is known to the panorama daemon after app initialization.
- The following constant types have their fields embedded directly into the node table:
- Number (integer, bigdecimal), string, boolean: `value`
- Sum: `label` (which variant is used?)
- Record types are essentially a collection of forced attributes.
A node with a record type _must_ contain every field listed in the labels of the record type.
- The panorama type system is _structurally_ typed.
#TODO Maybe add some convenient way of introducing ways to distinguish types apart?
### Convenient types
- $\textsf{Optional}(\tau) :\equiv \{ \texttt{'none} : () , \texttt{'some} : \tau \}$ \
The optional type.
### What is the point of a singleton type?
Singleton types only consist of a node ID.
The point of this is so apps can create types that are forced to have exactly a single node.
:::note
Apps with dashboards (mail) may create a type that represents the "entrypoint" into their application.
The process of creating it would look like this:
+ Upon app registration, I declare that I want a singleton type to be registered as `panorama-mail/entry`.
+ A node id will be assigned, if it doesn't already exist.
+ The application is returned the node ID.
+ The application can then register links to that node ID, and it can register a handler.
:::
When an app is registered, its types are parsed and registered into the database.
At the time of writing, if the node ID it refers to has already been found in the database, the type of the node will be checked against the given type.
If it doesn't match #TODO
## Attributes
Nodes contain attributes.
An attribute is a link to another node.
Attributes are typed, and the node it's linked to must have that type.

View file

@ -1,36 +1,14 @@
--- ---
title: Welcome to Starlight title: Welcome to Panorama
description: Get started building your docs site with Starlight. description: Get started building your docs site with Starlight.
template: splash template: splash
hero: hero:
tagline: Congrats on setting up a new Starlight project! tagline: I love scope creep...
image: image:
file: ../../assets/houston.webp file: ../../assets/houston.webp
actions: actions:
- text: Example Guide - text: Read the docs
link: /guides/example/ link: /dream
icon: right-arrow icon: right-arrow
variant: primary variant: primary
- text: Read the Starlight docs ---
link: https://starlight.astro.build
icon: external
---
import { Card, CardGrid } from '@astrojs/starlight/components';
## Next steps
<CardGrid stagger>
<Card title="Update content" icon="pencil">
Edit `src/content/docs/index.mdx` to see this page change.
</Card>
<Card title="Add new content" icon="add-document">
Add Markdown or MDX files to `src/content/docs` to create new pages.
</Card>
<Card title="Configure your site" icon="setting">
Edit your `sidebar` and other config in `astro.config.mjs`.
</Card>
<Card title="Read the docs" icon="open-book">
Learn more in [the Starlight Docs](https://starlight.astro.build/).
</Card>
</CardGrid>

View file

@ -1,11 +0,0 @@
---
title: Example Reference
description: A reference page in my new Starlight docs site.
---
Reference pages are ideal for outlining how things work in terse and clear terms.
Less concerned with telling a story or addressing a specific use case, they should give a comprehensive outline of what you're documenting.
## Further reading
- Read [about reference](https://diataxis.fr/reference/) in the Diátaxis framework

View file

@ -0,0 +1,23 @@
---
title: Custom App Sandboxing
---
:::caution
For the initial releases of panorama, I am not planning on including _any_
sandboxing whatsoever. The development overhead will be far too great to warrant supporting it.
The entire app _will_ be rewritten before the public alpha release, which will
include proper custom app sandboxing. This page lists some ideas.
:::
Custom apps are made up of two parts:
- The backend, which talks to the database
- The frontend, which talks to the user
I say "the" frontend, but there could possibly be multiple frontends. (TUI, headless, etc.)
Each part needs to be sandboxed individually.
## Backend sandboxing
This will be done via a WASM runtime. The custom app's backend software will

View file

@ -0,0 +1,6 @@
---
title: Loading process
---
The goal of panorama is to start up as quickly as possible.
The following tasks need to be performed on start:

View file

@ -0,0 +1,5 @@
---
title: Notifications
---
https://unifiedpush.org/

View file

@ -0,0 +1,10 @@
---
title: Protected Namespaces
---
There's some protected namespace of nodes that's used to keep track of the
actual database functionality. For example:
- List of installed apps
- List of currently registered types (maybe not keep this?)
- System log

View file

@ -1,3 +1,5 @@
{ {
"extends": "astro/tsconfigs/strict" "extends": "astro/tsconfigs/strict",
} "compilerOptions": { "skipLibCheck": true },
"exclude": ["dist"]
}

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,3 @@
packages: packages:
# - 'react' - 'app'
- 'app' - 'docs'

33
proto/panorama.proto Normal file
View file

@ -0,0 +1,33 @@
syntax = "proto3";
package io.mzhang.panorama;
service PanoramaHost {
rpc Hello (HelloRequest) returns (HelloResponse) {}
rpc RegisterSingletonType (RegisterSingletonTypeRequest) returns (RegisterSingletonTypeResponse) {}
rpc RegisterType (RegisterTypeRequest) returns (RegisterTypeResponse) {}
}
message HelloRequest {}
message HelloResponse {
// What the actual given name of your app is installed as; this is not easily changed
string appName = 1;
string panoramaVersion = 2;
}
message RegisterTypeRequest {
string typeName = 1;
string typeExpr = 2;
}
message RegisterTypeResponse {}
message RegisterSingletonTypeRequest {
// The name given to the attribute you want to reserve
string attributeName = 1;
}
message RegisterSingletonTypeResponse {
// Node id corresponding to the Singleton type
string nodeId = 1;
}
service PanoramaApp {
}