├── .github
└── workflows
│ └── generate-content-snapshot.yml
├── .gitignore
├── README.md
├── landscape-content-snapshot
├── package.json
├── src
│ └── generated
│ │ ├── ambient.d.ts
│ │ ├── automerge
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.png
│ │ └── logo.light.png
│ │ ├── basic
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.svg
│ │ └── logo.light.svg
│ │ ├── convex
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.svg
│ │ └── logo.light.svg
│ │ ├── ditto
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.svg
│ │ └── logo.light.svg
│ │ ├── dxos
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.svg
│ │ └── logo.light.svg
│ │ ├── electricsql
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.svg
│ │ └── logo.light.svg
│ │ ├── instant
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.svg
│ │ └── logo.light.svg
│ │ ├── jazz
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.svg
│ │ └── logo.light.svg
│ │ ├── liveblocks-storage
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.png
│ │ └── logo.light.png
│ │ ├── liveblocks-yjs
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.png
│ │ └── logo.light.png
│ │ ├── livestore
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.svg
│ │ └── logo.light.svg
│ │ ├── loro
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.svg
│ │ └── logo.light.svg
│ │ ├── mod.ts
│ │ ├── nextgraph
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.svg
│ │ └── logo.light.svg
│ │ ├── powersync
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.svg
│ │ └── logo.light.svg
│ │ ├── tinybase
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.svg
│ │ └── logo.light.svg
│ │ ├── triplit
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.svg
│ │ └── logo.light.svg
│ │ ├── y-sweet
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.png
│ │ └── logo.light.png
│ │ ├── yjs
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.svg
│ │ └── logo.light.svg
│ │ └── zero
│ │ ├── data.json
│ │ ├── details.md
│ │ ├── logo.dark.svg
│ │ └── logo.light.svg
└── tsconfig.json
├── landscape-content.tldr
├── landscape-fetch-content
├── package.json
├── src
│ ├── cli.ts
│ ├── fetch-repo.ts
│ └── repos.ts
└── tsconfig.json
├── landscape-schema
├── package.json
├── src
│ ├── mod.ts
│ └── schema.ts
└── tsconfig.json
├── package.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── temporary-technology-info
├── ditto
│ ├── data.js
│ ├── details.md
│ ├── logo.dark.png
│ └── logo.light.png
├── package.json
└── validate.js
└── tsconfig.all.json
/.github/workflows/generate-content-snapshot.yml:
--------------------------------------------------------------------------------
1 | name: Generate Content Snapshot
2 |
3 | on:
4 | schedule:
5 | # Runs at 00:00 UTC every day
6 | - cron: '0 0 * * *'
7 | # Allow manual trigger
8 | workflow_dispatch:
9 | # Also when pushing to main
10 | push:
11 | branches:
12 | - main
13 |
14 | jobs:
15 | generate:
16 | runs-on: ubuntu-latest
17 | environment: CI
18 | permissions:
19 | contents: write
20 |
21 | steps:
22 | - uses: actions/checkout@v4
23 |
24 | - uses: oven-sh/setup-bun@v2
25 |
26 | # Add pnpm cache
27 | - name: Cache pnpm modules
28 | uses: actions/cache@v3
29 | with:
30 | path: ~/.pnpm-store
31 | key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
32 | restore-keys: |
33 | ${{ runner.os }}-pnpm-
34 |
35 | - run: bun install -g pnpm
36 | - run: pnpm install
37 | - run: pnpm build:ts
38 |
39 | - name: Generate content snapshot
40 | run: pnpm generate:content-snapshot --show-full-errors
41 | env:
42 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
43 |
44 | - name: Check for changes
45 | id: git-check
46 | run: |
47 | git add .
48 | # Set output whether there are changes staged
49 | echo "changes=$(git diff --staged --quiet && echo 'false' || echo 'true')" >> $GITHUB_OUTPUT
50 |
51 | - name: Commit and push if there are changes
52 | if: steps.git-check.outputs.changes == 'true'
53 | env:
54 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
55 | run: |
56 | git config --local user.email "github-actions[bot]@users.noreply.github.com"
57 | git config --local user.name "github-actions[bot]"
58 | git commit -m "chore: update content snapshot [skip ci]"
59 | git push
60 |
61 | - name: Trigger localfirst.fm rebuild
62 | # Ensure this only runs if the push was successful or the whole job succeeded
63 | if: success()
64 | uses: peter-evans/repository-dispatch@v3
65 | with:
66 | token: ${{ secrets.LOCALFIRST_FM_PAT }}
67 | repository: schickling/localfirst.fm
68 | event-type: content-snapshot-updated
69 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | .vercel
4 |
5 | dist
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Local-first Landscape 🗺️
2 |
3 | A resource to learn about and compare tools in the local-first landscape. Whether you're a developer looking to experiment with local-first patterns or a technical leader making a strategic technology decision, this resource helps you navigate the growing ecosystem of local-first tools and make informed choices.
4 |
5 | ## Sub-packages
6 |
7 | This monorepo contains several packages that work together:
8 |
9 | - `landscape-schema`: Defines the TypeScript schema for the data that describes each technology in the landscape.
10 | - `landscape-fetch-content`: Contains the infrastructure to fetch the data for each technology from its designated GitHub repository (see below).
11 | - `landscape-content-snapshot`: A local cache of the fetched data from the technology repositories.
12 |
13 | ## Contributing Data
14 |
15 | The data for this landscape is maintained collaboratively.
16 |
17 | ### Suggesting a New Technology
18 |
19 | To suggest adding a new technology to the landscape, please open a Pull Request against the `packages/@localfirstfm/landscape-fetch-content/src/repos.ts` file in *this* repository. Add an entry for the new technology, specifying its unique ID, the GitHub owner and repository where its data will be maintained, and optionally a branch and base path within that repository.
20 |
21 | ### Editing Existing Technology Data
22 |
23 | To edit the information for an existing technology, you need to open a Pull Request against the specific GitHub repository where that technology's data is managed. Find the correct repository in the table below:
24 |
25 | | Technology | Data Repository |
26 | | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
27 | | [Automerge](placeholder-homepage-automerge) | [`automerge/local-first-landscape-data`](https://github.com/automerge/local-first-landscape-data) |
28 | | [Basic](placeholder-homepage-basic) | [`basicdb/local-first-landscape-data`](https://github.com/basicdb/local-first-landscape-data) |
29 | | [Convex](placeholder-homepage-convex) | [`get-convex/localfirst-landscape-data`](https://github.com/get-convex/localfirst-landscape-data) |
30 | | [Ditto](placeholder-homepage-ditto) | [`localfirstfm/local-first-landscape`](https://github.com/localfirstfm/local-first-landscape) |
31 | | [DXOS](placeholder-homepage-dxos) | [`dxos/local-first-landscape-data`](https://github.com/dxos/local-first-landscape-data) |
32 | | [ElectricSQL](placeholder-homepage-electricsql) | [`electric-sql/local-first-landscape-data`](https://github.com/electric-sql/local-first-landscape-data) |
33 | | [Jazz](placeholder-homepage-jazz) | [`garden-co/jazz-lofi-landscape`](https://github.com/garden-co/jazz-lofi-landscape) |
34 | | [Liveblocks](placeholder-homepage-liveblocks) | [`liveblocks/local-first-landscape-data`](https://github.com/liveblocks/local-first-landscape-data) |
35 | | [LiveStore](placeholder-homepage-livestore) | [`livestorejs/local-first-landscape`](https://github.com/livestorejs/local-first-landscape) |
36 | | [NextGraph](https://nextgraph.org) | [`nextgraph-org/landscape-data`](https://github.com/nextgraph-org/landscape-data) |
37 | | [PowerSync](placeholder-homepage-powersync) | [`powersync-ja/local-first-landscape-data`](https://github.com/powersync-ja/local-first-landscape-data) |
38 | | [TinyBase](placeholder-homepage-tinybase) | [`tinyplex/tinybase-landscape-data`](https://github.com/tinyplex/tinybase-landscape-data) |
39 | | [Triplit](placeholder-homepage-triplit) | [`aspen-cloud/local-first-landscape-data`](https://github.com/aspen-cloud/local-first-landscape-data) |
40 | | [Y-Sweet](placeholder-homepage-y-sweet) | [`jamsocket/y-sweet`](https://github.com/jamsocket/y-sweet) |
41 | | [Yjs](placeholder-homepage-yjs) | [`yjs/local-first-landscape-data`](https://github.com/yjs/local-first-landscape-data) |
42 | | [Zero](placeholder-homepage-zero) | [`rocicorp/local-first-landscape-data`](https://github.com/rocicorp/local-first-landscape-data) |
43 | | [Instant](https://instantdb.com) | [`instantdb/local-first-landscape-data`](https://github.com/instantdb/local-first-landscape-data) |
44 |
45 | Make your changes to the relevant files in that repository.
46 |
47 | > [!NOTE]
48 | > The content for each technology is automatically pulled from its respective repository and regenerated **daily at 00:00 UTC**. Changes made in the source repositories will only be reflected in the website after the next daily update.
49 |
50 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@localfirstfm/landscape-content-snapshot",
3 | "version": "0.0.0",
4 | "type": "module",
5 | "private": true,
6 | "dependencies": {
7 | "effect": "3.12.0",
8 | "@localfirstfm/landscape-schema": "workspace:*"
9 | },
10 | "devDependencies": {
11 | "typescript": "^5.7.2"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/ambient.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.svg' {
2 | const content: any
3 | export default content
4 | }
5 |
6 | declare module '*.png' {
7 | const content: any
8 | export default content
9 | }
10 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/automerge/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "automerge",
4 | "Name": "Automerge",
5 | "Description": "Automerge enables local first applications by providing generic version control for JSON documents",
6 | "MaturityLevel": "Production-Ready",
7 | "Website": "https://automerge.org",
8 | "GitHub": "https://github.com/automerge/automerge",
9 | "GetStarted": "https://automerge.org/docs/hello/",
10 | "InitialReleaseDate": "2017-01-01T00:00:00.000Z",
11 | "NotableAdopters": [
12 | {
13 | "Name": "GoodNotes",
14 | "URL": "https://github.com/automerge/automerge"
15 | },
16 | {
17 | "Name": "Bowtie",
18 | "URL": "https://www.bowtie.security/"
19 | }
20 | ],
21 | "Deployment": [
22 | "Self-hosted"
23 | ],
24 | "License": "MIT",
25 | "AppTarget": {
26 | "Platform": {
27 | "data": [
28 | "Browser",
29 | "Node",
30 | "iOS",
31 | "Android",
32 | "macOS",
33 | "Linux",
34 | "Windows",
35 | "WASM"
36 | ],
37 | "comment": "Automerge itself supports all these platforms, but the automerge-repo companion library is currently only available in JavaScript environments (excluding React Native) and Swift environments. Other platforms are in development."
38 | },
39 | "LanguageSDK": {
40 | "data": [
41 | "JavaScript",
42 | "TypeScript",
43 | "Swift",
44 | "Rust",
45 | "Go",
46 | "Java",
47 | "Kotlin"
48 | ],
49 | "comment": "The officially supported languages are JavaScript, TypeScript, Swift, and Rust. Go, Java and Kotlin are best-effort but tend to lag behind the official implementations"
50 | },
51 | "FrameworkIntegrations": {
52 | "data": [
53 | "React",
54 | "Svelte"
55 | ]
56 | },
57 | "ClientBundleSize": {
58 | "data": "~800Kb gzipped"
59 | }
60 | },
61 | "Networking": {
62 | "Protocol": {
63 | "data": [
64 | "WebSockets",
65 | "TCP"
66 | ],
67 | "comment": "The Automerge sync protocol runs over anything which provides an in-order byte stream"
68 | },
69 | "Topology": {
70 | "data": "P2P",
71 | "comment": "Typical deployments use a central relay server with opportunistic peer-to-peer"
72 | }
73 | },
74 | "ServerSideData": {
75 | "PersistenceMechanism": {
76 | "data": [
77 | "Local file system",
78 | "Custom"
79 | ],
80 | "comment": "Automerge can use any storage mechanism which supports key/value storage with range queries. There are community maintained adapters for many storage backends including PostgreSQL and S3"
81 | },
82 | "DataModelParadigm": {
83 | "data": "Document"
84 | }
85 | },
86 | "ClientSideData": {
87 | "QueryAPI": {
88 | "data": [
89 | "Async"
90 | ]
91 | },
92 | "LocalRefreshLatency": {
93 | "data": "~10-100ms"
94 | },
95 | "PersistenceMechanism": {
96 | "data": [
97 | "IndexedDB",
98 | "Local file system",
99 | "Custom"
100 | ],
101 | "comment": "Automerge can use any storage mechanism which supports key/value storage with range queries"
102 | },
103 | "DataModel": {
104 | "data": "Document"
105 | },
106 | "OfflineReads": {
107 | "data": "Full Support"
108 | },
109 | "OfflineWrites": {
110 | "data": "Local conflict resolution"
111 | },
112 | "DataSize": {
113 | "data": "up to 5-10mb per doc"
114 | }
115 | },
116 | "SynchronizationStrategy": {
117 | "FullOrPartialReplication": {
118 | "data": [
119 | "Full Replication"
120 | ]
121 | },
122 | "ConflictHandling": {
123 | "data": "Automatic via CRDT",
124 | "comment": "All changes are recorded and conflicts can be examined and resolved later"
125 | },
126 | "WhereResolutionOccurs": {
127 | "data": "Client"
128 | },
129 | "WhatGetsSynced": {
130 | "data": {
131 | "ClientToServer": "ops",
132 | "ServerToClient": "ops",
133 | "ClientToClient": "ops"
134 | },
135 | "comment": "There is no distinction between client and server in Automerge"
136 | },
137 | "Authority": {
138 | "data": "Decentralized"
139 | },
140 | "Latency": {
141 | "data": "~10-100ms"
142 | }
143 | },
144 | "AuthIdentity": {
145 | "Encryption": {
146 | "data": "Transport-level encryption"
147 | },
148 | "AuthenticationMethod": {
149 | "data": [
150 | "Full Custom"
151 | ]
152 | },
153 | "AuthorizationPermissions": {
154 | "data": "Custom"
155 | }
156 | },
157 | "UIRelated": {
158 | "RichTextEditing": {
159 | "data": "Yes"
160 | },
161 | "Components": {
162 | "data": [
163 | "ProseMirror plugin",
164 | "CodeMirror plugin",
165 | "React hooks"
166 | ]
167 | }
168 | },
169 | "__generated": {
170 | "lastUpdated": "2025-04-29T17:35:36.000Z"
171 | }
172 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/automerge/details.md:
--------------------------------------------------------------------------------
1 | # Automerge
2 |
3 | [Get Started](https://automerge.org/docs/quickstart/)
4 |
5 | ---
6 |
7 | Automerge is a toolkit which makes building collaborative, local first applications which don't depend on servers feel as easy as building local only prototypes. We do this by thinking of the problem of local first collaboration as a version control problem - every peer has a different version of the data and Automerge provides tools to easily synchronise different versions, examine, history, and merge changes.
8 |
9 | This gives us a number of benefits:
10 |
11 | ### Network Topology Agnosticism
12 |
13 | Every peer is the same, there is no special server/client relationship. This means that you can use a sync server - just a very available peer - and opportunistically use peer to peer connections when available. It also means that sync servers are fungible, you can run one, your users can run one, etc.
14 |
15 | ### Local first
16 |
17 | You always have a full local copy of the data, and local reads and writes are always committed instantly. If your sync server is unavailable, that's fine, you'll merge when you reconnect - or even just when you connect to a _different_ sync server.
18 |
19 | ### Rich change history
20 |
21 | Automerge tracks very fine grained (typically per keystroke) and rich (native representations for maps, lists, and rich text) changes. This allows us to avoid most conflicts, and provide good APIs for conflict resolution. It also means that you can always examine any part of the history of the document to review changes.
22 |
23 | ### Unified collaboration model
24 |
25 | Because of the rich change history Automerge tracks, the programming model for synchronous real-time collaboration, and asynchronous "I was working from a cabin in the woods for a week" collaboration is the same.
26 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/automerge/logo.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/localfirstfm/local-first-landscape/621278c13945f8c197c671acddb588970549d208/landscape-content-snapshot/src/generated/automerge/logo.dark.png
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/automerge/logo.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/localfirstfm/local-first-landscape/621278c13945f8c197c671acddb588970549d208/landscape-content-snapshot/src/generated/automerge/logo.light.png
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/basic/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "basic",
4 | "Name": "Basic.tech",
5 | "Description": "Infra for building personalized, multiplayer, local-first apps where users own their data",
6 | "MaturityLevel": "Beta",
7 | "Website": "https://basic.tech",
8 | "UniquenessNote": "Since data is synced to user-owned data stores, apps are interoperable by default. Apps can discover and reuse data schemas from other apps or use schema lenses to adapt to any app.",
9 | "Deployment": [
10 | "Self-hosted",
11 | "Hosted"
12 | ],
13 | "License": "MIT",
14 | "AppTarget": {
15 | "LanguageSDK": {
16 | "data": [
17 | "Typescript",
18 | "JavaScript"
19 | ]
20 | },
21 | "FrameworkIntegrations": {
22 | "data": [
23 | "Next.js",
24 | "React Native",
25 | "React"
26 | ]
27 | }
28 | },
29 | "Networking": {
30 | "Protocol": {
31 | "data": [
32 | "WebSockets",
33 | "HTTP"
34 | ]
35 | },
36 | "Topology": {
37 | "data": "Client-Server"
38 | }
39 | },
40 | "ServerSideData": {
41 | "PersistenceMechanism": {
42 | "data": [
43 | "PostgreSQL",
44 | "SQLite"
45 | ]
46 | },
47 | "DataModelParadigm": {
48 | "data": "Relational"
49 | },
50 | "SchemaManagement": {
51 | "data": [
52 | "Schema definition",
53 | "Validate schemas on write"
54 | ]
55 | }
56 | },
57 | "ClientSideData": {
58 | "QueryAPI": {
59 | "data": [
60 | "Async",
61 | "Reactive queries"
62 | ]
63 | },
64 | "PersistenceMechanism": {
65 | "data": [
66 | "IndexedDB"
67 | ]
68 | },
69 | "DataModel": {
70 | "data": "Document"
71 | },
72 | "OfflineReads": {
73 | "data": "Full Support"
74 | },
75 | "OfflineWrites": {
76 | "data": "Local conflict resolution"
77 | }
78 | },
79 | "SynchronizationStrategy": {
80 | "FullOrPartialReplication": {
81 | "data": [
82 | "Full Replication"
83 | ]
84 | },
85 | "ConflictHandling": {
86 | "data": "Server reconciliation"
87 | },
88 | "WhereResolutionOccurs": {
89 | "data": "Server"
90 | }
91 | },
92 | "AuthIdentity": {
93 | "Encryption": {
94 | "data": "Yes",
95 | "comment": "Encrypted at rest - End to end encryption optional"
96 | },
97 | "AuthenticationMethod": {
98 | "data": [
99 | "JWT Tokens"
100 | ]
101 | },
102 | "AuthorizationPermissions": {
103 | "data": "Custom"
104 | }
105 | },
106 | "UIRelated": {
107 | "Components": {
108 | "data": [
109 | "React components for Auth"
110 | ]
111 | }
112 | },
113 | "DevelopmentWorkflowsDX": {
114 | "DebuggingTools": {
115 | "data": [
116 | "Dashboard"
117 | ]
118 | },
119 | "CLI": {
120 | "data": "Yes"
121 | },
122 | "TypeSupport": {
123 | "data": "Yes"
124 | }
125 | },
126 | "__generated": {
127 | "lastUpdated": "2025-04-22T17:35:43.000Z"
128 | }
129 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/basic/details.md:
--------------------------------------------------------------------------------
1 | # Basic
2 |
3 | **Basic** is building infrastructure for personalized, multiplayer, local-first apps where users own their data.
4 |
5 | We set out to build a complete solution for local-first apps — and realized that a sync engine alone doesn’t solve the problem of user-owned data. That led us to create **personal data stores**: an independent, portable database owned and controlled by the *user*, not the app.
6 |
7 | ## Personal Data Stores
8 |
9 | Most apps today are built on a simple assumption: data lives on the app’s servers. Users generate it, and apps store all the data from all their users in a single, centralized database. This model has caused many of the web’s biggest problems: lock-in, privacy issues, broken interoperability, and walled gardens.
10 |
11 | **Basic flips that model.** Instead of one app owning data from many users, each user owns their own data — and apps just plug into it. It’s a small shift with big benefits:
12 |
13 | - **User control**: Data lives with the user, not the platform. They can revoke access at any time.
14 | - **Interoperability**: Apps don’t need to manually integrate with each other — it’s built in. This unlocks deeply personalized experiences and a “universal shared memory” across apps.
15 | - **Portability**: Users can switch tools without losing their data or starting over.
16 | - **Simpler apps**: Developers don’t need to build auth, sync, or complex backends — just good apps.
17 |
18 | ## Building on Basic
19 |
20 | **Basic** is a complete framework for building local-first apps. It includes auth, database, sync, and client SDKs.
21 |
22 | - **Auth**: Users authenticate with their own PDS. Basic makes this seamless by providing a default PDS for each user, enabling quick onboarding.
23 | - **Database & Schema**: Apps define a schema — a simple, declarative way to describe your data. You define your tables and fields; Basic handles the rest. This abstraction makes syncing across devices easy, without worrying about migrations or conflicts.
24 | - **Sync**: Basic comes with a built-in sync engine, fully integrated with the React SDK. We're working on support for more clients (like React Native) and even compatibility with other sync engines.
25 |
26 | ## Getting Started
27 |
28 | - [Check out the docs](https://docs.basic.tech) to learn more.
29 | - [Read more about personal data stores](https://docs.basic.tech/readings/user-owned-data-stores).
30 | - [Join our Discord](https://discord.gg/M57gcazvYk) to chat with the team or ask questions.
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/basic/logo.dark.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/basic/logo.light.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/convex/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "convex",
4 | "Name": "Convex",
5 | "Description": "Convex is the open source, reactive database where queries are TypeScript code running right in the database. Just like React components react to state changes, Convex queries react to database changes.",
6 | "MaturityLevel": "Production-Ready",
7 | "Logo": {
8 | "Light": "https://static.convex.dev/logo/convex-logo.svg",
9 | "Dark": "https://static.convex.dev/logo/convex-logo-light.svg"
10 | },
11 | "Website": "https://convex.dev",
12 | "GitHub": "https://github.com/get-convex/convex-backend",
13 | "GetStarted": "https://docs.convex.dev/tutorial/",
14 | "Deployment": [
15 | "Self-hosted",
16 | "Hosted"
17 | ],
18 | "License": "FSL-1.1-Apache-2.0",
19 | "AppTarget": {
20 | "Platform": {
21 | "data": [
22 | "Browser",
23 | "Node",
24 | "iOS",
25 | "Android",
26 | "macOS",
27 | "Linux"
28 | ]
29 | },
30 | "LanguageSDK": {
31 | "data": [
32 | "TypeScript",
33 | "JavaScript",
34 | "Kotlin",
35 | "Python",
36 | "Rust",
37 | "Swift"
38 | ]
39 | },
40 | "FrameworkIntegrations": {
41 | "data": [
42 | "Next.js",
43 | "Tanstack Start",
44 | "React",
45 | "React Native",
46 | "Svelte",
47 | "SwiftUI",
48 | "Vue",
49 | "Flutter"
50 | ]
51 | },
52 | "ClientBundleSize": {
53 | "data": "~120KiB"
54 | }
55 | },
56 | "Networking": {
57 | "Protocol": {
58 | "data": [
59 | "WebSockets",
60 | "HTTP"
61 | ]
62 | },
63 | "Topology": {
64 | "data": "Client-Server"
65 | }
66 | },
67 | "ServerSideData": {
68 | "PersistenceMechanism": {
69 | "data": [
70 | "Custom",
71 | "MySQL",
72 | "PostgreSQL",
73 | "SQLite"
74 | ]
75 | },
76 | "DataModelParadigm": {
77 | "data": "Relational"
78 | },
79 | "SchemaManagement": {
80 | "data": [
81 | "Schema definition",
82 | "Validate schemas on write"
83 | ]
84 | }
85 | },
86 | "ClientSideData": {
87 | "QueryAPI": {
88 | "data": [
89 | "Reactive queries",
90 | "Async"
91 | ]
92 | },
93 | "LocalRefreshLatency": {
94 | "data": "~10-100ms"
95 | },
96 | "PersistenceMechanism": {
97 | "data": []
98 | },
99 | "PersistenceFeatures": {
100 | "data": "Transactions"
101 | },
102 | "DataModel": {
103 | "data": "Relational"
104 | },
105 | "DataSize": {
106 | "data": "Up to 1 MB per document"
107 | }
108 | },
109 | "SynchronizationStrategy": {
110 | "FullOrPartialReplication": {
111 | "data": [
112 | "Partial Replication"
113 | ]
114 | },
115 | "ConflictHandling": {
116 | "data": "Custom conflict resolution supported"
117 | },
118 | "WhereResolutionOccurs": {
119 | "data": "Server"
120 | },
121 | "WhatGetsSynced": {
122 | "data": {
123 | "ClientToServer": "Mutations",
124 | "ServerToClient": "Query functions"
125 | }
126 | },
127 | "Authority": {
128 | "data": "Centralized"
129 | },
130 | "Latency": {
131 | "data": "~100ms"
132 | },
133 | "Throughput": {
134 | "data": "10000 writes/sec"
135 | },
136 | "Concurrency": {
137 | "data": "1M concurrent users"
138 | }
139 | },
140 | "AuthIdentity": {
141 | "Encryption": {
142 | "data": "Yes",
143 | "comment": "All data is encrypted at rest for the hosted product"
144 | },
145 | "AuthenticationMethod": {
146 | "data": [
147 | "Built-in",
148 | "JWT Tokens"
149 | ]
150 | },
151 | "AuthorizationPermissions": {
152 | "data": "Custom"
153 | }
154 | },
155 | "UIRelated": {
156 | "RichTextEditing": {
157 | "data": "Yes",
158 | "comment": "https://www.convex.dev/components/prosemirror-sync"
159 | }
160 | },
161 | "DevelopmentWorkflowsDX": {
162 | "DebuggingTools": {
163 | "data": [
164 | "Dashboard"
165 | ]
166 | },
167 | "CLI": {
168 | "data": "Yes"
169 | },
170 | "TypeSupport": {
171 | "data": "Yes",
172 | "comment": "End to-end type safety from the schema to functions to the client"
173 | }
174 | },
175 | "__generated": {
176 | "lastUpdated": "2025-04-14T22:29:55.000Z"
177 | }
178 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/convex/details.md:
--------------------------------------------------------------------------------
1 | # Convex
2 |
3 | [Convex](https://convex.dev) is the open-source reactive database designed to
4 | make life easy for web app developers, whether human or LLM. Fetch data and
5 | perform business logic with strong consistency by writing pure TypeScript.
6 |
7 | Convex provides a database, a place to write your server functions, and client
8 | libraries. It makes it easy to build and scale dynamic live-updating apps.
9 | [Read the docs to learn more](https://docs.convex.dev/understanding/).
10 |
11 | ## Features
12 |
13 | - **Functions**: Functions run on the backend and are written in JavaScript (or TypeScript). They are automatically available as APIs accessed through client libraries. Queries read data from the Convex database and are automatically cached and reactive. Mutations transactionally write to the database. Actions call external APIs.
14 | - **Database**: The Convex database provides a relational data model, stores JSON-like documents, and can be used with or without a schema. It "just works," giving you predictable query performance in an easy-to-use interface.
15 | - **Authentication**: Convex has built-in authentication and also supports integrating with any other OpenID Connect authentication provider.
16 | - **Scheduling**: Run a function one or repeatedly in the feature, composing Convex functions into durable workflows.
17 | - **File Storage**: Store and retrieve files of all file types in built-in file storage.
18 | - **Search**: Add text or vector indexes to search over data in your Convex database.
19 | - **Dashboard**: View your Convex deployment's data, functions, and logs in our built-in dashboard.
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/convex/logo.dark.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/convex/logo.light.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/ditto/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "ditto",
4 | "Name": "Ditto",
5 | "Description": "Ditto is the only edge-native, mobile database that can consistently support your business anytime, anywhere. Edge-native solutions are built specifically to thrive on mobile and edge devices, without relying solely on cloud-based services.",
6 | "MaturityLevel": "Production-Ready",
7 | "Website": "https://www.ditto.com",
8 | "GitHub": "https://github.com/getditto",
9 | "GetStarted": "https://docs.ditto.live/home/introduction#sdk-quickstart-guides",
10 | "InitialReleaseDate": "2019-04-30T00:00:00.000Z",
11 | "Deployment": [
12 | "Self-hosted",
13 | "Hosted"
14 | ],
15 | "License": "Proprietary",
16 | "AppTarget": {
17 | "Platform": {
18 | "data": [
19 | "Browser",
20 | "iOS",
21 | "Android",
22 | "macOS",
23 | "Linux",
24 | "Windows",
25 | "WASM"
26 | ],
27 | "comment": "The various Ditto Edge SDKs may or may not suppport all environments listed. Other platforms are in development."
28 | },
29 | "LanguageSDK": {
30 | "data": [
31 | "Swift",
32 | "Kotlin - Android",
33 | "Java - Server",
34 | "Java - Android",
35 | "Dart",
36 | "React Native",
37 | "JavaScript Web",
38 | "C# - .NET",
39 | "Rust",
40 | "C++"
41 | ],
42 | "comment": ""
43 | },
44 | "FrameworkIntegrations": {
45 | "data": [
46 | "React Native",
47 | "Flutter",
48 | ".NET Maui",
49 | "Jetpack Compose",
50 | "SwiftUI"
51 | ]
52 | }
53 | },
54 | "Networking": {
55 | "Protocol": {
56 | "data": [
57 | "WiFi LAN",
58 | "Bluetooth",
59 | "P2P WiFi",
60 | "TCP",
61 | "HTTP",
62 | "WebSockets"
63 | ],
64 | "comment": "We've developed an intelligent sync system that automatically discovers local devices, establishes a connection, and seamlessly switches between active transports when syncing data (Bluetooth, P2P WiFi, LAN, Websockets) so that if one transport goes down, it automatically switches to the next best one, optimizing for speed. \"Resilient Networking\" in this context means networking that can network in any environment and dynamically \"heal\" itself if connections break"
65 | },
66 | "Topology": {
67 | "data": "Mesh Network"
68 | }
69 | },
70 | "ServerSideData": {
71 | "PersistenceMechanism": {
72 | "data": [
73 | "Custom"
74 | ]
75 | },
76 | "DataSize": {
77 | "data": "No theoretical limit",
78 | "comment": "No theoretical limit, due to cloud scaling, but we offer benchmarking and performance services to validate & scale cloud resources for larger use cases."
79 | },
80 | "DataModelParadigm": {
81 | "data": "Document"
82 | },
83 | "ExistingDatabaseSupport": {
84 | "data": "HTTP/Webhooks and real-time via CDC Connectors (Kafka-based)"
85 | }
86 | },
87 | "ClientSideData": {
88 | "QueryAPI": {
89 | "data": [
90 | "Async",
91 | "Reactive queries"
92 | ]
93 | },
94 | "LocalRefreshLatency": {
95 | "data": "10ms-2s",
96 | "comment": "Depends on cardinality, query optimization plan, and local data size."
97 | },
98 | "PersistenceMechanism": {
99 | "data": [
100 | "SQLite"
101 | ]
102 | },
103 | "PersistenceFeatures": {
104 | "data": "Indexes"
105 | },
106 | "DataModel": {
107 | "data": "Document",
108 | "comment": "Queries are SQL, records are document-oriented."
109 | },
110 | "OfflineReads": {
111 | "data": "Full Support",
112 | "comment": "Dynamic query support."
113 | },
114 | "OptimisticUpdates": {
115 | "data": "Yes"
116 | },
117 | "OfflineWrites": {
118 | "data": "Full local conflict resolution"
119 | },
120 | "DataSize": {
121 | "data": "up to the size of the hard drive"
122 | }
123 | },
124 | "SynchronizationStrategy": {
125 | "FullOrPartialReplication": {
126 | "data": [
127 | "Full Replication",
128 | "Partial Replication"
129 | ],
130 | "comment": "Defined using [subscriptions](https://docs.ditto.live/key-concepts/syncing-data). Supports flexible [authorization](https://docs.ditto.live/key-concepts/authentication-and-authorization) model."
131 | },
132 | "ConflictHandling": {
133 | "data": "Automatic via CRDT",
134 | "comment": "All changes are recorded and conflicts are resolved automatically"
135 | },
136 | "WhereResolutionOccurs": {
137 | "data": "Client"
138 | },
139 | "WhatGetsSynced": {
140 | "data": {
141 | "ClientToClient": "document deltas"
142 | },
143 | "comment": "Ditto has client-to-client deltas, and the server is running the same CRDT as the client, and is not required."
144 | },
145 | "Authority": {
146 | "data": "Decentralized",
147 | "comment": "Decentralized via authentication servers."
148 | }
149 | },
150 | "AuthIdentity": {
151 | "Encryption": {
152 | "data": "Built-in e2ee"
153 | },
154 | "AuthenticationMethod": {
155 | "data": [
156 | "JWT Tokens"
157 | ]
158 | },
159 | "AuthorizationPermissions": {
160 | "data": "Custom-mapped ACLs"
161 | }
162 | },
163 | "UIRelated": {
164 | "Components": {
165 | "data": [
166 | "Presence"
167 | ],
168 | "comment": "SDK provides which peers you are connected to, and over what transports."
169 | }
170 | },
171 | "DevelopmentWorkflowsDX": {
172 | "DebuggingTools": {
173 | "data": [
174 | "DevTools",
175 | "Data Inspector",
176 | "Network Inspector"
177 | ],
178 | "comment": "Open source debugging and diagnostic tools for developers."
179 | }
180 | },
181 | "__generated": {
182 | "lastUpdated": "2025-04-30T15:39:55.000Z"
183 | }
184 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/ditto/details.md:
--------------------------------------------------------------------------------
1 | # Ditto
2 |
3 | Resilient Edge Device Connectivity. Servers and Cloud, Optional. The only mobile database with built-in edge device connectivity and resiliency
4 |
5 | ## Keep mission-critical systems online when it matters most
6 |
7 | Ditto is the only edge-native, mobile database that can consistently support your business anytime, anywhere. Edge-native solutions are built specifically to thrive on mobile and edge devices, without relying solely on cloud-based services.
8 |
9 | - **Build flexible operations** that are both latency-sensitive and resilient without reliance on network hardware, edge servers, or the cloud.
10 | - **Decentralize your systems** to remove single points of failure that lead to operational bottlenecks.
11 | - **Drive consistent revenue and customer service** anywhere, regardless of connectivity or bandwidth.
12 | - **Offline-first mobile database**: Even when your devices are completely offline, they can awlays read, write, and process data.
13 | - **Cross-platform**: Works on all major platforms.
14 | - **CRDT-powered conflict resolution**: To resolve concurrency conflicts that appear in decentralized models, as well as enable delta-based sync, Ditto harnesses the power of conflict-free replicated data types (CRDT) technology.
15 |
16 | ## P2P Sync
17 |
18 | ### Automatic Device Discovery and Mesh Networking
19 |
20 | Out-of-the-box support for BLE, P2P Wifi, LAN, and more enables real-time sync in disconnected or bandwidth-constrained environments.
21 |
22 | ### Direct Peer-to-Peer Sync
23 |
24 | Out-of-the-box suport for direct peer-to-peer sync between devices, without the need for a central server.
25 |
26 | ### Opportunistic Cloud Sync
27 |
28 | Anytime internet is available within the mesh, devices sync with your existing cloud systems.
29 |
30 | ## Core Features
31 |
32 | - **Intelligent Rainbow Connection**: Ditto manages multiple P2P and IP-based transports at the same time and optimizes your sync for speed based on available bandwidth.
33 | - **Opportunistic Cloud Sync**: Opportunistically sync with Ditto Server whenever a device within the mesh has internet.
34 | - **Bidirectional Cloud Connector**: Bidirectionally sync from Ditto Server to your existing systems.
35 | - **Cross-Platform Support**: Build and sync across your preferred languages, frameworks, and platforms.
36 | - **Conflict Resolution with CRDTs**: Simultaneous and offline changes are automatically resolved
37 | - **Expressive query system**: Find what you need with advanced filters, sorting, transactions.
38 | - **Reactive Design Patterns**: No more polling code for changes, register queries and get updates in real-time.
39 | - **Bring your own authentication**: Whether it's JWT, OAuth 2.0 or SAML. Bring your own identity providers.
40 |
41 |
42 | ## Learn More
43 | - [Ditto Website](https://www.ditto.com)
44 | - [Ditto Docs](https://docs.ditto.live/sdk/latest/quickstarts/quickstarts-landing)
45 | - [Ditto GitHub](https://github.com/getditto)
46 |
47 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/ditto/logo.dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/ditto/logo.light.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/dxos/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "dxos",
4 | "Name": "DXOS",
5 | "Description": "DXOS is an open source framework for building real-time, collaborative web applications.",
6 | "Website": "https://dxos.org",
7 | "Deployment": [
8 | "Self-hosted"
9 | ],
10 | "License": "MIT",
11 | "AppTarget": {
12 | "Platform": {
13 | "data": [
14 | "Browser",
15 | "Node"
16 | ]
17 | },
18 | "LanguageSDK": {
19 | "data": [
20 | "TypeScript"
21 | ]
22 | }
23 | },
24 | "Networking": {
25 | "Protocol": {
26 | "data": [
27 | "WebRTC",
28 | "WebSockets"
29 | ],
30 | "comment": "P2P connections are made via WebRTC, and client-server connections are made via WebSockets."
31 | },
32 | "Topology": {
33 | "data": "P2P",
34 | "comment": "Always available data optionally provided by server-based peers."
35 | }
36 | },
37 | "ServerSideData": {
38 | "PersistenceMechanism": {
39 | "data": [
40 | "N/A"
41 | ]
42 | },
43 | "DataModelParadigm": {
44 | "data": "Document"
45 | }
46 | },
47 | "ClientSideData": {
48 | "QueryAPI": {
49 | "data": [
50 | "Async",
51 | "Signals-based Reactivity"
52 | ]
53 | },
54 | "LocalRefreshLatency": {
55 | "data": "10-50ms",
56 | "comment": "Data is stored as Automerge documents under the hood."
57 | },
58 | "PersistenceMechanism": {
59 | "data": [
60 | "IndexedDB"
61 | ]
62 | },
63 | "PersistenceFeatures": {
64 | "data": "Indexes",
65 | "comment": "Custom indexes coming soon."
66 | },
67 | "DataModel": {
68 | "data": "Document"
69 | },
70 | "SchemaManagement": {
71 | "data": [
72 | "Schema definition",
73 | "Schema migrations",
74 | "Schema validation on write"
75 | ],
76 | "comment": "Schemas are defined using Effect Schema, and are validated on write. Migrations are supported at the object level."
77 | },
78 | "OfflineReads": {
79 | "data": "Full Support"
80 | },
81 | "OptimisticUpdates": {
82 | "data": "Yes"
83 | },
84 | "OfflineWrites": {
85 | "data": "Full local conflict resolution"
86 | },
87 | "DataSize": {
88 | "data": "up to 5-10mb per object",
89 | "comment": "Objects are Automerge documents under the hood."
90 | }
91 | },
92 | "SynchronizationStrategy": {
93 | "FullOrPartialReplication": {
94 | "data": [
95 | "Full Replication"
96 | ],
97 | "comment": "Full replication of all spaces joined per identity."
98 | },
99 | "ConflictHandling": {
100 | "data": "Automatic via CRDT",
101 | "comment": "Automerge is the CRDT used under the hood."
102 | },
103 | "WhereResolutionOccurs": {
104 | "data": "Client"
105 | },
106 | "WhatGetsSynced": {
107 | "data": {
108 | "ClientToClient": "see Automerge"
109 | },
110 | "comment": "Automerge is the CRDT used under the hood."
111 | },
112 | "Authority": {
113 | "data": "Decentralized"
114 | }
115 | },
116 | "AuthIdentity": {
117 | "Encryption": {
118 | "data": "Transport-level encryption",
119 | "comment": "Data is not currently encrypted at rest. E2EE is planned via Keyhive."
120 | },
121 | "AuthenticationMethod": {
122 | "data": [
123 | "Public keys"
124 | ]
125 | },
126 | "AuthorizationPermissions": {
127 | "data": "RBAC"
128 | }
129 | },
130 | "UIRelated": {
131 | "RichTextEditing": {
132 | "data": "Yes",
133 | "comment": "Anything compatible with Automerge documents (e.g. CodeMirror, ProseMirror, etc.)"
134 | },
135 | "Components": {
136 | "data": [
137 | "Invitations",
138 | "Presence"
139 | ],
140 | "comment": "React components for performing invitations are provided. SDK provides which peers you are connected to."
141 | }
142 | },
143 | "DevelopmentWorkflowsDX": {
144 | "DebuggingTools": {
145 | "data": [
146 | "DevTools",
147 | "Data Inspector",
148 | "Network Inspector"
149 | ]
150 | },
151 | "CLI": {
152 | "data": "CLI which contains a full client and commands for managing identities, spaces, etc."
153 | },
154 | "TypeSupport": {
155 | "data": "Full type support via Effect Schema"
156 | }
157 | },
158 | "__generated": {
159 | "lastUpdated": "2025-04-26T18:46:14.000Z"
160 | }
161 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/dxos/details.md:
--------------------------------------------------------------------------------
1 | # DXOS
2 |
3 | The new standard for building collaborative local-first software.
4 |
5 | DXOS is an open source framework for building real-time, collaborative web applications that run entirely on the client and communicate peer-to-peer, without the need for centralized servers.
6 |
7 | To show off the power of DXOS, we've built [Composer](https://dxos.org/composer). A local-first workspace that is designed for small team collaboration.
8 |
9 | ## Features
10 |
11 | - **Client-side databases that scale**: ECHO is an open source database architecture that incorporates transparent data replication and conflict resolution for secure and scalable local storage.
12 | - **Seamless Public/Private key identities**: HALO seamlessly manages digital identities using public/private key pairs allowing nuanced control over access to applications, databases, and networked devices.
13 | - **Performant Peer-to-Peer networks**: MESH extends existing internet protocols to enable secure and resilient peer-to-peer networks without the need for centralized server infrastructure.
14 | - **Seamless Collaboration**: Add realtime collaboration to your local-first application without the complexity of building your own sync engine.
15 |
16 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/dxos/logo.dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/dxos/logo.light.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/electricsql/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "electricsql",
4 | "Name": "ElectricSQL",
5 | "Website": "https://electric-sql.com",
6 | "Deployment": [
7 | "Self-hosted",
8 | "Hosted"
9 | ],
10 | "License": "Apache 2.0",
11 | "AppTarget": {
12 | "Platform": {
13 | "data": [
14 | "Browser",
15 | "React Native",
16 | "iOS",
17 | "Android",
18 | "macOS",
19 | "WASM",
20 | "Linux",
21 | "Node",
22 | "Javascript",
23 | "Typescript",
24 | "Elixir"
25 | ]
26 | }
27 | },
28 | "ServerSideData": {
29 | "PersistenceMechanism": {
30 | "data": [
31 | "Postgres"
32 | ]
33 | },
34 | "DataModelParadigm": {
35 | "data": "Relational"
36 | }
37 | },
38 | "ClientSideData": {
39 | "PersistenceMechanism": {
40 | "data": [
41 | "In-Memory",
42 | "Browser File Cache",
43 | "Localstorage",
44 | "IndexedDB",
45 | "OPFS",
46 | "SQLite",
47 | "PGLite",
48 | "React Query",
49 | "TanStack Optimistic",
50 | "Cloudflare Durable Object Storage",
51 | "Cloudflare D1",
52 | "Redis",
53 | "Custom"
54 | ],
55 | "comment": "\n Electric syncs data out of Postgres into anything you like.\n From an in-memory state variable to a local embedded database.\n "
56 | },
57 | "DataModel": {
58 | "data": "Log, Object or relational",
59 | "comment": "\n Data syncs in as a log of logical change operations.\n These can be materialized as collections of rows,\n or into an embedded database as relations in tables.\n "
60 | },
61 | "OfflineReads": {
62 | "data": "Full Support",
63 | "comment": "Full support when shape is synced."
64 | },
65 | "DataSize": {
66 | "data": "Limited by size of hard drive"
67 | }
68 | },
69 | "SynchronizationStrategy": {
70 | "FullOrPartialReplication": {
71 | "data": [
72 | "Partial Replication"
73 | ],
74 | "comment": "Partial replication via shapes."
75 | },
76 | "ConflictHandling": {
77 | "data": "Flexible",
78 | "comment": "\n Electric handles read-path sync. It doesn't prescribe a solution for writes\n and thus avoids handling conflicts. It does provide documented patterns\n and framework integrations for handling writes and optimistic state.\n These implement a range of strategies for conflict handling.\n "
79 | },
80 | "WhereResolutionOccurs": {
81 | "data": "Server"
82 | },
83 | "WhatGetsSynced": {
84 | "data": {
85 | "ServerToClient": "\n Shape logs, in the form of a stream of change messages\n (inserts, updates and deletes) and control messages\n (up-to-date, must-refetch).\n "
86 | }
87 | },
88 | "Authority": {
89 | "data": "Centralized",
90 | "comment": "Postgres is the source of truth, durability and total order."
91 | }
92 | },
93 | "__generated": {
94 | "lastUpdated": "2025-04-16T12:53:20.000Z"
95 | }
96 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/electricsql/details.md:
--------------------------------------------------------------------------------
1 | ## General
2 |
3 | Electric is a [Postgres sync engine](https://electric-sql.com). It syncs data out of Postgres into anything you like.
4 |
5 | Electric handles read-path sync, [partial replication](https://electric-sql.com/docs/guides/shapes), [fan-out](https://electric-sql.com/docs/api/http#caching), and [data delivery](https://electric-sql.com/docs/api/http). So you can build fast, modern software on live, local data — without rolling your own sync engine.
6 |
7 | Electric works with [any Postgres](https://electric-sql.com/docs/guides/deployment#_1-running-postgres), [any data model](https://electric-sql.com/docs/guides/deployment#data-model-compatibility) and [any web framework](https://electric-sql.com/docs/guides/client-development). Data syncs [over HTTP](https://electric-sql.com/docs/api/http), allowing you to use your existing API and web stack to handle auth, writes and any arbitrary stream transformation. Because it's HTTP, it works with standard CDNs, allowing you to easily scale out low-latancy data delivery to [millions of concurrent clients](https://electric-sql.com/docs/reference/benchmarks#cloud).
8 |
9 |
10 |
11 | ## The Story
12 |
13 | Electric was founded by [James Arthur and Valter Balegas](https://electric-sql.com/about/team), in collaboration with two of the inventors of CRDTs, Marc Shapiro and Nuno Preguiça; and Annette Bieniusa, a world expert on distributed database technology. Kyle Mathews joined as the third founder in 2024, having previously built and sold Gatsby to Netlify.
14 |
15 | The original vision for Electric was to build on [research advances in eventually consistent database technology](https://electric-sql.com/docs/reference/literature) to build a next-generation geo-distributed database for the "AP" side of the CAP theorem. The team quickly pivoted to using the same techniques to provide a replication layer for existing open source databases and then focused on building an end-to-end local-first software stack as the killer app for this.
16 |
17 | When Kyle joined, he led a [clean re-write](https://electric-sql.com/blog/2024/07/17/electric-next) to simplify Electric and build a core system that worked well for read-path sync. This pushed a lot of complexity out of scope which, combined with the experience the team had gained building previous iterations, allowed Electric to quickly build a highly-scalable read-path sync engine based based on a [new HTTP protocol](https://electric-sql.com/docs/api/http).
18 |
19 | This new system [hit BETA](https://electric-sql.com/blog/2024/12/10/electric-beta-release) in December 2025 and [GA with a 1.0 release](https://electric-sql.com/blog/2025/03/17/electricsql-1.0-released) on the 17th March 2025.
20 |
21 | Electric is a funded startup, backed by VCs including [Spark Captial](https://www.sparkcapital.com), [Lunar Ventures](https://www.lunar.vc) and [StepFunction](https://www.stepfunction.vc). They are also backed by a range of leading database and devtools founders, including the founders of Supabase, Motherduck, Cockroach, Xata, Nile, Heroku and Ink & Switch and leading angels like Theo Brown and Chris Riccomini.
22 |
23 | The core technology of Electric is developed in Elixir and the company is also backed by José Valim, the creator of Elixir and integrated into Phoenix, the main Elixir web framework as [Phoenix.Sync](https://hexdocs.pm/phoenix_sync). Other notable framework integrations include [LiveStore](LiveStore.dev) and [@TanStack/optimistic](https://github.com/TanStack/optimistic).
24 |
25 | Electric also develop the popular [PGlite](https://pglite.dev) project, a lightweight embeddable Postgres database that can be used in the browser. The two products (the Electric sync engine and the PGlite database) can be used together or independently and are now built into leading developer tools such as Google's [Firebase Tools](https://www.npmjs.com/package/firebase-tools?activeTab=dependencies) and Supabase's AI project builder [database.build](https://database.build).
26 |
27 | ## Resources
28 |
29 | Electric is an open source project published on GitHub as [electric-sql/electric](https://github.com/electric-sql/electric). Everything is Apache 2.0 licensed. There's an open Discord community at [discord.electric-sql.com](https://discord.electric-sql.com) and the PGlite project has a separate website at [pglite.dev](https://pglite.dev).
30 |
31 | - [Website](https://electric-sql.com)
32 | - [Docs](https://electric-sql.com/docs/intro)
33 | - [GitHub](https://github.com/electric-sql/electric)
34 | - [Discord](https://discord.electric-sql.com)
35 | - [Bluesky](https://bsky.app/profile/electric-sql.com)
36 | - [PGlite](https://pglite.dev)
37 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/electricsql/logo.dark.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/electricsql/logo.light.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/instant/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "instant",
4 | "Name": "InstantDB",
5 | "Description": "Instant is a modern Firebase. We make you productive by giving your frontend a real-time database.",
6 | "MaturityLevel": "Production-Ready",
7 | "Website": "https://instandb.com",
8 | "GitHub": "https://github.com/instantdb/instant",
9 | "GetStarted": "https://www.instantdb.com/tutorial",
10 | "Deployment": [
11 | "Self-hosted",
12 | "Hosted"
13 | ],
14 | "License": "Apache",
15 | "AppTarget": {
16 | "Platform": {
17 | "data": [
18 | "Browser",
19 | "Node",
20 | "iOS",
21 | "Android",
22 | "Desktop"
23 | ],
24 | "comment": "iOS and Android support via React native. Desktop via Electron and Tauri"
25 | },
26 | "LanguageSDK": {
27 | "data": [
28 | "TypeScript",
29 | "JavaScript"
30 | ]
31 | },
32 | "FrameworkIntegrations": {
33 | "data": [
34 | "React",
35 | "React Native"
36 | ]
37 | },
38 | "ClientBundleSize": {
39 | "data": "~27kb gzipped"
40 | }
41 | },
42 | "Networking": {
43 | "Protocol": {
44 | "data": [
45 | "WebSockets",
46 | "HTTP"
47 | ]
48 | },
49 | "Topology": {
50 | "data": "Client-Server"
51 | }
52 | },
53 | "ServerSideData": {
54 | "PersistenceMechanism": {
55 | "data": [
56 | "Postgres"
57 | ],
58 | "comment": "Support for bring your postgres coming"
59 | },
60 | "DataModelParadigm": {
61 | "data": "Relational"
62 | },
63 | "SchemaManagement": {
64 | "data": [
65 | "Schema definition",
66 | "Validate schemas on write"
67 | ]
68 | }
69 | },
70 | "ClientSideData": {
71 | "QueryAPI": {
72 | "data": [
73 | "Async",
74 | "Reactive queries"
75 | ]
76 | },
77 | "LocalRefreshLatency": {
78 | "data": "~1ms"
79 | },
80 | "PersistenceMechanism": {
81 | "data": [
82 | "IndexedDB"
83 | ]
84 | },
85 | "PersistenceFeatures": {
86 | "data": "Indexes, Transactions"
87 | },
88 | "DataModel": {
89 | "data": "Relational"
90 | },
91 | "OfflineReads": {
92 | "data": "Query Cache"
93 | },
94 | "OptimisticUpdates": {
95 | "data": "Yes"
96 | },
97 | "OfflineWrites": {
98 | "data": "Queued offline writes"
99 | },
100 | "DataSize": {
101 | "data": "Limited by device capabilities"
102 | }
103 | },
104 | "SynchronizationStrategy": {
105 | "FullOrPartialReplication": {
106 | "data": [
107 | "Partial Replication"
108 | ],
109 | "comment": "Use InstaQL queries to control which data is replicated"
110 | },
111 | "ConflictHandling": {
112 | "data": "Last write wins at attribute level"
113 | },
114 | "WhereResolutionOccurs": {
115 | "data": "Server"
116 | },
117 | "WhatGetsSynced": {
118 | "data": {
119 | "ClientToServer": "Mutations",
120 | "ServerToClient": "Rows"
121 | },
122 | "comment": "\"Mutations\" are instant logical operations `update`, `delete`. \"Rows\" are data that the client side engine uses to fulfill queries"
123 | },
124 | "Authority": {
125 | "data": "Centralized"
126 | },
127 | "Latency": {
128 | "data": "Close to network latency"
129 | },
130 | "Throughput": {
131 | "data": "Hundreds of writes per second",
132 | "comment": "This is based on early 2025 usage."
133 | },
134 | "Concurrency": {
135 | "data": "Effectively unlimited",
136 | "comment": "Server is horizontally scalable and shared-nothing. Running on top of Aurora. To see live connections go to instantdb.com"
137 | }
138 | },
139 | "AuthIdentity": {
140 | "Encryption": {
141 | "data": "no"
142 | },
143 | "AuthenticationMethod": {
144 | "data": [
145 | "JWT Tokens"
146 | ]
147 | },
148 | "AuthorizationPermissions": {
149 | "data": "Custom",
150 | "comment": "Permissions are defined using Instant's Rule Language which is builds on top of Google's CEL. For more details see: https://instantdb.com/docs/permissions"
151 | }
152 | },
153 | "DevelopmentWorkflowsDX": {
154 | "DebuggingTools": {
155 | "data": [
156 | "DevTools",
157 | "Data Inspector",
158 | "Dashboard"
159 | ]
160 | },
161 | "CLI": {
162 | "data": "Yes"
163 | },
164 | "TypeSupport": {
165 | "data": "Yes"
166 | }
167 | },
168 | "__generated": {
169 | "lastUpdated": "2025-04-30T18:24:22.000Z"
170 | }
171 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/instant/details.md:
--------------------------------------------------------------------------------
1 | # Insant
2 |
3 | Instant is a modern Firebase. We make you productive by giving your frontend a real-time database.
4 |
5 | You write [relational queries](https://www.instantdb.com/docs/instaql) in the shape of the data you want and Instant handles all the data fetching, permission checking, and offline caching. When you [change data](https://www.instantdb.com/docs/instaml), optimistic updates and rollbacks are handled for you as well. Plus, every query is multiplayer by default.
6 |
7 | We also support [ephemeral](https://www.instantdb.com/docs/presence-and-topics) updates, like cursors, or who's online. Currently we have SDKs for [Javascript](https://www.instantdb.com/docs/start-vanilla), [React](https://www.instantdb.com/docs/), and [React Native](https://www.instantdb.com/docs/start-rn).
8 |
9 | How does it look? Here's a barebones chat app in about 12 lines:
10 |
11 | ```javascript
12 | // ༼ つ ◕_◕ ༽つ Real-time Chat
13 | // ----------------------------------
14 | // * Updates instantly
15 | // * Multiplayer
16 | // * Works offline
17 |
18 | import { init, tx, id } from "@instantdb/react";
19 |
20 | const db = init({
21 | appId: process.env.NEXT_PUBLIC_APP_ID,
22 | });
23 |
24 | function Chat() {
25 | // 1. Read
26 | const { isLoading, error, data } = db.useQuery({
27 | messages: {},
28 | });
29 |
30 | // 2. Write
31 | const addMessage = (message) => {
32 | db.transact(tx.messages[id()].update(message));
33 | };
34 |
35 | // 3. Render!
36 | return ;
37 | }
38 | ```
39 |
40 | Want to see for yourself? try a demo in your browser.
41 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/instant/logo.dark.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/instant/logo.light.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/jazz/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "jazz",
4 | "Name": "Jazz",
5 | "Description": "Toolkit for backendless apps.",
6 | "MaturityLevel": "Production-Ready",
7 | "Website": "https://jazz.tools",
8 | "GitHub": "https://github.com/garden-co/jazz",
9 | "GetStarted": "https://jazz.tools/docs",
10 | "InitialReleaseDate": "2023-09-11T00:00:00.000Z",
11 | "Deployment": [
12 | "Self-hosted",
13 | "Hosted"
14 | ],
15 | "License": "MIT",
16 | "AppTarget": {
17 | "Platform": {
18 | "data": [
19 | "Browser",
20 | "Node",
21 | "iOS",
22 | "Android"
23 | ],
24 | "comment": "iOS and Android support via React Native."
25 | },
26 | "LanguageSDK": {
27 | "data": [
28 | "TypeScript"
29 | ]
30 | },
31 | "FrameworkIntegrations": {
32 | "data": [
33 | "React",
34 | "React Native",
35 | "Vue (experimental)",
36 | "Svelte (experimental)"
37 | ]
38 | },
39 | "ClientBundleSize": {
40 | "data": "112kb gzipped (jazz-react)"
41 | }
42 | },
43 | "Networking": {
44 | "Protocol": {
45 | "data": [
46 | "WebSockets"
47 | ]
48 | },
49 | "Topology": {
50 | "data": "P2P",
51 | "comment": "P2P via sync & storage servers. Servers are not stateless."
52 | }
53 | },
54 | "ServerSideData": {
55 | "PersistenceMechanism": {
56 | "data": [
57 | "SQLite",
58 | "Custom"
59 | ]
60 | },
61 | "DataSize": {
62 | "data": "Unlimited, granular load & sync"
63 | },
64 | "DataModelParadigm": {
65 | "data": "Document"
66 | },
67 | "SchemaManagement": {
68 | "data": [
69 | "Schema definition",
70 | "Derived types",
71 | "Schema migrations"
72 | ]
73 | },
74 | "ExistingDatabaseSupport": {
75 | "data": "manual sync to existing DBs"
76 | }
77 | },
78 | "ClientSideData": {
79 | "QueryAPI": {
80 | "data": [
81 | "Sync",
82 | "Signals-based Reactivity"
83 | ]
84 | },
85 | "LocalRefreshLatency": {
86 | "data": "~1ms"
87 | },
88 | "PersistenceMechanism": {
89 | "data": [
90 | "IndexedDB",
91 | "SQLite"
92 | ]
93 | },
94 | "DataModel": {
95 | "data": "Document"
96 | },
97 | "SchemaManagement": {
98 | "data": [
99 | "Schema definition",
100 | "Derived types",
101 | "Schema migrations"
102 | ]
103 | },
104 | "OfflineReads": {
105 | "data": "Full Support"
106 | },
107 | "OptimisticUpdates": {
108 | "data": "Yes"
109 | },
110 | "OfflineWrites": {
111 | "data": "Local conflict resolution"
112 | },
113 | "DataSize": {
114 | "data": "limited by RAM",
115 | "comment": "Soon limited only by disk."
116 | }
117 | },
118 | "SynchronizationStrategy": {
119 | "FullOrPartialReplication": {
120 | "data": [
121 | "Partial Replication"
122 | ],
123 | "comment": "Partial replication on-demand or with explicit load depths."
124 | },
125 | "ConflictHandling": {
126 | "data": "Automatic via CRDT"
127 | },
128 | "WhereResolutionOccurs": {
129 | "data": "Client"
130 | },
131 | "WhatGetsSynced": {
132 | "data": {
133 | "ClientToClient": "CoValue headers, CoValue session diffs (transactions)"
134 | }
135 | },
136 | "Authority": {
137 | "data": "Decentralized"
138 | },
139 | "Latency": {
140 | "data": "Close to network latency"
141 | },
142 | "Throughput": {
143 | "data": "Roughly 5k transactions/s (structured data) or ~50MB/s (binary data)",
144 | "comment": "Soon: limited only by number of participants (updates of any size by up to 5k participants/s)"
145 | },
146 | "Concurrency": {
147 | "data": "Support for granular prioritization"
148 | }
149 | },
150 | "AuthIdentity": {
151 | "Encryption": {
152 | "data": "Yes",
153 | "comment": "Built-in e2ee"
154 | },
155 | "AuthenticationMethod": {
156 | "data": [
157 | "Built-in"
158 | ]
159 | },
160 | "AuthorizationPermissions": {
161 | "data": "Built-in cryptographical hierarchical RBAC"
162 | }
163 | },
164 | "UIRelated": {
165 | "RichTextEditing": {
166 | "data": "Yes",
167 | "comment": "ProseMirror integration"
168 | },
169 | "Components": {
170 | "data": [
171 | "File upload",
172 | "progressive image loading",
173 | "multiplayer cursors"
174 | ]
175 | }
176 | },
177 | "DevelopmentWorkflowsDX": {
178 | "DebuggingTools": {
179 | "data": [
180 | "Data Inspector"
181 | ]
182 | },
183 | "CLI": {
184 | "data": "CLI for running local sync & storage server, for creating worker account"
185 | },
186 | "TypeSupport": {
187 | "data": "Full type support without extra config"
188 | }
189 | },
190 | "__generated": {
191 | "lastUpdated": "2025-04-29T12:51:37.000Z"
192 | }
193 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/jazz/details.md:
--------------------------------------------------------------------------------
1 | # Jazz
2 |
3 | ## Toolkit for backendless apps.
4 |
5 | Jazz gives you data without needing a database — plus auth, permissions, files and multiplayer without needing a backend.
6 |
7 | Do everything right from the frontend and ship better apps, faster.
8 |
9 | Open source. Self-host or use Jazz Cloud for zero-config magic.
10 |
11 | ## Features
12 |
13 | - Instant updates
14 | - Real-time sync
15 | - Multiplayer
16 | - File uploads
17 | - Social features
18 | - Permissions
19 | - E2E encryption
20 | - Authentication
21 |
22 | Find out how it works and more details at [jazz.tools](https://jazz.tools)
23 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/jazz/logo.dark.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/jazz/logo.light.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/liveblocks-storage/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "liveblocks-storage",
4 | "Name": "Liveblocks Storage",
5 | "MaturityLevel": "Production-ready",
6 | "Website": "https://liveblocks.io/sync-datastore/storage",
7 | "InitialReleaseDate": "2022-03-16T00:00:00.000Z",
8 | "Deployment": [
9 | "Hosted"
10 | ],
11 | "License": "Proprietary",
12 | "AppTarget": {
13 | "Platform": {
14 | "data": [
15 | "Browser",
16 | "Node"
17 | ]
18 | },
19 | "LanguageSDK": {
20 | "data": [
21 | "TypeScript"
22 | ]
23 | },
24 | "FrameworkIntegrations": {
25 | "data": [
26 | "React",
27 | "Zustand",
28 | "Redux"
29 | ]
30 | }
31 | },
32 | "Networking": {
33 | "Protocol": {
34 | "data": [
35 | "WebSockets",
36 | "HTTP"
37 | ]
38 | },
39 | "Topology": {
40 | "data": "Client-Server"
41 | }
42 | },
43 | "ServerSideData": {
44 | "PersistenceMechanism": {
45 | "data": [
46 | "Cloudflare Durable Object Storage",
47 | "SQLite"
48 | ]
49 | },
50 | "DataModelParadigm": {
51 | "data": "Document",
52 | "comment": "Each room is a digital space where people colalborate, and it corresponds with a document."
53 | },
54 | "SchemaManagement": {
55 | "data": [
56 | "Schema definition",
57 | "Schema validation"
58 | ]
59 | },
60 | "ExistingDatabaseSupport": {
61 | "data": "One-way sync with DBs",
62 | "comment": "Does not require a datastore, but you can migrate or automatically sync to your database with webhooks/REST API"
63 | }
64 | },
65 | "ClientSideData": {
66 | "QueryAPI": {
67 | "data": [
68 | "Signals-based reactivity",
69 | "Reactive queries"
70 | ],
71 | "comment": "JS: via subscription. React: via selector hooks, mutation callbacks. Automatically converts live data structures to JSON for easy UI. Hooks update automatically on changes. Can retrieve deep into the data structure without causing unnecessary renders."
72 | },
73 | "LocalRefreshLatency": {
74 | "data": "<1ms",
75 | "comment": "Changes on the client: <1ms. Other clients receive updates up to 60 times per second(16ms), configurable."
76 | },
77 | "PersistenceMechanism": {
78 | "data": [
79 | "Liveblocks Storage"
80 | ]
81 | },
82 | "DataModel": {
83 | "data": "Document",
84 | "comment": "LiveObject"
85 | },
86 | "SchemaManagement": {
87 | "data": [
88 | "Schema definition"
89 | ]
90 | },
91 | "OfflineReads": {
92 | "data": "Query Cache",
93 | "comment": "Previously accessed data is stored in-memory"
94 | },
95 | "OptimisticUpdates": {
96 | "data": "Yes"
97 | },
98 | "OfflineWrites": {
99 | "data": "Cached offline writes",
100 | "comment": "Full cached writes, stored in-memory, server will resolve conflict."
101 | },
102 | "DataSize": {
103 | "data": "Limited by memory",
104 | "comment": "It depends on the in memory size of the Storage document."
105 | }
106 | },
107 | "SynchronizationStrategy": {
108 | "ConflictHandling": {
109 | "data": "Automatic via LWW or fractional indexing",
110 | "comment": "Values: LWW, LiveObject: LWW at attribute level, LiveMap: LWW at entry level, LiveList: fractional indexing (for insertions) or LWW (for replacements)"
111 | },
112 | "WhereResolutionOccurs": {
113 | "data": "Server"
114 | },
115 | "WhatGetsSynced": {
116 | "data": {
117 | "ClientToServer": "ops",
118 | "ServerToClient": "ops, acks, and fix-ops (when conflict was resolved)"
119 | }
120 | },
121 | "Authority": {
122 | "data": "Centralized"
123 | }
124 | },
125 | "AuthIdentity": {
126 | "Encryption": {
127 | "data": "Transport-level (wss:// or https://)"
128 | },
129 | "AuthenticationMethod": {
130 | "data": [
131 | "JWT tokens",
132 | "Public key"
133 | ]
134 | },
135 | "AuthorizationPermissions": {
136 | "data": "ID tokens and access tokens",
137 | "comment": "ID tokens for permissions based on a per-room basis. Access tokens for permissions granted directly in the token"
138 | }
139 | },
140 | "UIRelated": {
141 | "Components": {
142 | "data": [
143 | "Comments/Threads",
144 | "Notifications",
145 | "AI Copilots",
146 | "Presence"
147 | ],
148 | "comment": "All Liveblocks products integrate into each other. Learn more about the other products on [liveblocks.io](https://liveblocks.io)."
149 | }
150 | },
151 | "DevelopmentWorkflowsDX": {
152 | "DebuggingTools": {
153 | "data": [
154 | "DevTools",
155 | "Dashboard",
156 | "Data Inspector"
157 | ],
158 | "comment": "Viewing/editing data, events, usage, etc."
159 | },
160 | "CLI": {
161 | "data": "CLI for installing examples, updating packages, creating your typescript config."
162 | },
163 | "TypeSupport": {
164 | "data": "Full type support",
165 | "comment": "Via [`liveblocks.config.ts`](https://liveblocks.io/docs/api-reference/liveblocks-react#TypeScript)."
166 | }
167 | },
168 | "__generated": {
169 | "lastUpdated": "2025-04-24T11:47:23.000Z"
170 | }
171 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/liveblocks-storage/details.md:
--------------------------------------------------------------------------------
1 | # Liveblocks
2 |
3 | [Liveblocks](https://liveblocks.io) provides customizable pre-built features for human and AI collaboration, used to make your product multiplayer, engaging, and AI‑ready. All without derailing your roadmap.
4 |
5 | ## Liveblocks Storage
6 |
7 | [Liveblocks Storage](https://liveblocks.io/sync-datastore/storage) is a realtime sync engine designed for multiplayer creative tools such as Figma, Pitch, and Spline. `LiveList`, `LiveMap`, and `LiveObject` conflict-free data types can be used to build all sorts of multiplayer tools. Liveblocks permanently stores Storage data in each room, handling scaling and maintenance for you.
8 |
9 | ### Links
10 |
11 | - [Get started](https://liveblocks.io/docs/get-started/custom)
12 | - [API reference](https://liveblocks.io/docs/api-reference/liveblocks-client#Storage)
13 | - [Examples](https://liveblocks.io/examples)
14 | - [More info](https://liveblocks.io/docs/platform/sync-datastore/liveblocks-storage)
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/liveblocks-storage/logo.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/localfirstfm/local-first-landscape/621278c13945f8c197c671acddb588970549d208/landscape-content-snapshot/src/generated/liveblocks-storage/logo.dark.png
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/liveblocks-storage/logo.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/localfirstfm/local-first-landscape/621278c13945f8c197c671acddb588970549d208/landscape-content-snapshot/src/generated/liveblocks-storage/logo.light.png
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/liveblocks-yjs/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "liveblocks-yjs",
4 | "Name": "Liveblocks Yjs",
5 | "MaturityLevel": "Production-ready",
6 | "Website": "https://liveblocks.io/sync-datastore/yjs",
7 | "InitialReleaseDate": "2023-09-05T00:00:00.000Z",
8 | "Deployment": [
9 | "Hosted"
10 | ],
11 | "License": "Proprietary",
12 | "AppTarget": {
13 | "Platform": {
14 | "data": [
15 | "Browser",
16 | "Node"
17 | ]
18 | },
19 | "LanguageSDK": {
20 | "data": [
21 | "TypeScript"
22 | ]
23 | },
24 | "FrameworkIntegrations": {
25 | "data": [
26 | "React"
27 | ]
28 | }
29 | },
30 | "Networking": {
31 | "Protocol": {
32 | "data": [
33 | "WebSockets",
34 | "HTTP"
35 | ]
36 | },
37 | "Topology": {
38 | "data": "Client-Server"
39 | }
40 | },
41 | "ServerSideData": {
42 | "PersistenceMechanism": {
43 | "data": [
44 | "Cloudflare Durable Object Storage",
45 | "IndexedDB"
46 | ]
47 | },
48 | "DataModelParadigm": {
49 | "data": "Document",
50 | "comment": "Each room is a digital space where people colalborate, and it corresponds with a document."
51 | },
52 | "SchemaManagement": {
53 | "data": [
54 | "None"
55 | ]
56 | },
57 | "ExistingDatabaseSupport": {
58 | "data": "One-way sync with DBs",
59 | "comment": "Does not require a datastore, but you can migrate or automatically sync to your database with webhooks/REST API"
60 | }
61 | },
62 | "ClientSideData": {
63 | "QueryAPI": {
64 | "data": [
65 | "Yjs"
66 | ],
67 | "comment": "Standard Yjs API"
68 | },
69 | "LocalRefreshLatency": {
70 | "data": "<1ms",
71 | "comment": "Changes on the client: <1ms. Other clients receive updates up to 60 times per second(16ms), configurable."
72 | },
73 | "PersistenceMechanism": {
74 | "data": [
75 | "Yjs"
76 | ]
77 | },
78 | "DataModel": {
79 | "data": "Document"
80 | },
81 | "SchemaManagement": {
82 | "data": [
83 | "None"
84 | ]
85 | },
86 | "OfflineReads": {
87 | "data": "Yes",
88 | "comment": "Beta option: `offlineSupport_experimental: true`"
89 | },
90 | "OptimisticUpdates": {
91 | "data": "Yes"
92 | },
93 | "OfflineWrites": {
94 | "data": "Yes",
95 | "comment": "Beta option: `offlineSupport_experimental: true`"
96 | },
97 | "DataSize": {
98 | "data": "Limited by memory",
99 | "comment": "It depends on the in memory size of the Yjs store and the history of the document."
100 | }
101 | },
102 | "SynchronizationStrategy": {
103 | "ConflictHandling": {
104 | "data": "Automatic via CRDT"
105 | },
106 | "WhereResolutionOccurs": {
107 | "data": "Server"
108 | },
109 | "WhatGetsSynced": {
110 | "data": {
111 | "ClientToServer": "Yjs encoded updates"
112 | }
113 | },
114 | "Authority": {
115 | "data": "Centralized"
116 | }
117 | },
118 | "AuthIdentity": {
119 | "AuthenticationMethod": {
120 | "data": [
121 | "Built-in",
122 | "Full Custom"
123 | ]
124 | },
125 | "AuthorizationPermissions": {
126 | "data": "ID tokens and access tokens",
127 | "comment": "ID tokens for permissions based on a per-room basis. Access tokens for permissions granted directly in the token"
128 | }
129 | },
130 | "UIRelated": {
131 | "RichTextEditing": {
132 | "data": "Liveblocks Text Editor",
133 | "comment": "Wrapper around Yjs with TipTap, BlockNote, and Lexical plugins."
134 | },
135 | "Components": {
136 | "data": [
137 | "Comments/Threads",
138 | "Notifications",
139 | "AI Copilots",
140 | "Yjs plugins",
141 | "Presence"
142 | ],
143 | "comment": "All Liveblocks products integrate into each other. Learn more about the other products on [liveblocks.io](https://liveblocks.io)."
144 | }
145 | },
146 | "DevelopmentWorkflowsDX": {
147 | "DebuggingTools": {
148 | "data": [
149 | "DevTools",
150 | "Dashboard",
151 | "Data Inspector"
152 | ],
153 | "comment": "Viewing/editing data, events, usage, etc."
154 | },
155 | "CLI": {
156 | "data": "CLI for installing examples, updating packages, creating your typescript config."
157 | }
158 | },
159 | "__generated": {
160 | "lastUpdated": "2025-04-24T11:47:23.000Z"
161 | }
162 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/liveblocks-yjs/details.md:
--------------------------------------------------------------------------------
1 | # Liveblocks
2 |
3 | [Liveblocks](https://liveblocks.io) provides customizable pre-built features for human and AI collaboration, used to make your product multiplayer, engaging, and AI‑ready. All without derailing your roadmap.
4 |
5 | ## Liveblocks Yjs
6 |
7 | [Liveblocks Yjs](https://liveblocks.io/sync-datastore/yjs) is a realtime sync engine designed for building collaborative text editors such as Notion and Google Docs. Liveblocks permanently stores Yjs data in each room, handling scaling and maintenance for you.
8 |
9 | ### Links
10 |
11 | - [Get started](https://liveblocks.io/docs/get-started/text-editor)
12 | - [API reference](https://liveblocks.io/docs/api-reference/liveblocks-yjs)
13 | - [Examples](https://liveblocks.io/examples)
14 | - [More info](https://liveblocks.io/docs/platform/sync-datastore/liveblocks-yjs)
15 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/liveblocks-yjs/logo.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/localfirstfm/local-first-landscape/621278c13945f8c197c671acddb588970549d208/landscape-content-snapshot/src/generated/liveblocks-yjs/logo.dark.png
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/liveblocks-yjs/logo.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/localfirstfm/local-first-landscape/621278c13945f8c197c671acddb588970549d208/landscape-content-snapshot/src/generated/liveblocks-yjs/logo.light.png
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/livestore/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "livestore",
4 | "Name": "LiveStore",
5 | "Description": "Client-centric local-first data layer for high-performance apps",
6 | "MaturityLevel": "Beta",
7 | "Website": "https://livestore.dev",
8 | "GitHub": "https://github.com/livestore-dev/livestore",
9 | "GetStarted": "https://livestore.dev",
10 | "InitialReleaseDate": "2021-12-01T00:00:00.000Z",
11 | "Deployment": [
12 | "Self-hosted"
13 | ],
14 | "AppTarget": {
15 | "Platform": {
16 | "data": [
17 | "Browser",
18 | "Node",
19 | "iOS",
20 | "Android"
21 | ]
22 | },
23 | "LanguageSDK": {
24 | "data": [
25 | "TypeScript"
26 | ]
27 | },
28 | "FrameworkIntegrations": {
29 | "data": [
30 | "React",
31 | "React Native",
32 | "Solid"
33 | ]
34 | },
35 | "ClientBundleSize": {
36 | "data": "~500kb gzipped",
37 | "comment": "For web apps, LiveStore ships with a SQLite WASM build (~600kb / 300kb gzipped) and the library itself is around 500kb / 170kb gzipped."
38 | }
39 | },
40 | "Networking": {
41 | "Protocol": {
42 | "data": [
43 | "WebSockets",
44 | "HTTP",
45 | "SSE"
46 | ],
47 | "comment": "Given LiveStore supports arbitrary sync backends, any kind of network protocol can be used."
48 | },
49 | "Topology": {
50 | "data": "Client-Server"
51 | }
52 | },
53 | "ServerSideData": {
54 | "PersistenceMechanism": {
55 | "data": [
56 | "Cloudflare D1",
57 | "Postgres",
58 | "SQLite",
59 | "Custom"
60 | ],
61 | "comment": "Almost anything works as long as it can persist an eventlog."
62 | },
63 | "DataSize": {
64 | "data": "10GB",
65 | "comment": "Theoretically there isn't an upper limit to the eventlog size however at some point it might become impractical to sync the eventlog over the network."
66 | },
67 | "DataModelParadigm": {
68 | "data": "Eventlog"
69 | }
70 | },
71 | "ClientSideData": {
72 | "QueryAPI": {
73 | "data": [
74 | "Reactive queries",
75 | "Signals-based Reactivity",
76 | "Sync"
77 | ]
78 | },
79 | "LocalRefreshLatency": {
80 | "data": "~1ms",
81 | "comment": "LiveStore is designed to enable next-frame refresh latency by using an in-memory SQLite database with a signals-based reactivivity system."
82 | },
83 | "PersistenceMechanism": {
84 | "data": [
85 | "IndexedDB",
86 | "OPFS"
87 | ]
88 | },
89 | "PersistenceFeatures": {
90 | "data": "Indexes"
91 | },
92 | "DataModel": {
93 | "data": "Event Sourcing",
94 | "comment": "LiveStore follows the event sourcing pattern which separates writes into an eventlog and materializes state into a local SQLite database."
95 | },
96 | "OfflineReads": {
97 | "data": "Full Support"
98 | },
99 | "OptimisticUpdates": {
100 | "data": "Yes",
101 | "comment": "There isn't an explicit concept of \"optimistic updates\" in LiveStore. Events are always executed locally first and then synced to other clients. In case of a conflict, the event is rebased and replayed. This is similar to how Git works."
102 | },
103 | "OfflineWrites": {
104 | "data": "Local conflict resolution"
105 | },
106 | "DataSize": {
107 | "data": "<1GB",
108 | "comment": "The upper limit is mostly determined by the used browser or client device. SQLite stores data fairly efficiently, so you should rarely hit any limits in regards to size."
109 | }
110 | },
111 | "SynchronizationStrategy": {
112 | "FullOrPartialReplication": {
113 | "data": [
114 | "Full Replication"
115 | ]
116 | },
117 | "ConflictHandling": {
118 | "data": "Automatic via CRDT"
119 | },
120 | "WhereResolutionOccurs": {
121 | "data": "Client"
122 | },
123 | "WhatGetsSynced": {
124 | "data": {
125 | "ClientToClient": "Ops"
126 | }
127 | }
128 | },
129 | "DevelopmentWorkflowsDX": {
130 | "DebuggingTools": {
131 | "data": [
132 | "DevTools",
133 | "Data Inspector",
134 | "Network Inspector"
135 | ]
136 | }
137 | },
138 | "__generated": {
139 | "lastUpdated": "2025-04-29T14:51:46.000Z"
140 | }
141 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/livestore/details.md:
--------------------------------------------------------------------------------
1 | # LiveStore
2 |
3 | LiveStore is a TypeScript library that provides a unique approach to building data-intensive, **local-first** applications for the web and mobile (Expo). It combines the architectural benefits of **Event Sourcing** with the power and familiarity of **SQLite**, enhanced by a **signals-based reactivity system**.
4 |
5 | - **Event-Driven:** Instead of direct state mutation, all changes are captured as immutable, ordered **events**. This event log forms the definitive history of state transitions and is the single source of truth. This enables **undo/redo** functionality, **auditability**, and **easier schema migrations**.
6 | - **Pluggable Synchronization:** The **event log** is the unit of synchronization between clients and the backend. The log is synchronized using a push/pull mechanism with client-side rebasing (similar to Git). LiveStore is agnostic to what syncing provider you use and can work with any backend as long as it can persist an event log.
7 | - **Reactive SQLite**: LiveStore processes the event log to materialize the application's state into a local and reactive SQLite database. This database runs **in-memory** to allow for **instant and synchronous queries** directly within your components without `isLoading` states. The database is also **persisted** in the browser and can be used even when offline.
8 | - **Developer Tools**: Includes powerful Devtools for inspecting the real-time state database, browsing the event log, analyzing query performance, visualizing the reactivity graph, monitoring sync status, and executing direct SQLite queries. *(Note: Devtools access may be sponsor-only post-launch)*
9 | - **Open Source & Independent:** Available under an open source license and developed independently, focusing on sustainable development aligned with user needs.
10 |
11 | ## Resources
12 |
13 | - [Website](https://next.livestore.dev)
14 | - [Documentation](https://next.livestore.dev/docs/)
15 | - [GitHub](https://github.com/livestorejs/livestore)
16 | - [Examples](https://github.com/livestorejs/livestore/tree/main/examples/standalone)
17 | - [Discord](https://discord.gg/RbMcjUAPd7)
18 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/livestore/logo.dark.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/livestore/logo.light.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/loro/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "loro",
4 | "Name": "Loro",
5 | "Description": "Make your JSON data collaborative and version-controlled with CRDTs",
6 | "MaturityLevel": "Production-Ready",
7 | "Logo": {
8 | "Light": "https://github.com/loro-dev/loro/blob/main/docs/Loro.svg",
9 | "Dark": "https://github.com/loro-dev/loro/blob/main/docs/Loro.svg"
10 | },
11 | "Website": "https://loro.dev",
12 | "GitHub": "https://github.com/loro-dev/loro",
13 | "GetStarted": "https://loro.dev/docs/tutorial/get_started",
14 | "InitialReleaseDate": "2023-11-13T00:00:00.000Z",
15 | "Deployment": [
16 | "Self-hosted"
17 | ],
18 | "License": "MIT",
19 | "AppTarget": {
20 | "Platform": {
21 | "data": [
22 | "Browser",
23 | "Node",
24 | "iOS",
25 | "macOS",
26 | "WASM",
27 | "Linux"
28 | ]
29 | },
30 | "LanguageSDK": {
31 | "data": [
32 | "typescript",
33 | "javascript",
34 | "Rust",
35 | "Swift",
36 | "Python"
37 | ]
38 | },
39 | "ClientBundleSize": {
40 | "data": "~900 kB"
41 | }
42 | },
43 | "Networking": {
44 | "Protocol": {
45 | "data": [
46 | "WebSockets",
47 | "HTTP"
48 | ]
49 | },
50 | "Topology": {
51 | "data": "P2P"
52 | }
53 | },
54 | "ServerSideData": {
55 | "PersistenceMechanism": {
56 | "data": [
57 | "Custom"
58 | ]
59 | },
60 | "DataModelParadigm": {
61 | "data": "Document"
62 | }
63 | },
64 | "ClientSideData": {
65 | "QueryAPI": {
66 | "data": [
67 | "Async"
68 | ]
69 | },
70 | "LocalRefreshLatency": {
71 | "data": "~1ms"
72 | },
73 | "PersistenceMechanism": {
74 | "data": [
75 | "IndexedDB",
76 | "Custom"
77 | ]
78 | },
79 | "DataModel": {
80 | "data": "Document"
81 | },
82 | "OfflineReads": {
83 | "data": "Full Support"
84 | },
85 | "OfflineWrites": {
86 | "data": "Local conflict resolution"
87 | },
88 | "DataSize": {
89 | "data": "Up to 5-10 MB per document"
90 | }
91 | },
92 | "SynchronizationStrategy": {
93 | "FullOrPartialReplication": {
94 | "data": [
95 | "Full Replication"
96 | ]
97 | },
98 | "ConflictHandling": {
99 | "data": "Automatic via CRDT"
100 | },
101 | "WhereResolutionOccurs": {
102 | "data": "Client"
103 | },
104 | "WhatGetsSynced": {
105 | "data": {
106 | "ClientToServer": "Ops",
107 | "ServerToClient": "Ops",
108 | "ClientToClient": "Ops"
109 | }
110 | },
111 | "Authority": {
112 | "data": "Decentralized"
113 | }
114 | },
115 | "UIRelated": {
116 | "RichTextEditing": {
117 | "data": "Yes"
118 | },
119 | "Components": {
120 | "data": [
121 | "ProseMirror",
122 | "CodeMirror"
123 | ]
124 | }
125 | },
126 | "DevelopmentWorkflowsDX": {
127 | "DebuggingTools": {
128 | "data": [
129 | "Data Inspector"
130 | ],
131 | "comment": "https://loro.dev/docs/advanced/inspector"
132 | },
133 | "TypeSupport": {
134 | "data": "TypeScript"
135 | }
136 | },
137 | "__generated": {
138 | "lastUpdated": "2025-04-30T09:20:37.000Z"
139 | }
140 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/loro/details.md:
--------------------------------------------------------------------------------
1 | Loro is a [CRDTs(Conflict-free Replicated Data Types)](https://crdt.tech/) library that makes building [local-first](https://www.inkandswitch.com/essay/local-first/) and collaborative apps easier. You can now use it in [Rust](https://crates.io/crates/loro), [JS](https://www.npmjs.com/package/loro-crdt) (via WASM), [Swift](https://swiftpackageindex.com/loro-dev/loro-swift) and [Python](https://pypi.org/project/loro/).
2 |
3 | ## Features
4 |
5 | **Features Provided by CRDTs**
6 |
7 | - P2P Synchronization
8 | - Automatic Merging
9 | - Local Availability
10 | - Scalability
11 | - Delta Updates
12 |
13 | **Supported CRDT Algorithms**
14 |
15 | - 📝 Text Editing with [Fugue](https://arxiv.org/abs/2305.00583)
16 | - 📙 [Rich Text CRDT](https://loro.dev/blog/loro-richtext)
17 | - 🌲 [Moveable Tree](https://loro.dev/docs/tutorial/tree)
18 | - 🚗 [Moveable List](https://loro.dev/docs/tutorial/list)
19 | - 🗺️ [Last-Write-Wins Map](https://loro.dev/docs/tutorial/map)
20 |
21 | **Advanced Features in Loro**
22 |
23 | - 🚀 [Fast Document Loading](https://loro.dev/blog/v1.0)
24 | - ⏱️ Fast [Time Travel](https://loro.dev/docs/tutorial/time_travel) Through History
25 | - 🏛️ [Version Control with Real-Time Collaboration](https://loro.dev/blog/v1.0#version-control)
26 | - 📦 [Shallow Snapshot](https://loro.dev/docs/advanced/shallow_snapshot) that Works like Git Shallow Clone
27 |
28 | ## Example
29 |
30 | ```ts
31 | import { expect, test } from "vitest";
32 | import { LoroDoc, LoroList } from "loro-crdt";
33 |
34 | test("sync example", () => {
35 | // Sync two docs with two rounds of exchanges
36 |
37 | // Initialize document A
38 | const docA = new LoroDoc();
39 | const listA: LoroList = docA.getList("list");
40 | listA.insert(0, "A");
41 | listA.insert(1, "B");
42 | listA.insert(2, "C");
43 |
44 | // Export all updates from docA
45 | const bytes: Uint8Array = docA.export({ mode: "update" });
46 |
47 | // Simulate sending `bytes` across the network to another peer, B
48 |
49 | const docB = new LoroDoc();
50 | // Peer B imports the updates from A
51 | docB.import(bytes);
52 |
53 | // B's state matches A's state
54 | expect(docB.toJSON()).toStrictEqual({
55 | list: ["A", "B", "C"],
56 | });
57 |
58 | // Get the current version of docB
59 | const version = docB.oplogVersion();
60 |
61 | // Simulate editing at B: delete item 'B'
62 | const listB: LoroList = docB.getList("list");
63 | listB.delete(1, 1);
64 |
65 | // Export the updates from B since the last sync point
66 | const bytesB: Uint8Array = docB.export({ mode: "update", from: version });
67 |
68 | // Simulate sending `bytesB` back across the network to A
69 |
70 | // A imports the updates from B
71 | docA.import(bytesB);
72 |
73 | // A has the same state as B
74 | expect(docA.toJSON()).toStrictEqual({
75 | list: ["A", "C"],
76 | });
77 | });
78 | ```
79 |
80 | ## DevTools
81 |
82 | ### Loro Inspector
83 |
84 | You can use the [Loro Inspector](https://inspector.loro.dev) to inspect the state and history of a Loro document.
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/loro/logo.dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
75 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/loro/logo.light.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
75 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/mod.ts:
--------------------------------------------------------------------------------
1 | import { LandscapeSchema } from '@localfirstfm/landscape-schema'
2 | import { Schema } from 'effect'
3 |
4 | import nextgraphJson from './nextgraph/data.json' with { type: 'json' }
5 | import yjsJson from './yjs/data.json' with { type: 'json' }
6 | import automergeJson from './automerge/data.json' with { type: 'json' }
7 | import electricsqlJson from './electricsql/data.json' with { type: 'json' }
8 | import jazzJson from './jazz/data.json' with { type: 'json' }
9 | import zeroJson from './zero/data.json' with { type: 'json' }
10 | import liveblocks_yjsJson from './liveblocks-yjs/data.json' with { type: 'json' }
11 | import liveblocks_storageJson from './liveblocks-storage/data.json' with { type: 'json' }
12 | import livestoreJson from './livestore/data.json' with { type: 'json' }
13 | import dxosJson from './dxos/data.json' with { type: 'json' }
14 | import basicJson from './basic/data.json' with { type: 'json' }
15 | import convexJson from './convex/data.json' with { type: 'json' }
16 | import dittoJson from './ditto/data.json' with { type: 'json' }
17 | import powersyncJson from './powersync/data.json' with { type: 'json' }
18 | import triplitJson from './triplit/data.json' with { type: 'json' }
19 | import tinybaseJson from './tinybase/data.json' with { type: 'json' }
20 | import y_sweetJson from './y-sweet/data.json' with { type: 'json' }
21 | import loroJson from './loro/data.json' with { type: 'json' }
22 | import instantJson from './instant/data.json' with { type: 'json' }
23 |
24 | import nextgraphLogoLight from './nextgraph/logo.light.svg'
25 | import nextgraphLogoDark from './nextgraph/logo.dark.svg'
26 | import yjsLogoLight from './yjs/logo.light.svg'
27 | import yjsLogoDark from './yjs/logo.dark.svg'
28 | import automergeLogoLight from './automerge/logo.light.png'
29 | import automergeLogoDark from './automerge/logo.dark.png'
30 | import electricsqlLogoLight from './electricsql/logo.light.svg'
31 | import electricsqlLogoDark from './electricsql/logo.dark.svg'
32 | import jazzLogoLight from './jazz/logo.light.svg'
33 | import jazzLogoDark from './jazz/logo.dark.svg'
34 | import zeroLogoLight from './zero/logo.light.svg'
35 | import zeroLogoDark from './zero/logo.dark.svg'
36 | import liveblocks_yjsLogoLight from './liveblocks-yjs/logo.light.png'
37 | import liveblocks_yjsLogoDark from './liveblocks-yjs/logo.dark.png'
38 | import liveblocks_storageLogoLight from './liveblocks-storage/logo.light.png'
39 | import liveblocks_storageLogoDark from './liveblocks-storage/logo.dark.png'
40 | import livestoreLogoLight from './livestore/logo.light.svg'
41 | import livestoreLogoDark from './livestore/logo.dark.svg'
42 | import dxosLogoLight from './dxos/logo.light.svg'
43 | import dxosLogoDark from './dxos/logo.dark.svg'
44 | import basicLogoLight from './basic/logo.light.svg'
45 | import basicLogoDark from './basic/logo.dark.svg'
46 | import convexLogoLight from './convex/logo.light.svg'
47 | import convexLogoDark from './convex/logo.dark.svg'
48 | import dittoLogoLight from './ditto/logo.light.svg'
49 | import dittoLogoDark from './ditto/logo.dark.svg'
50 | import powersyncLogoLight from './powersync/logo.light.svg'
51 | import powersyncLogoDark from './powersync/logo.dark.svg'
52 | import triplitLogoLight from './triplit/logo.light.svg'
53 | import triplitLogoDark from './triplit/logo.dark.svg'
54 | import tinybaseLogoLight from './tinybase/logo.light.svg'
55 | import tinybaseLogoDark from './tinybase/logo.dark.svg'
56 | import y_sweetLogoLight from './y-sweet/logo.light.png'
57 | import y_sweetLogoDark from './y-sweet/logo.dark.png'
58 | import loroLogoLight from './loro/logo.light.svg'
59 | import loroLogoDark from './loro/logo.dark.svg'
60 | import instantLogoLight from './instant/logo.light.svg'
61 | import instantLogoDark from './instant/logo.dark.svg'
62 |
63 | const nextgraph = Schema.decodeUnknownSync(LandscapeSchema)(nextgraphJson)
64 | const yjs = Schema.decodeUnknownSync(LandscapeSchema)(yjsJson)
65 | const automerge = Schema.decodeUnknownSync(LandscapeSchema)(automergeJson)
66 | const electricsql = Schema.decodeUnknownSync(LandscapeSchema)(electricsqlJson)
67 | const jazz = Schema.decodeUnknownSync(LandscapeSchema)(jazzJson)
68 | const zero = Schema.decodeUnknownSync(LandscapeSchema)(zeroJson)
69 | const liveblocks_yjs = Schema.decodeUnknownSync(LandscapeSchema)(liveblocks_yjsJson)
70 | const liveblocks_storage = Schema.decodeUnknownSync(LandscapeSchema)(liveblocks_storageJson)
71 | const livestore = Schema.decodeUnknownSync(LandscapeSchema)(livestoreJson)
72 | const dxos = Schema.decodeUnknownSync(LandscapeSchema)(dxosJson)
73 | const basic = Schema.decodeUnknownSync(LandscapeSchema)(basicJson)
74 | const convex = Schema.decodeUnknownSync(LandscapeSchema)(convexJson)
75 | const ditto = Schema.decodeUnknownSync(LandscapeSchema)(dittoJson)
76 | const powersync = Schema.decodeUnknownSync(LandscapeSchema)(powersyncJson)
77 | const triplit = Schema.decodeUnknownSync(LandscapeSchema)(triplitJson)
78 | const tinybase = Schema.decodeUnknownSync(LandscapeSchema)(tinybaseJson)
79 | const y_sweet = Schema.decodeUnknownSync(LandscapeSchema)(y_sweetJson)
80 | const loro = Schema.decodeUnknownSync(LandscapeSchema)(loroJson)
81 | const instant = Schema.decodeUnknownSync(LandscapeSchema)(instantJson)
82 |
83 | export const data = [
84 | { ...nextgraph, Logo: { Light: nextgraphLogoLight, Dark: nextgraphLogoDark } },
85 | { ...yjs, Logo: { Light: yjsLogoLight, Dark: yjsLogoDark } },
86 | { ...automerge, Logo: { Light: automergeLogoLight, Dark: automergeLogoDark } },
87 | { ...electricsql, Logo: { Light: electricsqlLogoLight, Dark: electricsqlLogoDark } },
88 | { ...jazz, Logo: { Light: jazzLogoLight, Dark: jazzLogoDark } },
89 | { ...zero, Logo: { Light: zeroLogoLight, Dark: zeroLogoDark } },
90 | { ...liveblocks_yjs, Logo: { Light: liveblocks_yjsLogoLight, Dark: liveblocks_yjsLogoDark } },
91 | { ...liveblocks_storage, Logo: { Light: liveblocks_storageLogoLight, Dark: liveblocks_storageLogoDark } },
92 | { ...livestore, Logo: { Light: livestoreLogoLight, Dark: livestoreLogoDark } },
93 | { ...dxos, Logo: { Light: dxosLogoLight, Dark: dxosLogoDark } },
94 | { ...basic, Logo: { Light: basicLogoLight, Dark: basicLogoDark } },
95 | { ...convex, Logo: { Light: convexLogoLight, Dark: convexLogoDark } },
96 | { ...ditto, Logo: { Light: dittoLogoLight, Dark: dittoLogoDark } },
97 | { ...powersync, Logo: { Light: powersyncLogoLight, Dark: powersyncLogoDark } },
98 | { ...triplit, Logo: { Light: triplitLogoLight, Dark: triplitLogoDark } },
99 | { ...tinybase, Logo: { Light: tinybaseLogoLight, Dark: tinybaseLogoDark } },
100 | { ...y_sweet, Logo: { Light: y_sweetLogoLight, Dark: y_sweetLogoDark } },
101 | { ...loro, Logo: { Light: loroLogoLight, Dark: loroLogoDark } },
102 | { ...instant, Logo: { Light: instantLogoLight, Dark: instantLogoDark } }
103 | ]
104 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/nextgraph/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "nextgraph",
4 | "Name": "NextGraph",
5 | "Description": "Decentralized and local-first web 3.0 ecosystem (everything apps and framework/SDK)",
6 | "MaturityLevel": "Alpha",
7 | "Website": "https://nextgraph.org",
8 | "GitHub": "https://git.nextgraph.org/NextGraph/nextgraph-rs",
9 | "UniquenessNote": "convergence of Linked Data, P2P, and local-first",
10 | "InitialReleaseDate": "2024-09-02T00:00:00.000Z",
11 | "Deployment": [
12 | "Self-hosted",
13 | "Hosted"
14 | ],
15 | "License": "MIT",
16 | "AppTarget": {
17 | "Platform": {
18 | "data": [
19 | "Browser",
20 | "Node",
21 | "iOS",
22 | "Android",
23 | "macOS",
24 | "WASM",
25 | "Linux"
26 | ]
27 | },
28 | "LanguageSDK": {
29 | "data": [
30 | "TypeScript",
31 | "JavaScript",
32 | "Rust",
33 | "Python"
34 | ]
35 | },
36 | "FrameworkIntegrations": {
37 | "data": [
38 | "React",
39 | "Svelte"
40 | ]
41 | },
42 | "ClientBundleSize": {
43 | "data": "4 kB compressed",
44 | "comment": "not including Automerge or Yjs dependencies"
45 | }
46 | },
47 | "Networking": {
48 | "Protocol": {
49 | "data": [
50 | "WebSockets"
51 | ]
52 | },
53 | "Topology": {
54 | "data": "P2P via Relay Servers"
55 | }
56 | },
57 | "ServerSideData": {
58 | "PersistenceMechanism": {
59 | "data": [
60 | "Custom"
61 | ]
62 | },
63 | "DataModelParadigm": {
64 | "data": "Document",
65 | "comment": "Document-oriented and graph (RDF)"
66 | }
67 | },
68 | "ClientSideData": {
69 | "QueryAPI": {
70 | "data": [
71 | "Async",
72 | "Sync",
73 | "Signals-based Reactivity"
74 | ]
75 | },
76 | "PersistenceMechanism": {
77 | "data": [
78 | "Yjs",
79 | "OPFS",
80 | "RocksDB"
81 | ]
82 | },
83 | "PersistenceFeatures": {
84 | "data": "Indexes",
85 | "comment": "also with Full-text search and Transactions"
86 | },
87 | "DataModel": {
88 | "data": "Document",
89 | "comment": "Document-oriented and graph (RDF)"
90 | },
91 | "SchemaManagement": {
92 | "data": [
93 | "Schema definition",
94 | "Schema validation on write"
95 | ]
96 | },
97 | "OfflineReads": {
98 | "data": "Full Support"
99 | },
100 | "OptimisticUpdates": {
101 | "data": "Yes"
102 | },
103 | "OfflineWrites": {
104 | "data": "Local conflict resolution"
105 | }
106 | },
107 | "SynchronizationStrategy": {
108 | "FullOrPartialReplication": {
109 | "data": [
110 | "Full Replication",
111 | "Partial Replication"
112 | ]
113 | },
114 | "ConflictHandling": {
115 | "data": "Automatic via CRDT",
116 | "comment": "supports Automerge, Yjs and RDF"
117 | },
118 | "WhereResolutionOccurs": {
119 | "data": "Client"
120 | },
121 | "WhatGetsSynced": {
122 | "data": {
123 | "ClientToClient": "Commits"
124 | }
125 | },
126 | "Authority": {
127 | "data": "Decentralized"
128 | }
129 | },
130 | "AuthIdentity": {
131 | "Encryption": {
132 | "data": "Yes",
133 | "comment": "end-to-end encryption + encryption at rest"
134 | },
135 | "AuthenticationMethod": {
136 | "data": [
137 | "Built-in",
138 | "Public keys"
139 | ]
140 | },
141 | "AuthorizationPermissions": {
142 | "data": "Cryptographic Capabilities"
143 | }
144 | },
145 | "UIRelated": {
146 | "RichTextEditing": {
147 | "data": "Yes"
148 | },
149 | "Components": {
150 | "data": [
151 | "reusable Editors",
152 | "reusable Viewers",
153 | "Auth with Wallet",
154 | "Malleable software"
155 | ]
156 | }
157 | },
158 | "DevelopmentWorkflowsDX": {
159 | "CLI": {
160 | "data": "Command line interface tools for developers and end-users"
161 | },
162 | "TypeSupport": {
163 | "data": "type support via LDO"
164 | }
165 | },
166 | "__generated": {
167 | "lastUpdated": "2025-04-29T14:47:05.000Z"
168 | }
169 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/nextgraph/details.md:
--------------------------------------------------------------------------------
1 |
2 | > Build local-first, collaborative and decentralized apps, with CRDTs, and end-to-end encryption.
3 |
4 | ## Framework and Platform
5 |
6 | NextGraph brings about the convergence of P2P and Semantic Web technologies, towards a decentralized, secure and privacy-preserving cloud, based on CRDTs.
7 |
8 | This open source ecosystem provides solutions for end-users (a platform) and software developers (a framework), wishing to use or create decentralized apps featuring: live collaboration on rich-text documents, peer-to-peer communication with end-to-end encryption, offline-first, local-first, portable and interoperable data, total ownership of data and software, security and privacy. Centered on repositories containing semantic data (RDF), rich text, and structured data formats like JSON, synced between peers belonging to permissioned groups of users, it offers strong eventual consistency, thanks to the use of CRDTs. Documents can be linked together, signed, shared securely, queried using the SPARQL language and organized into sites and containers.
9 |
10 | More info [on our website](https://nextgraph.org)
11 |
12 |
13 | ## Features
14 |
15 | - **Linked Data**: link documents and data together with RDF and DID URIs, then query all your data with SPARQL. Comaptible with Solid.
16 | - **Social Network**: NextGraph offers decentralized social network features (DM, timeline, share). Compatible with ActivityPub
17 | - **Portable & Interoperable**: Your data always remains under your control. It isn't tied to a specific app, format, domain name or server.
18 | - **Malleable Software**: switch viewers and editors and reuse them at will. Enjoy ready-made components that can be reused.
19 | - **Local-first**: Your data is stored locally, ensuring availability and privacy.
20 | - **End-to-end encrypted**: All documents are encrypted in the client, and the servers (brokers) cannot see their content.
21 | - **Cross-platform**: Works on all major platforms.
22 | - **Open-source**: The code is available for anyone to use and contribute to, in permissive licensing.
23 |
24 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/nextgraph/logo.dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
49 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/nextgraph/logo.light.svg:
--------------------------------------------------------------------------------
1 |
2 |
49 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/powersync/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "powersync",
4 | "Name": "PowerSync",
5 | "Description": "Syncs between SQLite on the client-side and Postgres, MongoDB or MySQL on the server-side.",
6 | "MaturityLevel": "Production-Ready",
7 | "Website": "https://www.powersync.com",
8 | "GitHub": "https://github.com/powersync-ja",
9 | "UniquenessNote": "Sync Rules allow flexible dynamic partial syncing. Write path is fully customizable through your own backend.",
10 | "InitialReleaseDate": "2023-11-30T00:00:00.000Z",
11 | "Deployment": [
12 | "Self-hosted",
13 | "Hosted"
14 | ],
15 | "License": "FSL-Apache 2.0 (Service) & Apache 2.0 (SDKs)",
16 | "AppTarget": {
17 | "Platform": {
18 | "data": [
19 | "Browser",
20 | "iOS",
21 | "Android",
22 | "macOS",
23 | "WASM",
24 | "Linux"
25 | ]
26 | },
27 | "LanguageSDK": {
28 | "data": [
29 | "TypeScript",
30 | "Swift",
31 | "Kotlin",
32 | "Rust",
33 | "Dart",
34 | ".NET"
35 | ]
36 | },
37 | "FrameworkIntegrations": {
38 | "data": [
39 | "React",
40 | "React Native",
41 | "Vue",
42 | "Svelte",
43 | "SolidJS",
44 | "Flutter"
45 | ]
46 | }
47 | },
48 | "Networking": {
49 | "Protocol": {
50 | "data": [
51 | "WebSockets",
52 | "HTTP"
53 | ]
54 | },
55 | "Topology": {
56 | "data": "Client-Server"
57 | }
58 | },
59 | "ServerSideData": {
60 | "PersistenceMechanism": {
61 | "data": [
62 | "Postgres",
63 | "MongoDB",
64 | "MySQL"
65 | ],
66 | "comment": "Backend source databases: Postgres, MongoDB, MySQL. Storage of sync bucket data: MongoDB, Postgres"
67 | },
68 | "DataSize": {
69 | "data": "No theoretical limit"
70 | },
71 | "DataModelParadigm": {
72 | "data": "Relational"
73 | },
74 | "ExistingDatabaseSupport": {
75 | "data": "Works with backend source databases: Postgres, MongoDB, MySQL"
76 | }
77 | },
78 | "ClientSideData": {
79 | "QueryAPI": {
80 | "data": [
81 | "Async",
82 | "Reactive queries"
83 | ]
84 | },
85 | "PersistenceMechanism": {
86 | "data": [
87 | "SQLite",
88 | "IndexedDB",
89 | "OPFS"
90 | ]
91 | },
92 | "PersistenceFeatures": {
93 | "data": "FTS, Indexes, Transactions"
94 | },
95 | "DataModel": {
96 | "data": "Relational",
97 | "comment": "Schemaless JSON synced and stored in SQLite and exposed as views to allow for relational queries based on client-side schema."
98 | },
99 | "SchemaManagement": {
100 | "data": [
101 | "Schema definition"
102 | ],
103 | "comment": "Client-side schema definition. Schema is used to expose views in SQLite based on schemaless synced data, generally avoiding the need for schema migrations."
104 | },
105 | "OfflineReads": {
106 | "data": "Full Support",
107 | "comment": "Dynamic query support."
108 | },
109 | "OptimisticUpdates": {
110 | "data": "Yes"
111 | },
112 | "OfflineWrites": {
113 | "data": "Yes"
114 | }
115 | },
116 | "SynchronizationStrategy": {
117 | "FullOrPartialReplication": {
118 | "data": [
119 | "Full Replication",
120 | "Partial Replication"
121 | ],
122 | "comment": "Partial or full replica defined using [Sync Rules](https://docs.powersync.com/usage/sync-rules). Sync Rules can make use of authenticated JWT parameters or client parameters."
123 | },
124 | "ConflictHandling": {
125 | "data": "Custom conflict resolution supported",
126 | "comment": "Developer defines an upload function which writes local mutations to backend database. Simplest implementation of this results in LWW. Can be customized by developer, including using CRDT data structures like [Yjs](https://www.powersync.com/blog/postgres-and-yjs-crdt-collaborative-text-editing-using-powersync), e.g."
127 | },
128 | "WhereResolutionOccurs": {
129 | "data": "Server"
130 | },
131 | "WhatGetsSynced": {
132 | "data": {
133 | "ClientToServer": "mutations",
134 | "ServerToClient": "ops"
135 | }
136 | },
137 | "Authority": {
138 | "data": "Centralized"
139 | }
140 | },
141 | "AuthIdentity": {
142 | "Encryption": {
143 | "data": "Yes",
144 | "comment": "transport-level and storage-level locally on the device using SQLCipher; E2EE can also be accomplished by syncing encrypted data and decrypting on client"
145 | },
146 | "AuthenticationMethod": {
147 | "data": [
148 | "JWT Tokens"
149 | ]
150 | },
151 | "AuthorizationPermissions": {
152 | "data": "Custom",
153 | "comment": "Reads: Access to data is controlled by authenticated parameters in JWT used in Sync Rules\nWrites: Access controlled using developer's own backend (through which writes go to)"
154 | }
155 | },
156 | "DevelopmentWorkflowsDX": {
157 | "DebuggingTools": {
158 | "data": [
159 | "Dashboard",
160 | "Data Inspector"
161 | ],
162 | "comment": "[Dashboard](https://docs.powersync.com/usage/tools/powersync-dashboard), [Diagnostic tool to inspect synced data](https://github.com/powersync-ja/powersync-js/tree/main/tools/diagnostics-app)"
163 | },
164 | "CLI": {
165 | "data": "CLI for managing cloud instances of PowerSync Service"
166 | }
167 | },
168 | "__generated": {
169 | "lastUpdated": "2025-04-26T01:09:17.000Z"
170 | }
171 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/powersync/details.md:
--------------------------------------------------------------------------------
1 |
2 | ## PowerSync Introduction
3 |
4 | [PowerSync](https://powersync.com) keeps backend databases in sync with on-device SQLite databases embedded in a client SDK. It enables instantly-responsive local-first & offline-first apps that remain available even when network connectivity is poor or non-existent.
5 |
6 | PowerSync is designed to be backend database agnostic, with support for Postgres, MongoDB, and MySQL as of April 2025.
7 |
8 | PowerSync is also designed to be client-side framework agnostic, and offers a wide range of client SDKs, including Flutter, React Native & Expo, web (JavaScript), Node.js, Kotlin Multiplatform, Swift and .NET.
9 |
10 | ## The Story
11 |
12 | PowerSync is a product of JourneyApps, a software company headquartered in Denver, Colorado. The original product of JourneyApps was the JourneyApps Platform, a full-stack app platform focused on industrial companies, with a sync engine as a subcomponent (originally also named PowerSync).
13 |
14 | The PowerSync engine in the JourneyApps Platform has been used for years in production by a range of Fortune 500 customers in industries such as manufacturing, mining, energy and others. These customers typically have a need to sync a high volume of relational data to users in harsh field conditions, such as remote locations where users are frequently offline. Usage in these kinds of demanding environments has led JourneyApps to battle-harden the PowerSync engine over several years, and these customers continue to rely on the PowerSync engine for critical daily business operations.
15 |
16 | In 2022, JourneyApps decided to spin off the PowerSync engine into the standalone PowerSync product (consisting of a sync service and SDK) allowing the creation of offline-first apps that sync data from backend databases to local SQLite on-device databases.
17 |
18 | ## Resources
19 |
20 | - [Website](https://powersync.com)
21 | - [Documentation](https://docs.powersync.com/intro/powersync-overview)
22 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/powersync/logo.dark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/powersync/logo.light.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/tinybase/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "tinybase",
4 | "Name": "TinyBase",
5 | "Description": "A reactive data store & sync engine.",
6 | "MaturityLevel": "Mature",
7 | "Logo": {
8 | "Light": "https://tinybase.org/favicon.svg",
9 | "Dark": "https://tinybase.org/favicon.svg"
10 | },
11 | "Website": "https://tinybase.org",
12 | "GitHub": "https://github.com/tinyplex/tinybase",
13 | "InitialReleaseDate": "2022-01-17T00:00:00.000Z",
14 | "NotableAdopters": [
15 | {
16 | "Name": "Athena Crisis",
17 | "URL": "https://athenacrisis.com"
18 | },
19 | {
20 | "Name": "TinyHub",
21 | "URL": "https://tinyhub.org"
22 | }
23 | ],
24 | "Deployment": [
25 | "Self-hosted"
26 | ],
27 | "License": "MIT",
28 | "AppTarget": {
29 | "Platform": {
30 | "data": [
31 | "Browser",
32 | "Node",
33 | "React Native",
34 | "Deno",
35 | "Cloudflare Workers"
36 | ]
37 | },
38 | "LanguageSDK": {
39 | "data": [
40 | "TypeScript",
41 | "JavaScript"
42 | ]
43 | },
44 | "FrameworkIntegrations": {
45 | "data": [
46 | "React",
47 | "React Native"
48 | ]
49 | },
50 | "ClientBundleSize": {
51 | "data": "5.3kB - 11.5kB",
52 | "comment": "The clue is in the name!"
53 | }
54 | },
55 | "Networking": {
56 | "Protocol": {
57 | "data": [
58 | "WebSockets",
59 | "HTTP"
60 | ]
61 | },
62 | "Topology": {
63 | "data": "P2P via Relay Servers",
64 | "comment": "Client-server is also made possible by an API that lets the server participate as a peer."
65 | }
66 | },
67 | "ServerSideData": {
68 | "PersistenceMechanism": {
69 | "data": [
70 | "Cloudflare Durable Object Storage",
71 | "SQLite",
72 | "Postgres",
73 | "Custom"
74 | ]
75 | },
76 | "DataSize": {
77 | "data": "Up to 5-10 MB per store",
78 | "comment": "The server can also use a database like SQLite or Postgres for larger data."
79 | },
80 | "DataModelParadigm": {
81 | "data": "Relational",
82 | "comment": "Both relational and key-value data can be stored and synced."
83 | }
84 | },
85 | "ClientSideData": {
86 | "QueryAPI": {
87 | "data": [
88 | "Sync",
89 | "Reactive queries"
90 | ]
91 | },
92 | "LocalRefreshLatency": {
93 | "data": "~1ms"
94 | },
95 | "PersistenceMechanism": {
96 | "data": [
97 | "SQLite",
98 | "IndexedDB",
99 | "PGLite via OPFS",
100 | "SQLite",
101 | "Yjs",
102 | "Custom"
103 | ]
104 | },
105 | "PersistenceFeatures": {
106 | "data": "Indexes"
107 | },
108 | "DataModel": {
109 | "data": "Document"
110 | },
111 | "OfflineReads": {
112 | "data": "Full Support"
113 | },
114 | "OfflineWrites": {
115 | "data": "Local conflict resolution"
116 | },
117 | "DataSize": {
118 | "data": "Up to 5-10 MB per store"
119 | }
120 | },
121 | "SynchronizationStrategy": {
122 | "FullOrPartialReplication": {
123 | "data": [
124 | "Full Replication"
125 | ]
126 | },
127 | "ConflictHandling": {
128 | "data": "Automatic via CRDT"
129 | },
130 | "WhereResolutionOccurs": {
131 | "data": "Client",
132 | "comment": "Server can also resolve conflicts."
133 | },
134 | "WhatGetsSynced": {
135 | "data": {
136 | "ClientToServer": "Cell- or value-level changes",
137 | "ServerToClient": "Cell- or value-level changes",
138 | "ClientToClient": "Cell- or value-level changes"
139 | }
140 | }
141 | },
142 | "UIRelated": {
143 | "Components": {
144 | "data": [
145 | "React",
146 | "ReactDom"
147 | ]
148 | }
149 | },
150 | "DevelopmentWorkflowsDX": {
151 | "DebuggingTools": {
152 | "data": [
153 | "Data Inspector"
154 | ]
155 | },
156 | "TypeSupport": {
157 | "data": "TypeScript, inferred from Schemas"
158 | }
159 | },
160 | "__generated": {
161 | "lastUpdated": "2025-04-18T20:59:16.000Z"
162 | }
163 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/tinybase/details.md:
--------------------------------------------------------------------------------
1 | # TinyBase
2 |
3 | A reactive& sync.
4 |
5 | Get started
6 |
7 | Try the demos
8 |
9 | Read the docs
10 |
11 | ---
12 |
13 | ## It's _Reactive_
14 |
15 | TinyBase lets you listen to changes made to any part of your data. This means
16 | your app will be fast, since you only spend rendering cycles on things that
17 | change. The optional bindings to React and pre-built components let you easily
18 | build fully reactive UIs on top of TinyBase. You even get a built-in undo
19 | stack, and developer tools!
20 |
21 | ## It's _Database-Like_
22 |
23 | Consumer app? Enterprise app? Or even a game? Model key-value data and tabular
24 | data with optional typed schematization, whatever its data structures. There
25 | are built-in indexing, metric aggregation, and tabular relationships APIs -
26 | and a powerful query engine to select, join, filter, and group data
27 | (reactively!) without SQL.
28 |
29 | ## It _Synchronizes_
30 |
31 | TinyBase has native CRDT support, meaning that you can deterministically
32 | synchronize and merge data across multiple sources, clients, and servers. And
33 | although TinyBase is an in-memory data store, you can easily persist your data
34 | to file, browser storage /persister-browser, IndexedDB, SQLite or PostgreSQL
35 | databases, and more.
36 |
37 | ## It's Built For A _Local-First_ World
38 |
39 | TinyBase works anywhere that JavaScript does, but it's especially great for
40 | local-first apps: where data is stored locally on the user's device and that
41 | can be run offline. It's tiny by name, tiny by nature: just 5.3kB - 11.5kB and
42 | with no dependencies - yet 100% tested, fully documented, and of course, open
43 | source!
44 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/tinybase/logo.dark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/tinybase/logo.light.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/triplit/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "triplit",
4 | "Name": "Triplit",
5 | "Description": "The Typescript-first database that handles caching and syncing for your app automatically",
6 | "MaturityLevel": "Production-Ready",
7 | "Website": "https://triplit.dev",
8 | "InitialReleaseDate": "2023-07-27T00:00:00.000Z",
9 | "Deployment": [
10 | "Self-hosted",
11 | "Hosted"
12 | ],
13 | "License": "GPL3",
14 | "AppTarget": {
15 | "Platform": {
16 | "data": [
17 | "Browser",
18 | "Node",
19 | "Deno",
20 | "Bun",
21 | "Cloudflare Workers",
22 | "Hermes"
23 | ]
24 | },
25 | "LanguageSDK": {
26 | "data": [
27 | "Typescript"
28 | ]
29 | },
30 | "FrameworkIntegrations": {
31 | "data": [
32 | "React",
33 | "Vue",
34 | "Svelte",
35 | "Angular",
36 | "React Native"
37 | ]
38 | },
39 | "ClientBundleSize": {
40 | "data": "~70kB (gzip) "
41 | }
42 | },
43 | "Networking": {
44 | "Protocol": {
45 | "data": [
46 | "WebSockets",
47 | "HTTP"
48 | ]
49 | },
50 | "Topology": {
51 | "data": "Client-Server"
52 | }
53 | },
54 | "ServerSideData": {
55 | "PersistenceMechanism": {
56 | "data": [
57 | "SQLite",
58 | "Cloudflare Durable Object Storage",
59 | "Custom"
60 | ],
61 | "comment": "Pluggable with simple Key-Value interface"
62 | },
63 | "DataModelParadigm": {
64 | "data": "Relational"
65 | },
66 | "SchemaManagement": {
67 | "data": [
68 | "Derived types",
69 | "Schema migrations",
70 | "Validate schemas on write"
71 | ]
72 | }
73 | },
74 | "ClientSideData": {
75 | "QueryAPI": {
76 | "data": [
77 | "Async",
78 | "Reactive queries"
79 | ]
80 | },
81 | "LocalRefreshLatency": {
82 | "data": "~1ms"
83 | },
84 | "PersistenceMechanism": {
85 | "data": [
86 | "IndexedDB",
87 | "SQLite",
88 | "Custom"
89 | ],
90 | "comment": "Adapter for k-v stores."
91 | },
92 | "PersistenceFeatures": {
93 | "data": "Transactions"
94 | },
95 | "DataModel": {
96 | "data": "Relational"
97 | },
98 | "SchemaManagement": {
99 | "data": [
100 | "Derived types"
101 | ]
102 | },
103 | "OfflineReads": {
104 | "data": "Query Cache",
105 | "comment": "Subscribed queries have full db support including novel queries"
106 | },
107 | "OptimisticUpdates": {
108 | "data": "Yes"
109 | },
110 | "OfflineWrites": {
111 | "data": "Cached offline writes"
112 | },
113 | "DataSize": {
114 | "data": "limited by device capabilities"
115 | }
116 | },
117 | "SynchronizationStrategy": {
118 | "FullOrPartialReplication": {
119 | "data": [
120 | "Partial Replication"
121 | ]
122 | },
123 | "ConflictHandling": {
124 | "data": "LWW at the attribute level"
125 | },
126 | "WhereResolutionOccurs": {
127 | "data": "Server"
128 | },
129 | "WhatGetsSynced": {
130 | "data": {
131 | "ClientToServer": "Minimal deltas",
132 | "ServerToClient": "Normalized query results, depuded across subscriptions then minimal deltas for changes"
133 | }
134 | },
135 | "Authority": {
136 | "data": "Centralized"
137 | }
138 | },
139 | "AuthIdentity": {
140 | "AuthenticationMethod": {
141 | "data": [
142 | "JWT Tokens"
143 | ]
144 | },
145 | "AuthorizationPermissions": {
146 | "data": "Custom mapping from token attributes to query filters"
147 | }
148 | },
149 | "DevelopmentWorkflowsDX": {
150 | "DebuggingTools": {
151 | "data": [
152 | "DevTools",
153 | "Network Inspector",
154 | "Data Inspector",
155 | "Dashboard"
156 | ]
157 | },
158 | "CLI": {
159 | "data": "Yes"
160 | },
161 | "TypeSupport": {
162 | "data": "Yes"
163 | }
164 | },
165 | "__generated": {
166 | "lastUpdated": "2025-04-29T03:07:26.000Z"
167 | }
168 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/triplit/details.md:
--------------------------------------------------------------------------------
1 | # Triplit
2 |
3 | Triplit is the database that's in sync with your front-end.
4 |
5 | ## Get Started with Triplit Cloud or Self-Hosted today
6 |
7 | Website: [https://triplit.dev](https://triplit.dev)
8 | Github: [aspen-cloud/triplit](https://github.com/aspen-cloud/triplit)
9 |
10 | ## Features
11 |
12 | 🔄 Real-time sync with incremental updates and conflict resolution at the property level
13 | 🏠 Local caching powered by a full-fledged client-side database
14 | 💽 Durable server-side storage with an admin dashboard
15 | 😃 Optimistic updates to make every interaction feel fast
16 | 🔗 Relational querying for complex data models
17 | 🛫 Offline-mode with automatic reconnection and consistency guarantees
18 | 🔙 Rollback and retry management on failed updates
19 | 🗂️ Schemas for data safety and Typescript autocompletion
20 | 🔐 Authorization with row level granularity
21 | 🤝 Collaboration/Multiplayer powered by CRDTs
22 | 🏎️ Low latency with minimal network traffic using delta patches
23 | 📝 Simple API for querying and mutating data in both vanilla Javascript and frameworks like React
24 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/triplit/logo.dark.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/triplit/logo.light.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/y-sweet/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "y-sweet",
4 | "Name": "Y-Sweet",
5 | "Website": "https://y-sweet.dev",
6 | "Deployment": [
7 | "Self-hosted",
8 | "Hosted"
9 | ],
10 | "License": "MIT",
11 | "AppTarget": {
12 | "Platform": {
13 | "data": [
14 | "Browser",
15 | "Node",
16 | "iOS",
17 | "Android",
18 | "macOS",
19 | "Linux"
20 | ],
21 | "comment": "Limited only by Yjs support."
22 | },
23 | "LanguageSDK": {
24 | "data": [
25 | "TypeScript",
26 | "Python"
27 | ]
28 | },
29 | "FrameworkIntegrations": {
30 | "data": [
31 | "React"
32 | ]
33 | }
34 | },
35 | "Networking": {
36 | "Protocol": {
37 | "data": [
38 | "WebSockets",
39 | "HTTP"
40 | ]
41 | },
42 | "Topology": {
43 | "data": "Client-Server"
44 | }
45 | },
46 | "ServerSideData": {
47 | "PersistenceMechanism": {
48 | "data": [
49 | "S3-compatible object store"
50 | ]
51 | },
52 | "DataModelParadigm": {
53 | "data": "Document"
54 | },
55 | "ExistingDatabaseSupport": {
56 | "data": "Yes",
57 | "comment": "In the \"Figma architecture\" sense: ground-truth document data only lives on S3, but document metadata exists in your existing DB."
58 | }
59 | },
60 | "ClientSideData": {
61 | "LocalRefreshLatency": {
62 | "data": "<1 ms"
63 | },
64 | "PersistenceMechanism": {
65 | "data": [
66 | "IndexedDB"
67 | ]
68 | },
69 | "DataModel": {
70 | "data": "Document"
71 | },
72 | "SchemaManagement": {
73 | "data": [
74 | "No support"
75 | ]
76 | },
77 | "OfflineReads": {
78 | "data": "Yes"
79 | },
80 | "OptimisticUpdates": {
81 | "data": "Yes"
82 | },
83 | "OfflineWrites": {
84 | "data": "Yes"
85 | }
86 | },
87 | "SynchronizationStrategy": {
88 | "ConflictHandling": {
89 | "data": "Automatic via CRDT",
90 | "comment": "CRDT (YATA)"
91 | },
92 | "WhereResolutionOccurs": {
93 | "data": "Server"
94 | },
95 | "WhatGetsSynced": {
96 | "data": {
97 | "ClientToServer": "mutations"
98 | }
99 | },
100 | "Authority": {
101 | "data": "Centralized"
102 | }
103 | },
104 | "AuthIdentity": {
105 | "Encryption": {
106 | "data": "Yes",
107 | "comment": "Subject to the underlying object store used; most encrypt at rest by default; AES-GCM encryption on the client"
108 | },
109 | "AuthenticationMethod": {
110 | "data": [
111 | "Tokens"
112 | ],
113 | "comment": "Auth delegation from your application server based on temporary tokens."
114 | }
115 | },
116 | "UIRelated": {
117 | "Components": {
118 | "data": [
119 | "y.js plugins",
120 | "Presence"
121 | ],
122 | "comment": "Anything compatible with Yjs (Slate, BlockNote, Quill, Lexical, etc.)"
123 | }
124 | },
125 | "__generated": {
126 | "lastUpdated": "2025-04-25T16:01:03.000Z"
127 | }
128 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/y-sweet/details.md:
--------------------------------------------------------------------------------
1 | ## General
2 |
3 | Y-Sweet is an open-source Yjs server that uses S3(-compatible) object storage for persistence.
4 |
5 | ## Resources
6 |
7 | - [Website](https://y-sweet.dev)
8 | - [Documentation](https://docs.jamsocket.com/y-sweet)
9 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/y-sweet/logo.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/localfirstfm/local-first-landscape/621278c13945f8c197c671acddb588970549d208/landscape-content-snapshot/src/generated/y-sweet/logo.dark.png
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/y-sweet/logo.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/localfirstfm/local-first-landscape/621278c13945f8c197c671acddb588970549d208/landscape-content-snapshot/src/generated/y-sweet/logo.light.png
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/yjs/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "Id": "yjs",
4 | "Name": "Yjs",
5 | "Description": "Shared types to make anything collaborative",
6 | "MaturityLevel": "Mature",
7 | "Website": "https://yjs.dev",
8 | "GitHub": "https://github.com/yjs/yjs",
9 | "GetStarted": "https://learn.yjs.dev",
10 | "UniquenessNote": "Minimal, flexible, fast, easy to integrate, unopinionated",
11 | "InitialReleaseDate": "2015-01-26T23:00:00.000Z",
12 | "NotableAdopters": [
13 | {
14 | "Name": "Evernote",
15 | "URL": "https://evernote.com"
16 | },
17 | {
18 | "Name": "Project Jupyter",
19 | "URL": "https://jupyter.org/"
20 | },
21 | {
22 | "Name": "La Suite",
23 | "URL": "https://lasuite.numerique.gouv.fr/en"
24 | },
25 | {
26 | "Name": "NextCloud",
27 | "URL": "https://nextcloud.com/"
28 | }
29 | ],
30 | "Deployment": [
31 | "Self-hosted",
32 | "Hosted",
33 | "Third-party integrations"
34 | ],
35 | "License": "MIT",
36 | "AppTarget": {
37 | "Platform": {
38 | "data": [
39 | "Browser",
40 | "Node",
41 | "iOS",
42 | "React Native",
43 | "WASM"
44 | ],
45 | "comment": "We have language bindings to many popular programming languages. See y-crdt."
46 | },
47 | "LanguageSDK": {
48 | "data": [
49 | "TypeScript",
50 | "JavaScript",
51 | "Rust",
52 | "C#",
53 | "Swift",
54 | "Python",
55 | "Cffi",
56 | "Kotlin"
57 | ]
58 | },
59 | "FrameworkIntegrations": {
60 | "data": [
61 | "React",
62 | "React Native",
63 | "Vue",
64 | "Svelte",
65 | "Zustand"
66 | ],
67 | "comment": "There are several \"bindings\" that make Yjs work with different web frameworks. This list is probably not up to date."
68 | },
69 | "ClientBundleSize": {
70 | "data": "~20kb",
71 | "comment": "About ~20kb gzipped. Your final bundle might be smaller as Yjs works well with dead-code elimination."
72 | }
73 | },
74 | "Networking": {
75 | "Protocol": {
76 | "data": [
77 | "WebRTC",
78 | "WebSockets",
79 | "Matrix",
80 | "Signal",
81 | "via integrations",
82 | "custom"
83 | ],
84 | "comment": "It is relatively easy sync Yjs through custom communication protocols."
85 | },
86 | "Topology": {
87 | "data": "P2P / Client-server"
88 | }
89 | },
90 | "ServerSideData": {
91 | "PersistenceMechanism": {
92 | "data": [
93 | "Redis",
94 | "Leveldb",
95 | "DB-integrations",
96 | "custom"
97 | ],
98 | "comment": "It is relatively easy to persist Yjs data in your own database."
99 | },
100 | "DataModelParadigm": {
101 | "data": "Document"
102 | },
103 | "ExistingDatabaseSupport": {
104 | "data": "Via integrations and plugins"
105 | }
106 | },
107 | "ClientSideData": {
108 | "QueryAPI": {
109 | "data": [
110 | "Sync"
111 | ]
112 | },
113 | "LocalRefreshLatency": {
114 | "data": "<1ms",
115 | "comment": "The in-memory data structures fire events instantaneously, without waiting for a database."
116 | },
117 | "PersistenceMechanism": {
118 | "data": [
119 | "IndexedDB",
120 | "DB-integrations",
121 | "custom"
122 | ]
123 | },
124 | "PersistenceFeatures": {
125 | "data": "Transactions"
126 | },
127 | "DataModel": {
128 | "data": "Document"
129 | },
130 | "OfflineReads": {
131 | "data": "Full Support"
132 | },
133 | "OptimisticUpdates": {
134 | "data": "Yes"
135 | },
136 | "OfflineWrites": {
137 | "data": "Local conflict resolution"
138 | },
139 | "DataSize": {
140 | "data": "Depends on the size of the shared data"
141 | }
142 | },
143 | "SynchronizationStrategy": {
144 | "FullOrPartialReplication": {
145 | "data": [
146 | "Full Replication"
147 | ]
148 | },
149 | "ConflictHandling": {
150 | "data": "Automatic via CRDT"
151 | },
152 | "WhereResolutionOccurs": {
153 | "data": "Client"
154 | },
155 | "WhatGetsSynced": {
156 | "data": {
157 | "ClientToClient": "CRDT operations, awareness state, content attribution."
158 | }
159 | },
160 | "Authority": {
161 | "data": "Decentralized"
162 | },
163 | "Latency": {
164 | "data": "<1ms",
165 | "comment": "Depends on which provider you choose. But it's pretty fast."
166 | }
167 | },
168 | "AuthIdentity": {
169 | "Encryption": {
170 | "data": "Unopinionated, via providers",
171 | "comment": "E.g. via secsync or matrix-crdt"
172 | },
173 | "AuthenticationMethod": {
174 | "data": [
175 | "Unopinionated, via providers"
176 | ]
177 | },
178 | "AuthorizationPermissions": {
179 | "data": "Unopinionated, via providers"
180 | }
181 | },
182 | "UIRelated": {
183 | "RichTextEditing": {
184 | "data": "Yes",
185 | "comment": "We have integrations with most popular rich-text editors like ProseMirror, Lexical, and CodeMirror."
186 | }
187 | },
188 | "DevelopmentWorkflowsDX": {
189 | "DebuggingTools": {
190 | "data": [
191 | "DevTools",
192 | "Data Inspector"
193 | ]
194 | },
195 | "TypeSupport": {
196 | "data": "Full Support"
197 | }
198 | },
199 | "__generated": {
200 | "lastUpdated": "2025-04-25T15:10:43.000Z"
201 | }
202 | }
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/yjs/details.md:
--------------------------------------------------------------------------------
1 | # Yjs
2 |
3 | Sponsors-backed project for making anything on the web collaborative. Connect
4 | with us to build cool integrations.
5 |
6 | Visit [yjs.dev](https://yjs.dev) for more information.
7 |
8 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/yjs/logo.dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
95 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/yjs/logo.light.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
93 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/zero/details.md:
--------------------------------------------------------------------------------
1 | # Zero
2 |
3 | Zero is a general-purpose sync engine for the web.
4 |
5 | You put Zero in front of your database or web service, and we distribute your backend all the way to main thread of the UI. You get a client-side API that _looks_ like an embedded db, but to which you can issue arbitrary _hybrid queries_ that span the entire database, including the server.
6 |
7 | 
8 |
9 | Behind the scenes, we synchronize queries results continuously to a client-side persistent cache. This cache is used automatically for future queries whenever possible.
10 |
11 | ## More info
12 |
13 | To learn more, see [zerosync.dev](https://zerosync.dev/).
14 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/zero/logo.dark.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/src/generated/zero/logo.light.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/landscape-content-snapshot/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Base Options: */
4 | "esModuleInterop": true,
5 | "skipLibCheck": true,
6 | "target": "es2022",
7 | "allowJs": true,
8 | "moduleDetection": "force",
9 | "resolveJsonModule": true,
10 | "isolatedModules": true,
11 | "verbatimModuleSyntax": true,
12 | /* Strictness */
13 | "strict": true,
14 | "noUncheckedIndexedAccess": true,
15 | "noImplicitOverride": true,
16 | /* If transpiling with TypeScript: */
17 | "module": "NodeNext",
18 | "moduleResolution": "NodeNext",
19 | "sourceMap": true,
20 | /* AND if you're building for a library: */
21 | "declaration": true,
22 | /* If your code doesn't run in the DOM: */
23 | "lib": ["es2022"],
24 | "rootDir": "./src",
25 | "outDir": "./dist",
26 | "tsBuildInfoFile": "./dist/.tsbuildinfo",
27 | "incremental": true,
28 | "composite": true
29 | },
30 | "include": ["src", "src/**/*.json"]
31 | }
32 |
--------------------------------------------------------------------------------
/landscape-fetch-content/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@localfirstfm/landscape-fetch-content",
3 | "version": "0.0.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "build": "tsc",
8 | "fetch-content": "bun src/cli.ts --target-dir ../landscape-content-snapshot/src/generated"
9 | },
10 | "exports": {
11 | "./repos": "./src/repos.ts"
12 | },
13 | "dependencies": {
14 | "@localfirstfm/landscape-schema": "workspace:*",
15 | "effect": "3.12.0",
16 | "@effect/cli": "0.51.0",
17 | "@effect/platform": "0.72.0",
18 | "@effect/platform-node": "0.68.0"
19 | },
20 | "devDependencies": {
21 | "@types/node": "22.10.2",
22 | "typescript": "^5.7.2"
23 | }
24 | }
--------------------------------------------------------------------------------
/landscape-fetch-content/src/cli.ts:
--------------------------------------------------------------------------------
1 | import path from 'node:path'
2 | import { fileURLToPath } from 'node:url'
3 | import * as Cli from '@effect/cli'
4 | import { FileSystem } from '@effect/platform'
5 | import * as PlatformNode from '@effect/platform-node'
6 | import { Array, Effect, Layer, Logger } from 'effect'
7 | import packageJson from '../package.json' with { type: 'json' }
8 | import { fetchRepo } from './fetch-repo.js'
9 | import { repos } from './repos.js'
10 |
11 | const targetDirOption = Cli.Options.directory('target-dir')
12 | const overrideTargetDirOption = Cli.Options.boolean('override-target-dir').pipe(
13 | Cli.Options.withDefault(false),
14 | )
15 |
16 | const showFullErrorsOption = Cli.Options.boolean('show-full-errors').pipe(
17 | Cli.Options.withDefault(false),
18 | )
19 |
20 | export const fetchContentCommand = Cli.Command.make(
21 | 'fetch-content',
22 | {
23 | targetDir: targetDirOption,
24 | overrideTargetDir: overrideTargetDirOption,
25 | showFullErrors: showFullErrorsOption,
26 | },
27 | Effect.fn('fetch-content')(function* ({
28 | targetDir,
29 | overrideTargetDir,
30 | showFullErrors,
31 | }) {
32 | const fs = yield* FileSystem.FileSystem
33 |
34 | if (!process.env.GITHUB_TOKEN) {
35 | yield* Effect.logError(
36 | 'GITHUB_TOKEN is not set. You might run into rate limiting issues.',
37 | )
38 | }
39 |
40 | console.log('targetDir', targetDir)
41 |
42 | if (
43 | (yield* fs.exists(targetDir)) &&
44 | (yield* fs.readDirectory(targetDir).pipe(Effect.map((_) => _.length > 0)))
45 | ) {
46 | const confirmed =
47 | overrideTargetDir ||
48 | (yield* Cli.Prompt.confirm({
49 | message:
50 | 'Target directory is not empty. Please confirm you want to overwrite it.',
51 | }))
52 |
53 | if (confirmed) {
54 | // Make the target directory writable before removing it
55 | yield* fs.chmod(targetDir, 0o755)
56 | yield* fs.remove(targetDir, { recursive: true })
57 | } else {
58 | yield* Effect.log('Aborting')
59 | return
60 | }
61 |
62 | yield* fs.makeDirectory(targetDir, { recursive: true })
63 | }
64 |
65 | const repoResults = yield* Effect.forEach(
66 | repos,
67 | (repoInfo) =>
68 | fetchRepo(repoInfo).pipe(
69 | Effect.catchAll((cause) =>
70 | showFullErrors
71 | ? Effect.logWarning(
72 | `Skipping repo ${repoInfo.id} (${repoInfo.owner}/${repoInfo.repo}) due to error`,
73 | cause,
74 | )
75 | : Effect.logWarning(
76 | `Skipping repo ${repoInfo.id} (${repoInfo.owner}/${repoInfo.repo}) due to error: ${cause._tag} (Run with --show-full-errors to see the full error)`,
77 | ),
78 | ),
79 | ),
80 | {
81 | concurrency: 10,
82 | },
83 | ).pipe(Effect.map(Array.filter((result) => result != null)))
84 |
85 | for (const result of repoResults) {
86 | const dir = path.join(targetDir, result.repoInfo.id)
87 |
88 | yield* fs.makeDirectory(dir, { recursive: true })
89 | for (const { name, content, lastUpdated } of Object.values(
90 | result.files,
91 | )) {
92 | const filePath = path.join(dir, name)
93 | if (typeof content === 'string') {
94 | yield* fs.writeFileString(filePath, content)
95 | } else {
96 | yield* fs.writeFile(filePath, content)
97 | }
98 | yield* fs.chmod(filePath, 0o444)
99 | yield* fs.utimes(filePath, lastUpdated, lastUpdated)
100 | }
101 | }
102 |
103 | // console.log('repoResults', repoResults)
104 |
105 | const ambientDtsContent = `\
106 | declare module '*.svg' {
107 | const content: any
108 | export default content
109 | }
110 |
111 | declare module '*.png' {
112 | const content: any
113 | export default content
114 | }
115 | `
116 |
117 | yield* fs.writeFileString(
118 | path.join(targetDir, 'ambient.d.ts'),
119 | ambientDtsContent,
120 | )
121 | yield* fs.chmod(path.join(targetDir, 'ambient.d.ts'), 0o444)
122 |
123 | // Replace all invalid characters with underscores
124 | const idToVarName = (id: string) => id.replace(/[^a-zA-Z0-9]/g, '_')
125 |
126 | const modFileContent = `\
127 | import { LandscapeSchema } from '@localfirstfm/landscape-schema'
128 | import { Schema } from 'effect'
129 |
130 | ${repoResults
131 | .map(
132 | (repo) =>
133 | `import ${idToVarName(repo.repoInfo.id)}Json from './${repo.repoInfo.id}/${repo.files.dataJson.name}' with { type: 'json' }`,
134 | )
135 | .join('\n')}
136 |
137 | ${repoResults
138 | .map(
139 | (repo) =>
140 | `import ${idToVarName(repo.repoInfo.id)}LogoLight from './${repo.repoInfo.id}/${repo.files.logoLight.name}'
141 | import ${idToVarName(repo.repoInfo.id)}LogoDark from './${repo.repoInfo.id}/${repo.files.logoDark.name}'`,
142 | )
143 | .join('\n')}
144 |
145 | ${repoResults
146 | .map(
147 | (repo) =>
148 | `const ${idToVarName(repo.repoInfo.id)} = Schema.decodeUnknownSync(LandscapeSchema)(${idToVarName(repo.repoInfo.id)}Json)`,
149 | )
150 | .join('\n')}
151 |
152 | export const data = [
153 | ${repoResults
154 | .map(
155 | (repo) =>
156 | `{ ...${idToVarName(repo.repoInfo.id)}, Logo: { Light: ${idToVarName(
157 | repo.repoInfo.id,
158 | )}LogoLight, Dark: ${idToVarName(repo.repoInfo.id)}LogoDark } }`,
159 | )
160 | .join(',\n ')}
161 | ]
162 | `
163 |
164 | yield* fs.writeFileString(path.join(targetDir, 'mod.ts'), modFileContent)
165 | yield* fs.chmod(path.join(targetDir, 'mod.ts'), 0o444)
166 |
167 | yield* Effect.log(`Successfully wrote content to ${targetDir}`)
168 | }),
169 | )
170 |
171 | // Check if the module is the main module executed
172 | const isMain = process.argv[1] === fileURLToPath(import.meta.url)
173 |
174 | if (isMain) {
175 | const cli = Cli.Command.run(fetchContentCommand, {
176 | name: 'Localfirst.fm Landscape CLI',
177 | version: packageJson.version,
178 | })
179 |
180 | const layer = Layer.mergeAll(PlatformNode.NodeContext.layer, Logger.pretty)
181 |
182 | cli(process.argv).pipe(
183 | Effect.annotateLogs({ thread: 'cli-main' }),
184 | Effect.provide(layer),
185 | PlatformNode.NodeRuntime.runMain,
186 | )
187 | }
188 |
--------------------------------------------------------------------------------
/landscape-fetch-content/src/repos.ts:
--------------------------------------------------------------------------------
1 | import { Schema } from 'effect'
2 |
3 | export const RepoInfo = Schema.Struct({
4 | id: Schema.String,
5 | owner: Schema.String,
6 | repo: Schema.String,
7 | /** @default 'main' */
8 | branch: Schema.optionalWith(Schema.String, { default: () => 'main' }),
9 | /** @default '' */
10 | basePath: Schema.optionalWith(Schema.String, { default: () => '' }),
11 | })
12 |
13 | export type RepoInfo = typeof RepoInfo.Type
14 |
15 | export const repos = Schema.decodeSync(Schema.Array(RepoInfo))([
16 | {
17 | id: 'nextgraph',
18 | owner: 'nextgraph-org',
19 | repo: 'landscape-data',
20 | basePath: '',
21 | },
22 | {
23 | id: 'yjs',
24 | owner: 'yjs',
25 | repo: 'local-first-landscape-data',
26 | basePath: 'yjs',
27 | },
28 | {
29 | id: 'automerge',
30 | owner: 'automerge',
31 | repo: 'local-first-landscape-data',
32 | basePath: '',
33 | },
34 | {
35 | id: 'electricsql',
36 | owner: 'electric-sql',
37 | repo: 'local-first-landscape-data',
38 | basePath: '',
39 | },
40 | {
41 | id: 'jazz',
42 | owner: 'garden-co',
43 | repo: 'jazz-lofi-landscape',
44 | },
45 | {
46 | id: 'zero',
47 | owner: 'rocicorp',
48 | repo: 'local-first-landscape-data',
49 | basePath: '',
50 | },
51 | {
52 | id: 'liveblocks-yjs',
53 | owner: 'liveblocks',
54 | repo: 'local-first-landscape-data',
55 | basePath: 'liveblocks-yjs',
56 | },
57 | {
58 | id: 'liveblocks-storage',
59 | owner: 'liveblocks',
60 | repo: 'local-first-landscape-data',
61 | basePath: 'liveblocks-storage',
62 | },
63 | {
64 | id: 'livestore',
65 | owner: 'livestorejs',
66 | repo: 'local-first-landscape',
67 | },
68 | {
69 | id: 'dxos',
70 | owner: 'dxos',
71 | repo: 'local-first-landscape-data',
72 | basePath: '',
73 | },
74 | {
75 | id: 'basic',
76 | owner: 'basicdb',
77 | repo: 'local-first-landscape-data',
78 | basePath: '',
79 | },
80 | {
81 | id: 'convex',
82 | owner: 'get-convex',
83 | repo: 'localfirst-landscape-data',
84 | basePath: '',
85 | },
86 | {
87 | id: 'ditto',
88 | owner: 'getditto',
89 | repo: 'local-first-landscape-data',
90 | basePath: '',
91 | },
92 | {
93 | id: 'powersync',
94 | owner: 'powersync-ja',
95 | repo: 'local-first-landscape-data',
96 | basePath: '',
97 | },
98 | {
99 | id: 'triplit',
100 | owner: 'aspen-cloud',
101 | repo: 'local-first-landscape-data',
102 | basePath: '',
103 | },
104 | {
105 | id: 'tinybase',
106 | owner: 'tinyplex',
107 | repo: 'tinybase-landscape-data',
108 | basePath: '',
109 | },
110 | {
111 | id: 'y-sweet',
112 | owner: 'jamsocket',
113 | repo: 'y-sweet',
114 | basePath: 'local-first-landscape',
115 | },
116 | {
117 | id: 'loro',
118 | owner: 'loro-dev',
119 | repo: 'loro-landscape-data',
120 | basePath: '',
121 | },
122 | {
123 | id: 'instant',
124 | owner: 'instantdb',
125 | repo: 'local-first-landscape-data',
126 | basePath: '',
127 | },
128 | ])
129 |
--------------------------------------------------------------------------------
/landscape-fetch-content/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Base Options: */
4 | "esModuleInterop": true,
5 | "skipLibCheck": true,
6 | "target": "es2022",
7 | "allowJs": true,
8 | "moduleDetection": "force",
9 | "resolveJsonModule": true,
10 | "isolatedModules": true,
11 | "verbatimModuleSyntax": true,
12 | /* Strictness */
13 | "strict": true,
14 | "noUncheckedIndexedAccess": true,
15 | "noImplicitOverride": true,
16 | /* If transpiling with TypeScript: */
17 | "module": "NodeNext",
18 | "moduleResolution": "NodeNext",
19 | "sourceMap": true,
20 | /* AND if you're building for a library: */
21 | "declaration": true,
22 | /* If your code doesn't run in the DOM: */
23 | "lib": ["es2022", "dom"],
24 | "rootDir": "./src",
25 | "outDir": "./dist",
26 | "tsBuildInfoFile": "./dist/.tsbuildinfo",
27 | "incremental": true,
28 | "composite": true
29 | },
30 | "include": ["src/**/*.ts"]
31 | }
32 |
--------------------------------------------------------------------------------
/landscape-schema/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@localfirstfm/landscape-schema",
3 | "version": "0.0.2",
4 | "type": "module",
5 | "exports": {
6 | ".": {
7 | "types": "./dist/mod.d.ts",
8 | "default": "./dist/mod.js"
9 | }
10 | },
11 | "types": "./dist/mod.d.ts",
12 | "files": ["dist", "src"],
13 | "scripts": {
14 | "build": "tsc"
15 | },
16 | "dependencies": {},
17 | "peerDependencies": {
18 | "effect": "3.12.x"
19 | },
20 | "devDependencies": {
21 | "effect": "3.12.0",
22 | "typescript": "^5.7.2"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/landscape-schema/src/mod.ts:
--------------------------------------------------------------------------------
1 | export * from './schema.js'
2 |
--------------------------------------------------------------------------------
/landscape-schema/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Base Options: */
4 | "esModuleInterop": true,
5 | "skipLibCheck": true,
6 | "target": "es2022",
7 | "allowJs": true,
8 | "moduleDetection": "force",
9 | "isolatedModules": true,
10 | "verbatimModuleSyntax": true,
11 | /* Strictness */
12 | "strict": true,
13 | "noUncheckedIndexedAccess": true,
14 | "noImplicitOverride": true,
15 | /* If transpiling with TypeScript: */
16 | "module": "NodeNext",
17 | "sourceMap": true,
18 | /* AND if you're building for a library: */
19 | "declaration": true,
20 | /* If your code doesn't run in the DOM: */
21 | "lib": ["es2022", "dom"],
22 | "rootDir": "./src",
23 | "outDir": "./dist",
24 | "tsBuildInfoFile": "./dist/.tsbuildinfo",
25 | "incremental": true,
26 | "composite": true
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@localfirstfm/landscape-mono",
3 | "private": true,
4 | "scripts": {
5 | "build:ts": "tsc --build tsconfig.all.json",
6 | "generate:content-snapshot": "pnpm --filter @localfirstfm/landscape-fetch-content exec bun ./src/cli.ts --target-dir=../landscape-content-snapshot/src/generated --override-target-dir"
7 | },
8 | "devDependencies": {
9 | "typescript": "^5.7.2",
10 | "@biomejs/biome": "1.9.4"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - '*'
3 |
--------------------------------------------------------------------------------
/temporary-technology-info/ditto/data.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | import { LandscapeSchema } from '@localfirstfm/landscape-schema'
3 |
4 | export const data = LandscapeSchema.make({
5 | Version: 1,
6 | Id: 'ditto',
7 | Name: 'Ditto',
8 | Description:
9 | 'Real-time, peer-to-peer data synchronization across devices and platforms without relying on the cloud, even in offline or unreliable network conditions.',
10 | Website: 'https://ditto.live',
11 | Deployment: ['Hosted', 'Self-hosted'],
12 | License: 'Proprietary',
13 | Logo: {
14 | Light: 'https://path-to-light-logo.png',
15 | Dark: 'https://path-to-dark-logo.png',
16 | },
17 | AppTarget: {
18 | Platform: {
19 | data: ['Browser', 'iOS', 'Android', 'macOS', 'WASM'],
20 | },
21 | LanguageSDK: {
22 | data: ['Swift', 'Kotlin', 'JavaScript', 'C#', 'c++', 'Java'],
23 | },
24 | FrameworkIntegrations: {
25 | data: ['React Native', 'Flutter', 'Jetpack Compose', 'SwiftUI'],
26 | },
27 | },
28 | Networking: {
29 | Protocol: {
30 | data: ['WiFi LAN', 'Bluetooth', 'P2P WiFi', 'TCP', 'HTTP', 'WebSockets'],
31 | comment: `We've developed an intelligent sync system that automatically discovers local devices, establishes a connection, and seamlessly switches between active transports when syncing data (Bluetooth, P2P WiFi, LAN, Websockets) so that if one transport goes down, it automatically switches to the next best one, optimizing for speed. "Resilient Networking" in this context means networking that can network in any environment and dynamically "heal" itself if connections break`,
32 | },
33 | Topology: {
34 | data: 'P2P',
35 | },
36 | },
37 | ServerSideData: {
38 | PersistenceMechanism: {
39 | data: ['Custom'],
40 | },
41 | DataModelParadigm: {
42 | data: 'Document',
43 | },
44 | ExistingDatabaseSupport: {
45 | data: 'HTTP/Webhooks and real-time via CDC Connectors (Kafka-based)',
46 | },
47 | DataSize: {
48 | data: 'No theoretical limit',
49 | comment:
50 | 'No theoretical limit, due to cloud scaling, but we offer benchmarking and performance services to validate & scale cloud resources for larger use cases.',
51 | },
52 | },
53 | ClientSideData: {
54 | QueryAPI: {
55 | data: ['Async'],
56 | },
57 | LocalRefreshLatency: {
58 | data: '10ms-2s',
59 | comment:
60 | 'Depends on cardinality, query optimization plan, and local data size.',
61 | },
62 | PersistenceMechanism: {
63 | data: ['SQLite'],
64 | },
65 | DataModel: {
66 | data: 'Document',
67 | comment: 'Queries are SQL, records are document-oriented.',
68 | },
69 | OfflineReads: {
70 | data: 'Full Support',
71 | },
72 | OfflineWrites: {
73 | data: 'Full local conflict resolution',
74 | },
75 | DataSize: {
76 | data: 'up to the size of the hard drive',
77 | },
78 | },
79 | SynchronizationStrategy: {
80 | FullOrPartialReplication: {
81 | data: ['Full Replication', 'Partial Replication'],
82 | },
83 | ConflictHandling: {
84 | data: 'Automatic via CRDT',
85 | },
86 | WhereResolutionOccurs: {
87 | data: 'Client',
88 | },
89 | WhatGetsSynced: {
90 | data: {
91 | ClientToClient: 'document deltas',
92 | },
93 | comment:
94 | 'Ditto has client-to-client deltas, and the server is running the same CRDT as the client, and is not required.',
95 | },
96 | Authority: {
97 | data: 'Decentralized',
98 | comment: 'Decentralized via authentication servers.',
99 | },
100 | },
101 | AuthIdentity: {
102 | Encryption: {
103 | data: 'Built-in e2ee',
104 | },
105 | AuthenticationMethod: {
106 | data: ['JWT Tokens'],
107 | },
108 | AuthorizationPermissions: {
109 | data: 'Custom-mapped ACLs',
110 | },
111 | },
112 | UIRelated: {
113 | Components: {
114 | data: ['Presence'],
115 | comment:
116 | 'SDK provides which peers you are connected to, and over what transports.',
117 | },
118 | },
119 | DevelopmentWorkflowsDX: {
120 | DebuggingTools: {
121 | data: ['DevTools', 'Data Inspector', 'Network Inspector'],
122 | comment: 'Open source debugging and diagnostic tools for developers.',
123 | },
124 | },
125 | })
126 |
--------------------------------------------------------------------------------
/temporary-technology-info/ditto/details.md:
--------------------------------------------------------------------------------
1 | ## General
2 |
3 | Lorem ipsum dolor sit amet consectetur. Penatibus viverra quam massa leo suspendisse. Est porttitor donec integer luctus sed sed ipsum in adipiscing. Nunc pharetra lacus iaculis tristique penatibus dolor sit.
4 |
5 | 
6 |
7 | ## The Story
8 |
9 | Lorem ipsum dolor sit amet consectetur. Penatibus viverra quam massa leo suspendisse. Est porttitor donec integer luctus sed sed ipsum in adipiscing. Nunc pharetra lacus iaculis tristique penatibus dolor sit. Lorem ipsum dolor sit amet consectetur. Penatibus viverra quam massa leo suspendisse. Est porttitor donec integer luctus sed sed ipsum in adipiscing. Nunc pharetra lacus iaculis tristique penatibus dolor sit. Lorem ipsum dolor sit amet consectetur. Penatibus viverra quam massa leo suspendisse. Est porttitor donec integer luctus sed sed ipsum in adipiscing. Nunc pharetra lacus iaculis tristique penatibus dolor sit.
10 |
11 | ## Resources
12 |
13 | Lorem ipsum dolor sit amet consectetur. Penatibus viverra quam massa leo suspendisse.
14 |
15 | - [Website](https://ditto.live)
16 | - [Documentation](https://docs.ditto.live/home/introduction)
17 |
--------------------------------------------------------------------------------
/temporary-technology-info/ditto/logo.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/localfirstfm/local-first-landscape/621278c13945f8c197c671acddb588970549d208/temporary-technology-info/ditto/logo.dark.png
--------------------------------------------------------------------------------
/temporary-technology-info/ditto/logo.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/localfirstfm/local-first-landscape/621278c13945f8c197c671acddb588970549d208/temporary-technology-info/ditto/logo.light.png
--------------------------------------------------------------------------------
/temporary-technology-info/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@localfirstfm/temporary-technology-info",
3 | "type": "module",
4 | "version": "0.0.0",
5 | "dependencies": {
6 | "@localfirstfm/landscape-schema": "workspace:*"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/temporary-technology-info/validate.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | import { readdir } from 'node:fs/promises'
3 | import { join } from 'node:path'
4 |
5 | const directories = [
6 | 'y-sweet',
7 | 'zero',
8 | 'jazz',
9 | 'liveblocks-storage',
10 | 'powersync',
11 | 'triplit',
12 | 'convex',
13 | 'electricsql',
14 | 'automerge',
15 | 'basicdb',
16 | 'ditto',
17 | 'dxos',
18 | 'liveblocks-yjs',
19 | ]
20 |
21 | async function validateAll() {
22 | for (const dir of directories) {
23 | try {
24 | const module = await import(`./${dir}/data.js`)
25 | console.log(`✓ ${dir} validated successfully`)
26 | } catch (error) {
27 | console.error(`✗ Error in ${dir}:`, error.message)
28 | }
29 | }
30 | }
31 |
32 | validateAll()
33 |
--------------------------------------------------------------------------------
/tsconfig.all.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": [],
3 | "references": [
4 | { "path": "./landscape-schema" },
5 | { "path": "./landscape-fetch-content" },
6 | { "path": "./landscape-content-snapshot" }
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------