├── .gitignore
├── .svelte-kit
├── ambient.d.ts
├── generated
│ ├── client-manifest.js
│ ├── client-matchers.js
│ ├── client
│ │ ├── app.js
│ │ ├── matchers.js
│ │ └── nodes
│ │ │ ├── 0.js
│ │ │ ├── 1.js
│ │ │ ├── 2.js
│ │ │ ├── 3.js
│ │ │ ├── 4.js
│ │ │ ├── 5.js
│ │ │ ├── 6.js
│ │ │ ├── 7.js
│ │ │ └── 8.js
│ ├── nodes
│ │ ├── 0.js
│ │ ├── 1.js
│ │ └── 2.js
│ ├── root.svelte
│ └── server
│ │ └── internal.js
├── tsconfig.json
└── types
│ ├── route_meta_data.json
│ └── src
│ └── routes
│ ├── $types.d.ts
│ ├── (iframe)
│ └── demo
│ │ ├── $types.d.ts
│ │ └── [row_id]
│ │ ├── $types.d.ts
│ │ └── [mode]
│ │ └── $types.d.ts
│ └── (main)
│ ├── $types.d.ts
│ ├── contact
│ └── $types.d.ts
│ └── depth
│ └── $types.d.ts
├── Dockerfile
├── LICENSE
├── README.md
├── docker-compose.yml
├── header.png
├── jsconfig.json
├── package-lock.json
├── package.json
├── src
├── app.html
├── components
│ ├── Button.svelte
│ ├── CodeSnippet.svelte
│ ├── CopyInput.svelte
│ ├── DataBall.svelte
│ ├── DataTable.svelte
│ ├── DemoBox.svelte
│ ├── FeatureCard.svelte
│ ├── FeatureItem.svelte
│ ├── Frame.svelte
│ ├── Input.svelte
│ ├── Markup.svelte
│ ├── QRCode.svelte
│ ├── ShowOff.svelte
│ ├── Subtitle.svelte
│ └── Title.svelte
├── data
│ └── code.json
├── global.d.ts
├── routes
│ ├── (iframe)
│ │ ├── datatable
│ │ │ ├── +page.js
│ │ │ └── +page.svelte
│ │ └── demo
│ │ │ ├── +layout.svelte
│ │ │ └── [row_id]
│ │ │ ├── +page.js
│ │ │ ├── +page.svelte
│ │ │ └── [mode]
│ │ │ ├── +page.js
│ │ │ └── +page.svelte
│ ├── (main)
│ │ ├── +layout.svelte
│ │ ├── +page.js
│ │ ├── +page.svelte
│ │ ├── contact
│ │ │ ├── +page.js
│ │ │ └── +page.svelte
│ │ └── depth
│ │ │ ├── +page.js
│ │ │ └── +page.svelte
│ └── +error.svelte
└── utils
│ ├── condition.ts
│ ├── mapStore.ts
│ ├── primaryKeys.ts
│ ├── svupa.ts
│ ├── table.ts
│ ├── tableRow.ts
│ └── tableStore.ts
├── static
├── arrow.png
├── arrow2.png
├── check.png
├── concept.png
├── copy.png
├── demo_hero.gif
├── frameworks.png
├── github.png
├── icon.png
├── link.png
├── plus.png
├── qr.png
├── styles.css
├── tail.css
├── trash.png
└── x.png
├── svelte.config.js
├── tailwind.config.cjs
└── vite.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 |
--------------------------------------------------------------------------------
/.svelte-kit/ambient.d.ts:
--------------------------------------------------------------------------------
1 |
2 | // this file is generated — do not edit it
3 |
4 |
5 | ///
3 |
4 |
The total value of number_field is {$sum}.
\n", 4 | "sql": "INSERT INTO table_name (primary_key, my_column, another_column) VALUES ('key-123', 'my_value', 'new data');", 5 | "installNpm": "npm install svupa --save", 6 | "installYarn": "yarn install svupa ?" 7 | } -------------------------------------------------------------------------------- /src/global.d.ts: -------------------------------------------------------------------------------- 1 | ///16 | Hey there 👋 If you like Svupa.js consider dropping a star on { 18 | openInNewTab("https://github.com/jfreyberg/Svupa"); 19 | }} 20 | class="underline cursor-pointer">Github! 22 |
23 |175 | You can open this link in a new tab, another browser, your phone or send it 176 | to your friend on another continent. They will see the same data as you do, 177 | and they will see it update in realtime when you click - and you will see 178 | their changes in realtime too. 179 |
180 | 181 |184 | This is just a minimalistic demo. You are viewing and manipulating one single value 187 | in one isolated row in 188 | one lonely table. But Svupa will work just as 189 | fine with dozens of tables, 190 | hundreds of rows 191 | and thousands of values. If synchronization of 192 | one single integer already looks that cool, imagine what synchronization of 193 | a whole application can look like. Sounds like a you need to write a lot of 194 | code, doesn't it? Fortunately, it is svupa simple. 195 |
196 | 197 |202 | Using the Supabase API is low effort already. Svupa takes it to the next 203 | level. You can integrate it into your existing Svelte project with just a 204 | few lines of code. 205 |
206 | 207 |
224 | That's it. Your application is now subscribed to the state of
225 |
234 | Svupa has some built in metadata stores like
249 | And - you probably already guessed it - this store and the dependent UI 250 | components are updated with any update to the underlying data. No matter if 251 | it's an optimistic update or an update in the database, your UI will always 252 | be up to date and consistent. 253 |
254 | 255 |258 | Updates of relevant rows will trigger a render of the component on all 259 | subscribed clients, no matter where they come from. Any microservice or 260 | cronjob can update the data and all clients will immediately see the change. 261 |
262 |280 | Currently, Svupa is in a proof of concept state and I am very happy about 281 | feedback. The framework is in open alpha (i.e. it works and is openly 282 | available on GitHub), but there is no npm release yet. While the majority of 283 | features seem to be running stable, it is strongly advised against using 284 | Svupa for anything other than playing around as of now and the API is very 285 | likely going to change (improve) drastically before the first beta release. 286 | If you have questions, ideas or feedback, please get in touch. 287 |
288 | 289 |8 | This website does not use cookies and it does not collect any personal data. 9 |
10 | 11 |13 | I built Svupa to use it at my startup kmapp.io. We are building a modern, document-centric knowledge management platform. 17 | Building a multi-user web app is not easy, there are a lot of things to 18 | consider during development. One of the most important things is the state 19 | of the application. The state of the application is what the user sees, and 20 | ideally, it should be consistent for all users that are currently viewing 21 | the same content. If user A adds a comment, user B should see this comment 22 | in realtime. It is absolutely possible to achieve this with Supabase and 23 | Svelte, but doing it for many different parts of the application (comments, 24 | tags, etc.) requires a lot of boilerplate code. Abstraction is the key to 25 | success here, and that is when I came up with the idea for Svupa - an 26 | abstraction layer, that makes it easy to build realtime web apps. 27 |
28 | 72 |77 | As a developer, one just just needs to define what data is needed, if (and 78 | how) it needs to be transformed and how the data should be displayed to the 79 | user and mutated by the user. Everything else is handled by Svupa. The data 80 | changes, the UI updates. 81 |
82 | 83 |87 | Svupa is built on top of Svelte and Supabase, which in turn is built on top 88 | of Postgres. This makes Svupa a heavily opinionated framework. Below you 89 | will see why I chose these dependencies, as well as explanations of how to 90 | understand Svupa if you are not familiar with Svelte or Supabase. 91 |
92 |94 | If you are familiar with Svelte (especially stores and reactivity) you can 95 | think of Svupa like this: Using a Svelte store means you can see changes 96 | applied to the store data immediately on the UI. With Svupa, the same thing 97 | happens but not just for one user, but all users who subscribe to a the data 98 | of a store. 99 |
100 | 101 |117 | If you are familar with Supabase Realtime, you can think of Svupa like this: 118 | Using realtime, changes in your database are streamed to subscribed 119 | instances of your application (client browsers). Svupa now leverages Svelte 120 | to further "stream" this data inside the clients browser, transforming it if 121 | necessary and updating the UI to instantly reflect your changes. 122 |
123 |142 | There are other great, much more sophisticated and established frameworks 143 | that deal with client synchronization. If you like Svupa, check out these 144 | frameworks to see if they fit your usecase. 145 |
146 |