Compare commits
9 commits
Author | SHA1 | Date | |
---|---|---|---|
6a4fbf5afc | |||
1885d43fa6 | |||
5072a69333 | |||
bf41d27353 | |||
463e18015f | |||
22e8576cab | |||
70a92cb0e6 | |||
ec1ed9e487 | |||
c8a02fb468 |
28 changed files with 893 additions and 1351 deletions
9
.gitignore
vendored
9
.gitignore
vendored
|
@ -1,9 +1,15 @@
|
|||
node_modules
|
||||
gm0
|
||||
introducer
|
||||
storage0
|
||||
storage1
|
||||
webapp
|
||||
|
||||
# Output
|
||||
.output
|
||||
.vercel
|
||||
/.svelte-kit
|
||||
.svelte-kit
|
||||
packages/.svelte-kit
|
||||
/build
|
||||
|
||||
# OS
|
||||
|
@ -11,6 +17,7 @@ node_modules
|
|||
Thumbs.db
|
||||
|
||||
# Env
|
||||
.venv
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
|
93
README.md
93
README.md
|
@ -18,6 +18,66 @@ The project intends to be a demonstration of how to use [Tahoe-lafs]() "provide
|
|||
git clone https://github.com/blaisep/private_facts.git && cd private_facts
|
||||
```
|
||||
|
||||
Install dependencies.
|
||||
|
||||
```sh
|
||||
uv venv
|
||||
source .venv/bin/activate
|
||||
uv pip install -r pyproject.toml
|
||||
```
|
||||
|
||||
Setup a grid:
|
||||
|
||||
```sh
|
||||
grid-manager --config ./gm0 create
|
||||
```
|
||||
|
||||
Initiate Tahoe-LAFS servers (one introducer, two storage servers and a client server, each in a separate terminal window):
|
||||
|
||||
Introducer server:
|
||||
|
||||
```sh
|
||||
.venv/bin/tahoe create-introducer --listen=tcp --port=6001 --location=tcp:localhost:6001 ./introducer
|
||||
.venv/bin/tahoe -d introducer run
|
||||
```
|
||||
|
||||
Two storage servers:
|
||||
|
||||
```sh
|
||||
.venv/bin/tahoe create-node --introducer $(cat introducer/private/introducer.furl) --nickname storage0 --webport 6101 --location tcp:localhost:6102 --port 6102 ./storage0
|
||||
.venv/bin/tahoe create-node --introducer $(cat introducer/private/introducer.furl) --nickname storage1 --webport 6201 --location tcp:localhost:6202 --port 6202 ./storage1
|
||||
.venv/bin/tahoe -d storage0 run
|
||||
.venv/bin/tahoe -d storage1 run
|
||||
```
|
||||
|
||||
Add storage servers to grid and create certificates:
|
||||
|
||||
```sh
|
||||
grid-manager --config ./gm0 add storage0 $(cat storage0/node.pubkey)
|
||||
grid-manager --config ./gm0 add storage1 $(cat storage1/node.pubkey)
|
||||
grid-manager --config ./gm0 sign storage0 > ./storage0/gridmanager.cert 30
|
||||
grid-manager --config ./gm0 sign storage1 > ./storage1/gridmanager.cert 30
|
||||
```
|
||||
|
||||
Edit storage servers to make them announce their certificates to the grid. Edit the `tahoe.cfg` file in `storage0` and `storage1`:
|
||||
|
||||
```sh
|
||||
[storage]
|
||||
grid_management = true
|
||||
|
||||
[grid_manager_certificates]
|
||||
default = gridmanager.cert
|
||||
```
|
||||
|
||||
Re-start storage servers.
|
||||
|
||||
Client:
|
||||
|
||||
```sh
|
||||
.venv/bin/tahoe create-client --introducer $(cat introducer/private/introducer.furl) --nickname webapp --webport 6301 --shares-total=3 --shares-needed=2 --shares-happy=3 ./webapp
|
||||
.venv/bin/tahoe -d webapp run
|
||||
```
|
||||
|
||||
### Install from (Docker) Image
|
||||
|
||||
TBA
|
||||
|
@ -60,39 +120,6 @@ The project issue tracker is getting migrated. For now, feel free to open an iss
|
|||
Pull requests are welcome. For major changes, please open an issue first
|
||||
to discuss what you would like to change.
|
||||
|
||||
### Set up the developer environment
|
||||
|
||||
Initiate Tahoe-LAFS servers (one introducer, two storage servers and a client server):
|
||||
|
||||
Introducer server:
|
||||
|
||||
```sh
|
||||
.venv/bin/tahoe create-introducer --listen=tcp --port=5555 --location=tcp:localhost:5555 ./introducer
|
||||
.venv/bin/tahoe -d introducer run &>/dev/null &
|
||||
```
|
||||
|
||||
Two storage servers:
|
||||
|
||||
```sh
|
||||
.venv/bin/tahoe create-node --introducer $(cat introducer/private/introducer.furl) --nickname storage0 --webport 6001 --location tcp:localhost:6003 --port 6003 ./storage0
|
||||
.venv/bin/tahoe create-node --introducer $(cat introducer/private/introducer.furl) --nickname storage1 --webport 6101 --location tcp:localhost:6103 --port 6103 ./storage1
|
||||
.venv/bin/tahoe -d storage0 run &>/dev/null &
|
||||
.venv/bin/tahoe -d storage1 run &>/dev/null &
|
||||
```
|
||||
|
||||
Client:
|
||||
|
||||
```sh
|
||||
.venv/bin/tahoe create-client --introducer $(cat introducer/private/introducer.furl) --nickname webapp --webport 6401 --shares-total=3 --shares-needed=2 --shares-happy=3 ./webapp
|
||||
.venv/bin/tahoe -d webapp run &>/dev/null &
|
||||
```
|
||||
|
||||
The commands should return four PIDs. Note them down to kill them later, when finished, with:
|
||||
|
||||
```sh
|
||||
kill -9 <PID>
|
||||
```
|
||||
|
||||
### Getting ready for your first pull request
|
||||
|
||||
Please make sure to update tests as appropriate.
|
||||
|
|
1
packages/.env.example
Normal file
1
packages/.env.example
Normal file
|
@ -0,0 +1 @@
|
|||
TAHOE_API=http://x.x.x.x:xxxx
|
263
packages/.svelte-kit/ambient.d.ts
vendored
263
packages/.svelte-kit/ambient.d.ts
vendored
|
@ -1,263 +0,0 @@
|
|||
|
||||
// this file is generated — do not edit it
|
||||
|
||||
|
||||
/// <reference types="@sveltejs/kit" />
|
||||
|
||||
/**
|
||||
* Environment variables [loaded by Vite](https://vitejs.dev/guide/env-and-mode.html#env-files) from `.env` files and `process.env`. Like [`$env/dynamic/private`](https://svelte.dev/docs/kit/$env-dynamic-private), this module cannot be imported into client-side code. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://svelte.dev/docs/kit/configuration#env) _and do_ start with [`config.kit.env.privatePrefix`](https://svelte.dev/docs/kit/configuration#env) (if configured).
|
||||
*
|
||||
* _Unlike_ [`$env/dynamic/private`](https://svelte.dev/docs/kit/$env-dynamic-private), the values exported from this module are statically injected into your bundle at build time, enabling optimisations like dead code elimination.
|
||||
*
|
||||
* ```ts
|
||||
* import { API_KEY } from '$env/static/private';
|
||||
* ```
|
||||
*
|
||||
* Note that all environment variables referenced in your code should be declared (for example in an `.env` file), even if they don't have a value until the app is deployed:
|
||||
*
|
||||
* ```
|
||||
* MY_FEATURE_FLAG=""
|
||||
* ```
|
||||
*
|
||||
* You can override `.env` values from the command line like so:
|
||||
*
|
||||
* ```bash
|
||||
* MY_FEATURE_FLAG="enabled" npm run dev
|
||||
* ```
|
||||
*/
|
||||
declare module '$env/static/private' {
|
||||
export const NVM_INC: string;
|
||||
export const COREPACK_ROOT: string;
|
||||
export const npm_package_devDependencies_prettier: string;
|
||||
export const TERM_PROGRAM: string;
|
||||
export const npm_package_devDependencies_eslint_plugin_svelte: string;
|
||||
export const NODE: string;
|
||||
export const NVM_CD_FLAGS: string;
|
||||
export const npm_package_devDependencies_prettier_plugin_svelte: string;
|
||||
export const INIT_CWD: string;
|
||||
export const SHELL: string;
|
||||
export const TERM: string;
|
||||
export const npm_package_devDependencies_vite: string;
|
||||
export const TMPDIR: string;
|
||||
export const HOMEBREW_REPOSITORY: string;
|
||||
export const RIPGREP_CONFIG_PATH: string;
|
||||
export const npm_package_scripts_lint: string;
|
||||
export const TERM_PROGRAM_VERSION: string;
|
||||
export const npm_package_scripts_dev: string;
|
||||
export const TERM_SESSION_ID: string;
|
||||
export const npm_package_devDependencies__sveltejs_kit: string;
|
||||
export const npm_config_registry: string;
|
||||
export const ZSH: string;
|
||||
export const npm_package_devDependencies_globals: string;
|
||||
export const USER: string;
|
||||
export const NVM_DIR: string;
|
||||
export const LS_COLORS: string;
|
||||
export const COMMAND_MODE: string;
|
||||
export const npm_package_devDependencies_mdsvex: string;
|
||||
export const PNPM_SCRIPT_SRC_DIR: string;
|
||||
export const SSH_AUTH_SOCK: string;
|
||||
export const __CF_USER_TEXT_ENCODING: string;
|
||||
export const npm_package_devDependencies_eslint: string;
|
||||
export const TERM_FEATURES: string;
|
||||
export const npm_execpath: string;
|
||||
export const PAGER: string;
|
||||
export const FZF_DEFAULT_OPTS: string;
|
||||
export const npm_package_devDependencies_svelte: string;
|
||||
export const LSCOLORS: string;
|
||||
export const npm_config_frozen_lockfile: string;
|
||||
export const PATH: string;
|
||||
export const TERMINFO_DIRS: string;
|
||||
export const FZF_COMPLETION_TRIGGER: string;
|
||||
export const npm_config_engine_strict: string;
|
||||
export const __CFBundleIdentifier: string;
|
||||
export const PWD: string;
|
||||
export const npm_command: string;
|
||||
export const JAVA_HOME: string;
|
||||
export const npm_package_scripts_preview: string;
|
||||
export const EDITOR: string;
|
||||
export const npm_lifecycle_event: string;
|
||||
export const LANG: string;
|
||||
export const npm_package_name: string;
|
||||
export const npm_package_devDependencies__sveltejs_vite_plugin_svelte: string;
|
||||
export const ITERM_PROFILE: string;
|
||||
export const NODE_PATH: string;
|
||||
export const npm_package_scripts_build: string;
|
||||
export const XPC_FLAGS: string;
|
||||
export const npm_package_devDependencies_vitest: string;
|
||||
export const FZF_COMPLETION_OPTS: string;
|
||||
export const NVM_LAZY_LOAD: string;
|
||||
export const npm_package_devDependencies_eslint_config_prettier: string;
|
||||
export const npm_config_node_gyp: string;
|
||||
export const XPC_SERVICE_NAME: string;
|
||||
export const npm_package_version: string;
|
||||
export const npm_package_devDependencies__sveltejs_adapter_auto: string;
|
||||
export const COLORFGBG: string;
|
||||
export const HOME: string;
|
||||
export const SHLVL: string;
|
||||
export const PYENV_SHELL: string;
|
||||
export const npm_package_type: string;
|
||||
export const npm_package_scripts_test: string;
|
||||
export const LC_TERMINAL_VERSION: string;
|
||||
export const HOMEBREW_PREFIX: string;
|
||||
export const ITERM_SESSION_ID: string;
|
||||
export const LOGNAME: string;
|
||||
export const LESS: string;
|
||||
export const npm_package_scripts_format: string;
|
||||
export const VISUAL: string;
|
||||
export const npm_lifecycle_script: string;
|
||||
export const FZF_DEFAULT_COMMAND: string;
|
||||
export const NVM_BIN: string;
|
||||
export const npm_config_user_agent: string;
|
||||
export const HOMEBREW_CELLAR: string;
|
||||
export const INFOPATH: string;
|
||||
export const DISPLAY: string;
|
||||
export const LC_TERMINAL: string;
|
||||
export const npm_package_devDependencies__types_eslint: string;
|
||||
export const COLORTERM: string;
|
||||
export const npm_package_scripts_test_unit: string;
|
||||
export const npm_node_execpath: string;
|
||||
export const NODE_ENV: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to [`$env/static/private`](https://svelte.dev/docs/kit/$env-static-private), except that it only includes environment variables that begin with [`config.kit.env.publicPrefix`](https://svelte.dev/docs/kit/configuration#env) (which defaults to `PUBLIC_`), and can therefore safely be exposed to client-side code.
|
||||
*
|
||||
* Values are replaced statically at build time.
|
||||
*
|
||||
* ```ts
|
||||
* import { PUBLIC_BASE_URL } from '$env/static/public';
|
||||
* ```
|
||||
*/
|
||||
declare module '$env/static/public' {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This module provides access to runtime environment variables, as defined by the platform you're running on. For example if you're using [`adapter-node`](https://github.com/sveltejs/kit/tree/main/packages/adapter-node) (or running [`vite preview`](https://svelte.dev/docs/kit/cli)), this is equivalent to `process.env`. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://svelte.dev/docs/kit/configuration#env) _and do_ start with [`config.kit.env.privatePrefix`](https://svelte.dev/docs/kit/configuration#env) (if configured).
|
||||
*
|
||||
* This module cannot be imported into client-side code.
|
||||
*
|
||||
* Dynamic environment variables cannot be used during prerendering.
|
||||
*
|
||||
* ```ts
|
||||
* import { env } from '$env/dynamic/private';
|
||||
* console.log(env.DEPLOYMENT_SPECIFIC_VARIABLE);
|
||||
* ```
|
||||
*
|
||||
* > In `dev`, `$env/dynamic` always includes environment variables from `.env`. In `prod`, this behavior will depend on your adapter.
|
||||
*/
|
||||
declare module '$env/dynamic/private' {
|
||||
export const env: {
|
||||
NVM_INC: string;
|
||||
COREPACK_ROOT: string;
|
||||
npm_package_devDependencies_prettier: string;
|
||||
TERM_PROGRAM: string;
|
||||
npm_package_devDependencies_eslint_plugin_svelte: string;
|
||||
NODE: string;
|
||||
NVM_CD_FLAGS: string;
|
||||
npm_package_devDependencies_prettier_plugin_svelte: string;
|
||||
INIT_CWD: string;
|
||||
SHELL: string;
|
||||
TERM: string;
|
||||
npm_package_devDependencies_vite: string;
|
||||
TMPDIR: string;
|
||||
HOMEBREW_REPOSITORY: string;
|
||||
RIPGREP_CONFIG_PATH: string;
|
||||
npm_package_scripts_lint: string;
|
||||
TERM_PROGRAM_VERSION: string;
|
||||
npm_package_scripts_dev: string;
|
||||
TERM_SESSION_ID: string;
|
||||
npm_package_devDependencies__sveltejs_kit: string;
|
||||
npm_config_registry: string;
|
||||
ZSH: string;
|
||||
npm_package_devDependencies_globals: string;
|
||||
USER: string;
|
||||
NVM_DIR: string;
|
||||
LS_COLORS: string;
|
||||
COMMAND_MODE: string;
|
||||
npm_package_devDependencies_mdsvex: string;
|
||||
PNPM_SCRIPT_SRC_DIR: string;
|
||||
SSH_AUTH_SOCK: string;
|
||||
__CF_USER_TEXT_ENCODING: string;
|
||||
npm_package_devDependencies_eslint: string;
|
||||
TERM_FEATURES: string;
|
||||
npm_execpath: string;
|
||||
PAGER: string;
|
||||
FZF_DEFAULT_OPTS: string;
|
||||
npm_package_devDependencies_svelte: string;
|
||||
LSCOLORS: string;
|
||||
npm_config_frozen_lockfile: string;
|
||||
PATH: string;
|
||||
TERMINFO_DIRS: string;
|
||||
FZF_COMPLETION_TRIGGER: string;
|
||||
npm_config_engine_strict: string;
|
||||
__CFBundleIdentifier: string;
|
||||
PWD: string;
|
||||
npm_command: string;
|
||||
JAVA_HOME: string;
|
||||
npm_package_scripts_preview: string;
|
||||
EDITOR: string;
|
||||
npm_lifecycle_event: string;
|
||||
LANG: string;
|
||||
npm_package_name: string;
|
||||
npm_package_devDependencies__sveltejs_vite_plugin_svelte: string;
|
||||
ITERM_PROFILE: string;
|
||||
NODE_PATH: string;
|
||||
npm_package_scripts_build: string;
|
||||
XPC_FLAGS: string;
|
||||
npm_package_devDependencies_vitest: string;
|
||||
FZF_COMPLETION_OPTS: string;
|
||||
NVM_LAZY_LOAD: string;
|
||||
npm_package_devDependencies_eslint_config_prettier: string;
|
||||
npm_config_node_gyp: string;
|
||||
XPC_SERVICE_NAME: string;
|
||||
npm_package_version: string;
|
||||
npm_package_devDependencies__sveltejs_adapter_auto: string;
|
||||
COLORFGBG: string;
|
||||
HOME: string;
|
||||
SHLVL: string;
|
||||
PYENV_SHELL: string;
|
||||
npm_package_type: string;
|
||||
npm_package_scripts_test: string;
|
||||
LC_TERMINAL_VERSION: string;
|
||||
HOMEBREW_PREFIX: string;
|
||||
ITERM_SESSION_ID: string;
|
||||
LOGNAME: string;
|
||||
LESS: string;
|
||||
npm_package_scripts_format: string;
|
||||
VISUAL: string;
|
||||
npm_lifecycle_script: string;
|
||||
FZF_DEFAULT_COMMAND: string;
|
||||
NVM_BIN: string;
|
||||
npm_config_user_agent: string;
|
||||
HOMEBREW_CELLAR: string;
|
||||
INFOPATH: string;
|
||||
DISPLAY: string;
|
||||
LC_TERMINAL: string;
|
||||
npm_package_devDependencies__types_eslint: string;
|
||||
COLORTERM: string;
|
||||
npm_package_scripts_test_unit: string;
|
||||
npm_node_execpath: string;
|
||||
NODE_ENV: string;
|
||||
[key: `PUBLIC_${string}`]: undefined;
|
||||
[key: `${string}`]: string | undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to [`$env/dynamic/private`](https://svelte.dev/docs/kit/$env-dynamic-private), but only includes variables that begin with [`config.kit.env.publicPrefix`](https://svelte.dev/docs/kit/configuration#env) (which defaults to `PUBLIC_`), and can therefore safely be exposed to client-side code.
|
||||
*
|
||||
* Note that public dynamic environment variables must all be sent from the server to the client, causing larger network requests — when possible, use `$env/static/public` instead.
|
||||
*
|
||||
* Dynamic environment variables cannot be used during prerendering.
|
||||
*
|
||||
* ```ts
|
||||
* import { env } from '$env/dynamic/public';
|
||||
* console.log(env.PUBLIC_DEPLOYMENT_SPECIFIC_VARIABLE);
|
||||
* ```
|
||||
*/
|
||||
declare module '$env/dynamic/public' {
|
||||
export const env: {
|
||||
[key: `PUBLIC_${string}`]: string | undefined;
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
export { matchers } from './matchers.js';
|
||||
|
||||
export const nodes = [
|
||||
() => import('./nodes/0'),
|
||||
() => import('./nodes/1'),
|
||||
() => import('./nodes/2')
|
||||
];
|
||||
|
||||
export const server_loads = [];
|
||||
|
||||
export const dictionary = {
|
||||
"/": [2]
|
||||
};
|
||||
|
||||
export const hooks = {
|
||||
handleError: (({ error }) => { console.error(error) }),
|
||||
|
||||
reroute: (() => {})
|
||||
};
|
||||
|
||||
export { default as root } from '../root.js';
|
|
@ -1 +0,0 @@
|
|||
export const matchers = {};
|
|
@ -1 +0,0 @@
|
|||
export { default as component } from "../../../../node_modules/.pnpm/@sveltejs+kit@2.8.0_@sveltejs+vite-plugin-svelte@4.0.0_svelte@5.1.15_vite@5.4.11__svelte@5.1.15_vite@5.4.11/node_modules/@sveltejs/kit/src/runtime/components/svelte-5/layout.svelte";
|
|
@ -1 +0,0 @@
|
|||
export { default as component } from "../../../../node_modules/.pnpm/@sveltejs+kit@2.8.0_@sveltejs+vite-plugin-svelte@4.0.0_svelte@5.1.15_vite@5.4.11__svelte@5.1.15_vite@5.4.11/node_modules/@sveltejs/kit/src/runtime/components/svelte-5/error.svelte";
|
|
@ -1 +0,0 @@
|
|||
export { default as component } from "../../../../src/routes/+page.svelte";
|
|
@ -1,3 +0,0 @@
|
|||
import { asClassComponent } from 'svelte/legacy';
|
||||
import Root from './root.svelte';
|
||||
export default asClassComponent(Root);
|
|
@ -1,66 +0,0 @@
|
|||
<!-- This file is generated by @sveltejs/kit — do not edit it! -->
|
||||
<svelte:options runes={true} />
|
||||
<script>
|
||||
import { setContext, onMount, tick } from 'svelte';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
// stores
|
||||
let { stores, page, constructors, components = [], form, data_0 = null, data_1 = null } = $props();
|
||||
|
||||
if (!browser) {
|
||||
setContext('__svelte__', stores);
|
||||
}
|
||||
|
||||
if (browser) {
|
||||
$effect.pre(() => stores.page.set(page));
|
||||
} else {
|
||||
stores.page.set(page);
|
||||
}
|
||||
$effect(() => {
|
||||
stores;page;constructors;components;form;data_0;data_1;
|
||||
stores.page.notify();
|
||||
});
|
||||
|
||||
let mounted = $state(false);
|
||||
let navigated = $state(false);
|
||||
let title = $state(null);
|
||||
|
||||
onMount(() => {
|
||||
const unsubscribe = stores.page.subscribe(() => {
|
||||
if (mounted) {
|
||||
navigated = true;
|
||||
tick().then(() => {
|
||||
title = document.title || 'untitled page';
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
mounted = true;
|
||||
return unsubscribe;
|
||||
});
|
||||
|
||||
const Pyramid_1=$derived(constructors[1])
|
||||
</script>
|
||||
|
||||
{#if constructors[1]}
|
||||
{@const Pyramid_0 = constructors[0]}
|
||||
<!-- svelte-ignore binding_property_non_reactive -->
|
||||
<Pyramid_0 bind:this={components[0]} data={data_0} {form}>
|
||||
<!-- svelte-ignore binding_property_non_reactive -->
|
||||
<Pyramid_1 bind:this={components[1]} data={data_1} {form} />
|
||||
</Pyramid_0>
|
||||
|
||||
{:else}
|
||||
{@const Pyramid_0 = constructors[0]}
|
||||
<!-- svelte-ignore binding_property_non_reactive -->
|
||||
<Pyramid_0 bind:this={components[0]} data={data_0} {form} />
|
||||
|
||||
{/if}
|
||||
|
||||
{#if mounted}
|
||||
<div id="svelte-announcer" aria-live="assertive" aria-atomic="true" style="position: absolute; left: 0; top: 0; clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden; white-space: nowrap; width: 1px; height: 1px">
|
||||
{#if navigated}
|
||||
{title}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
|
@ -1,34 +0,0 @@
|
|||
|
||||
import root from '../root.js';
|
||||
import { set_building, set_prerendering } from '__sveltekit/environment';
|
||||
import { set_assets } from '__sveltekit/paths';
|
||||
import { set_manifest, set_read_implementation } from '__sveltekit/server';
|
||||
import { set_private_env, set_public_env, set_safe_public_env } from '../../../node_modules/.pnpm/@sveltejs+kit@2.8.0_@sveltejs+vite-plugin-svelte@4.0.0_svelte@5.1.15_vite@5.4.11__svelte@5.1.15_vite@5.4.11/node_modules/@sveltejs/kit/src/runtime/shared-server.js';
|
||||
|
||||
export const options = {
|
||||
app_dir: "_app",
|
||||
app_template_contains_nonce: false,
|
||||
csp: {"mode":"auto","directives":{"upgrade-insecure-requests":false,"block-all-mixed-content":false},"reportOnly":{"upgrade-insecure-requests":false,"block-all-mixed-content":false}},
|
||||
csrf_check_origin: true,
|
||||
embedded: false,
|
||||
env_public_prefix: 'PUBLIC_',
|
||||
env_private_prefix: '',
|
||||
hooks: null, // added lazily, via `get_hooks`
|
||||
preload_strategy: "modulepreload",
|
||||
root,
|
||||
service_worker: false,
|
||||
templates: {
|
||||
app: ({ head, body, assets, nonce, env }) => "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<link rel=\"icon\" href=\"" + assets + "/favicon.png\" />\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\t\t" + head + "\n\t</head>\n\t<body data-sveltekit-preload-data=\"hover\">\n\t\t<div style=\"display: contents\">" + body + "</div>\n\t</body>\n</html>\n",
|
||||
error: ({ status, message }) => "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>" + message + "</title>\n\n\t\t<style>\n\t\t\tbody {\n\t\t\t\t--bg: white;\n\t\t\t\t--fg: #222;\n\t\t\t\t--divider: #ccc;\n\t\t\t\tbackground: var(--bg);\n\t\t\t\tcolor: var(--fg);\n\t\t\t\tfont-family:\n\t\t\t\t\tsystem-ui,\n\t\t\t\t\t-apple-system,\n\t\t\t\t\tBlinkMacSystemFont,\n\t\t\t\t\t'Segoe UI',\n\t\t\t\t\tRoboto,\n\t\t\t\t\tOxygen,\n\t\t\t\t\tUbuntu,\n\t\t\t\t\tCantarell,\n\t\t\t\t\t'Open Sans',\n\t\t\t\t\t'Helvetica Neue',\n\t\t\t\t\tsans-serif;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tjustify-content: center;\n\t\t\t\theight: 100vh;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t.error {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tmax-width: 32rem;\n\t\t\t\tmargin: 0 1rem;\n\t\t\t}\n\n\t\t\t.status {\n\t\t\t\tfont-weight: 200;\n\t\t\t\tfont-size: 3rem;\n\t\t\t\tline-height: 1;\n\t\t\t\tposition: relative;\n\t\t\t\ttop: -0.05rem;\n\t\t\t}\n\n\t\t\t.message {\n\t\t\t\tborder-left: 1px solid var(--divider);\n\t\t\t\tpadding: 0 0 0 1rem;\n\t\t\t\tmargin: 0 0 0 1rem;\n\t\t\t\tmin-height: 2.5rem;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t}\n\n\t\t\t.message h1 {\n\t\t\t\tfont-weight: 400;\n\t\t\t\tfont-size: 1em;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t@media (prefers-color-scheme: dark) {\n\t\t\t\tbody {\n\t\t\t\t\t--bg: #222;\n\t\t\t\t\t--fg: #ddd;\n\t\t\t\t\t--divider: #666;\n\t\t\t\t}\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div class=\"error\">\n\t\t\t<span class=\"status\">" + status + "</span>\n\t\t\t<div class=\"message\">\n\t\t\t\t<h1>" + message + "</h1>\n\t\t\t</div>\n\t\t</div>\n\t</body>\n</html>\n"
|
||||
},
|
||||
version_hash: "1vvcu4z"
|
||||
};
|
||||
|
||||
export async function get_hooks() {
|
||||
return {
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
export { set_assets, set_building, set_manifest, set_prerendering, set_private_env, set_public_env, set_read_implementation, set_safe_public_env };
|
25
packages/.svelte-kit/non-ambient.d.ts
vendored
25
packages/.svelte-kit/non-ambient.d.ts
vendored
|
@ -1,25 +0,0 @@
|
|||
|
||||
// this file is generated — do not edit it
|
||||
|
||||
|
||||
declare module "svelte/elements" {
|
||||
export interface HTMLAttributes<T> {
|
||||
'data-sveltekit-keepfocus'?: true | '' | 'off' | undefined | null;
|
||||
'data-sveltekit-noscroll'?: true | '' | 'off' | undefined | null;
|
||||
'data-sveltekit-preload-code'?:
|
||||
| true
|
||||
| ''
|
||||
| 'eager'
|
||||
| 'viewport'
|
||||
| 'hover'
|
||||
| 'tap'
|
||||
| 'off'
|
||||
| undefined
|
||||
| null;
|
||||
'data-sveltekit-preload-data'?: true | '' | 'hover' | 'tap' | 'off' | undefined | null;
|
||||
'data-sveltekit-reload'?: true | '' | 'off' | undefined | null;
|
||||
'data-sveltekit-replacestate'?: true | '' | 'off' | undefined | null;
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
|
@ -1,49 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"$lib": [
|
||||
"../src/lib"
|
||||
],
|
||||
"$lib/*": [
|
||||
"../src/lib/*"
|
||||
]
|
||||
},
|
||||
"rootDirs": [
|
||||
"..",
|
||||
"./types"
|
||||
],
|
||||
"verbatimModuleSyntax": true,
|
||||
"isolatedModules": true,
|
||||
"lib": [
|
||||
"esnext",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"moduleResolution": "bundler",
|
||||
"module": "esnext",
|
||||
"noEmit": true,
|
||||
"target": "esnext"
|
||||
},
|
||||
"include": [
|
||||
"ambient.d.ts",
|
||||
"non-ambient.d.ts",
|
||||
"./types/**/$types.d.ts",
|
||||
"../vite.config.js",
|
||||
"../vite.config.ts",
|
||||
"../src/**/*.js",
|
||||
"../src/**/*.ts",
|
||||
"../src/**/*.svelte",
|
||||
"../tests/**/*.js",
|
||||
"../tests/**/*.ts",
|
||||
"../tests/**/*.svelte"
|
||||
],
|
||||
"exclude": [
|
||||
"../node_modules/**",
|
||||
"../src/service-worker.js",
|
||||
"../src/service-worker/**/*.js",
|
||||
"../src/service-worker.ts",
|
||||
"../src/service-worker/**/*.ts",
|
||||
"../src/service-worker.d.ts",
|
||||
"../src/service-worker/**/*.d.ts"
|
||||
]
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
import prettier from 'eslint-config-prettier';
|
||||
import js from '@eslint/js';
|
||||
import svelte from 'eslint-plugin-svelte';
|
||||
import globals from 'globals';
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
js.configs.recommended,
|
||||
...svelte.configs['flat/recommended'],
|
||||
prettier,
|
||||
...svelte.configs['flat/prettier'],
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
ignores: ['build/', '.svelte-kit/', 'dist/']
|
||||
}
|
||||
];
|
|
@ -7,7 +7,7 @@
|
|||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"format": "prettier --write .",
|
||||
"lint": "prettier --check . && eslint .",
|
||||
"lint": "prettier --check .",
|
||||
"test:unit": "vitest",
|
||||
"test": "npm run test:unit -- --run"
|
||||
},
|
||||
|
@ -15,10 +15,6 @@
|
|||
"@sveltejs/adapter-auto": "^3.0.0",
|
||||
"@sveltejs/kit": "^2.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
||||
"@types/eslint": "^9.6.0",
|
||||
"eslint": "^9.7.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-svelte": "^2.36.0",
|
||||
"globals": "^15.0.0",
|
||||
"mdsvex": "^0.11.2",
|
||||
"prettier": "^3.3.2",
|
||||
|
@ -26,5 +22,8 @@
|
|||
"svelte": "^5.0.0",
|
||||
"vite": "^5.0.3",
|
||||
"vitest": "^2.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": "^16.4.5"
|
||||
}
|
||||
}
|
||||
|
|
827
packages/pnpm-lock.yaml
generated
827
packages/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
34
packages/src/lib/components/loading.svelte
Normal file
34
packages/src/lib/components/loading.svelte
Normal file
|
@ -0,0 +1,34 @@
|
|||
<div class='overlay'></div>
|
||||
|
||||
<div class="wrap">
|
||||
<svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="10" height="10">
|
||||
<animate
|
||||
attributeName="rx"
|
||||
values="0;5;0"
|
||||
dur="1s"
|
||||
repeatCount="indefinite" />
|
||||
</rect>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.wrap {
|
||||
position: absolute;
|
||||
z-index: 51;
|
||||
opacity: 0.6;
|
||||
width: 3em;
|
||||
left: calc(50% - 3em);
|
||||
top: calc(50% - 2em);
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
z-index: 50;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--shade-loading);
|
||||
}
|
||||
</style>
|
111
packages/src/lib/components/modal.svelte
Normal file
111
packages/src/lib/components/modal.svelte
Normal file
|
@ -0,0 +1,111 @@
|
|||
<script>
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
let {
|
||||
showModal = false, wide = true, hideSidebar = false,
|
||||
enter, escape, children
|
||||
} = $props()
|
||||
|
||||
const handleKeydown = (e) => {
|
||||
if (showModal) {
|
||||
if (e.keyCode === 27) {
|
||||
escape()
|
||||
} else if (e.keyCode === 13) {
|
||||
enter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (showModal) {
|
||||
window.addEventListener("keydown", handleKeydown)
|
||||
} else {
|
||||
window.removeEventListener("keydown", handleKeydown)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if showModal}
|
||||
<div class='modal'>
|
||||
<div class="overlay" role='button' tabindex='0' onclick={() => escape()} onkeydown={() => escape()}>
|
||||
<div
|
||||
class="dark"
|
||||
role='button'
|
||||
tabindex='0'
|
||||
class:narrow={!wide}
|
||||
class:hidden={hideSidebar}
|
||||
onclick={() => escape()}
|
||||
onkeydown={() => escape()}
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<div class="wrap">
|
||||
{@render children?.()}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.modal {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
z-index: 100;
|
||||
margin: auto 1em;
|
||||
background-color: var(--theme-background);
|
||||
border: solid thin var(--theme-color);
|
||||
border-radius: 10px;
|
||||
padding: 1em;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
z-index: 50;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.overlay .dark {
|
||||
margin-top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--shade-background);
|
||||
}
|
||||
|
||||
.overlay .dark::before {
|
||||
content: "";
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
left: 0;
|
||||
background-color: var(--shade-background);
|
||||
border-radius: 40px 40px 0 0;
|
||||
}
|
||||
|
||||
.overlay .dark.narrow::before {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.overlay .dark.hidden::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (min-width: 45em) {
|
||||
.wrap {
|
||||
margin: auto;
|
||||
padding: 1em 3em;
|
||||
width: unset;
|
||||
}
|
||||
}
|
||||
</style>
|
65
packages/src/lib/components/nav-bar.svelte
Normal file
65
packages/src/lib/components/nav-bar.svelte
Normal file
|
@ -0,0 +1,65 @@
|
|||
<script>
|
||||
import { goto } from '$app/navigation'
|
||||
</script>
|
||||
|
||||
<nav class='nav-bar'>
|
||||
<div class='cluster nav-left'>
|
||||
<ul>
|
||||
<li><button onclick={() => goto('/')}>Home</button></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class='cluster nav-right'>
|
||||
<ul>
|
||||
<li><button onclick={() => goto('/dashboard')}>Dashboard</button></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<style>
|
||||
.nav-bar {
|
||||
height: var(--navbar-height);
|
||||
display: flex;
|
||||
background: var(--theme-background);
|
||||
border-bottom: solid thin var(--border-color);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.cluster ul {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.cluster li {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.nav-left {
|
||||
margin: 0 auto 0 0;
|
||||
}
|
||||
|
||||
.nav-right {
|
||||
margin: 0 0 0 auto;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
background: transparent;
|
||||
color: var(--theme-color);
|
||||
border: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 1em;
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
|
@ -1 +0,0 @@
|
|||
// place files you want to import through the `$lib` alias in this folder.
|
79
packages/src/lib/utils/tahoe.js
Normal file
79
packages/src/lib/utils/tahoe.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
import { env } from '$env/dynamic/private'
|
||||
|
||||
export const createAlias = () => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const url = `${env.TAHOE_API}/uri?t=mkdir`
|
||||
const response = await fetch(url, { method: 'POST' })
|
||||
const capKey = await response.json()
|
||||
|
||||
return resolve({ capKey })
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const listDirectories = (capKey) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const url = `${env.TAHOE_API}/uri/${capKey}?t=json`
|
||||
const response = await fetch(url, { method: 'GET' })
|
||||
const list = await response.json()
|
||||
|
||||
return resolve({ list })
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const createDirectory = (path, dirName) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const url = `${env.TAHOE_API}/uri/${path}?t=mkdir&name=${dirName}`
|
||||
const response = await fetch(url, { method: 'POST' })
|
||||
|
||||
if (response.status !== 200) {
|
||||
return json({ success: false, status: response.status, message: response.statusText })
|
||||
}
|
||||
|
||||
const cap = await response.json()
|
||||
|
||||
return resolve({ cap })
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const uploadFile = (path, file) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const url = `${env.TAHOE_API}/uri/${path}`
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'PUT',
|
||||
body: file
|
||||
})
|
||||
|
||||
return resolve()
|
||||
} catch (error) {
|
||||
console.log({ error })
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const unlink = (path) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const url = `${env.TAHOE_API}/uri/${path}`
|
||||
const response = await fetch(url, { method: 'DELETE' })
|
||||
|
||||
return resolve()
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
25
packages/src/routes/+error.svelte
Normal file
25
packages/src/routes/+error.svelte
Normal file
|
@ -0,0 +1,25 @@
|
|||
<script>
|
||||
import { page } from '$app/stores'
|
||||
</script>
|
||||
|
||||
<div class='error-page'>
|
||||
<h1>Private facts</h1>
|
||||
|
||||
<h2>Oops... Something went wrong!</h2>
|
||||
|
||||
{#if $page.status === 401}
|
||||
<h3>Error {$page.status}: {$page.error?.message}</h3>
|
||||
<p>
|
||||
Go to <a href="/auth/login">log in</a> page.
|
||||
</p>
|
||||
{:else}
|
||||
<h3>{$page.status}: {$page.error?.message}</h3>
|
||||
<p>We are looking into it.</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.error-page {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
73
packages/src/routes/+layout.svelte
Normal file
73
packages/src/routes/+layout.svelte
Normal file
|
@ -0,0 +1,73 @@
|
|||
<script>
|
||||
import NavBar from '$lib/components/nav-bar.svelte'
|
||||
</script>
|
||||
|
||||
<div class='content'>
|
||||
<NavBar />
|
||||
|
||||
<slot></slot>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--border-color: #aaa;
|
||||
--button-color: #f6f6f6;
|
||||
--font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif;
|
||||
--navbar-height: 3em;
|
||||
--shade-background: rgba(0, 0, 0, 0.2);
|
||||
--shade-color: #eee;
|
||||
--shade-loading: rgba(0, 0, 0, 0.3);
|
||||
--theme-background: white;
|
||||
--theme-color: #444;
|
||||
}
|
||||
|
||||
.content {
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
height: calc(100vh - 6em);
|
||||
max-width: 60em;
|
||||
overflow: clip;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
:global(body) {
|
||||
margin: 0;
|
||||
font-family: var(--font-family);
|
||||
font-weight: 400;
|
||||
background: var(--theme-background);
|
||||
color: var(--theme-color);
|
||||
overflow: clip;
|
||||
}
|
||||
|
||||
:global(button) {
|
||||
margin: 1em;
|
||||
width: 10em;
|
||||
height: 2.5em;
|
||||
font-family: var(--font-family-text);
|
||||
font-weight: 200;
|
||||
font-size: 16px;
|
||||
background: var(--button-color);
|
||||
border: solid thin;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
:global(button:hover) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
:global(button:disabled) {
|
||||
background-color: light-dark(rgba(239, 239, 239, 0.3), rgba(19, 1, 1, 0.3));
|
||||
color: light-dark(rgba(16, 16, 16, 0.3), rgba(255, 255, 255, 0.3));
|
||||
border-color: light-dark(rgba(118, 118, 118, 0.3), rgba(195, 195, 195, 0.3));
|
||||
}
|
||||
|
||||
:global(input) {
|
||||
font-size: 0.9em;
|
||||
font-weight: 400;
|
||||
padding: 0 1em;
|
||||
height: 3em;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
outline: solid thin var(--border-color);
|
||||
}
|
||||
</style>
|
|
@ -1,2 +1,14 @@
|
|||
<h1>Welcome to SvelteKit</h1>
|
||||
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
|
||||
<script>
|
||||
import { goto } from '$app/navigation'
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Home page</title>
|
||||
<meta name='description' content='Home page'/>
|
||||
</svelte:head>
|
||||
|
||||
<div class='landing-page'>
|
||||
<h1>Private facts</h1>
|
||||
|
||||
<button onclick={() => goto('/dashboard')}>Dashboard</button>
|
||||
</div>
|
||||
|
|
102
packages/src/routes/dashboard/+page.server.js
Normal file
102
packages/src/routes/dashboard/+page.server.js
Normal file
|
@ -0,0 +1,102 @@
|
|||
import { fail } from '@sveltejs/kit'
|
||||
import { createAlias, createDirectory, listDirectories, unlink, uploadFile } from '$lib/utils/tahoe'
|
||||
|
||||
export const actions = {
|
||||
createCapKey: async ({ request, fetch }) => {
|
||||
try {
|
||||
const { capKey } = await createAlias()
|
||||
|
||||
return { endpoint: 'createCapKey', capKey }
|
||||
} catch (error) {
|
||||
console.log({ error })
|
||||
return fail(500, { endpoint: 'createCapKey', error })
|
||||
}
|
||||
},
|
||||
|
||||
listDirectories: async ({ request, fetch }) => {
|
||||
const formData = await request.formData()
|
||||
const capKey = formData.get('capKeyInput')
|
||||
const encoded = encodeURIComponent(capKey)
|
||||
|
||||
try {
|
||||
const { list } = await listDirectories(capKey)
|
||||
|
||||
return { endpoint: 'listDirectories', list, capKey }
|
||||
} catch (error) {
|
||||
if (error.cause.message.includes('ECONNREFUSED')) {
|
||||
return { error: 'Tahoe server may be offline.' }
|
||||
}
|
||||
|
||||
console.log({ error })
|
||||
return fail(500, { endpoint: 'listDirectories', error })
|
||||
}
|
||||
},
|
||||
|
||||
createDirectory: async ({ request, fetch }) => {
|
||||
const formData = await request.formData()
|
||||
const capKey = formData.get('capKey')
|
||||
const encoded = encodeURIComponent(capKey)
|
||||
const dirName= formData.get('dirName')
|
||||
let path = formData.get('path')
|
||||
|
||||
if (path.length === 0) path = '/'
|
||||
if (path.slice(0, 1) !== '/') path = '/' + path
|
||||
if (path.slice(-1) !== '/') path = path + '/'
|
||||
|
||||
path = encoded + encodeURI(path)
|
||||
|
||||
try {
|
||||
const { cap } = await createDirectory(path, dirName)
|
||||
|
||||
return { success: true, endpoint: 'uploadFile' }
|
||||
} catch (error) {
|
||||
console.log({ error })
|
||||
return fail(500, { endpoint: 'uploadFile', error})
|
||||
}
|
||||
},
|
||||
|
||||
uploadFile: async ({ request, fetch }) => {
|
||||
const formData = await request.formData()
|
||||
const capKey = formData.get('capKey')
|
||||
const encoded = encodeURIComponent(capKey)
|
||||
const file = formData.get('file')
|
||||
let path = formData.get('path')
|
||||
|
||||
if (path.length === 0) path = '/'
|
||||
if (path.slice(0, 1) !== '/') path = '/' + path
|
||||
if (path.slice(-1) !== '/') path = path + '/'
|
||||
|
||||
path = encoded + encodeURI(path + file.name)
|
||||
|
||||
try {
|
||||
await uploadFile(path, file.name, file)
|
||||
|
||||
return { success: true, endpoint: 'uploadFile' }
|
||||
} catch (error) {
|
||||
console.log({ error })
|
||||
return fail(500, { endpoint: 'uploadFile', error})
|
||||
}
|
||||
},
|
||||
|
||||
deletePath: async ({ request, fetch }) => {
|
||||
const formData = await request.formData()
|
||||
const capKey = formData.get('capKey')
|
||||
const encoded = encodeURIComponent(capKey)
|
||||
const partialPath = formData.get('path')
|
||||
const slash = partialPath.slice(0, 1) === '/' ? '' : '/'
|
||||
const path = encoded + slash + partialPath
|
||||
|
||||
if (partialPath.length === 0) {
|
||||
return { success: false, endpoint: 'deletePath', error: 'Path cannot be empty.'}
|
||||
}
|
||||
|
||||
try {
|
||||
await unlink(path)
|
||||
|
||||
return { success: true, endpoint: 'deletePath' }
|
||||
} catch (error) {
|
||||
console.log({ error })
|
||||
return json({ success: false, code: 500, error })
|
||||
}
|
||||
}
|
||||
}
|
293
packages/src/routes/dashboard/+page.svelte
Normal file
293
packages/src/routes/dashboard/+page.svelte
Normal file
|
@ -0,0 +1,293 @@
|
|||
<script>
|
||||
import { enhance } from '$app/forms'
|
||||
import { beforeNavigate } from '$app/navigation'
|
||||
import Loading from '$lib/components/loading.svelte'
|
||||
import Modal from '$lib/components/modal.svelte'
|
||||
import { fade } from 'svelte/transition'
|
||||
|
||||
let { form } = $props()
|
||||
let capKey = $state()
|
||||
let capKeyInput = $state()
|
||||
let list = $state()
|
||||
let listForm = $state()
|
||||
let modalTitle = $state()
|
||||
let modalText = $state()
|
||||
let newCapKey = $state()
|
||||
let checked = $state(false)
|
||||
let loading = $state(false)
|
||||
let showModal = $state(false)
|
||||
let showDelModal = $state(false)
|
||||
let showUploadModal = $state(false)
|
||||
let showAddFolderModal = $state(false)
|
||||
|
||||
|
||||
const submitKey = () => {
|
||||
capKey = capKeyInput
|
||||
}
|
||||
|
||||
const persistCapKey = () => {
|
||||
capKey = newCapKey
|
||||
newCapKey = undefined
|
||||
}
|
||||
|
||||
const enhanceForm = () => {
|
||||
showDelModal = false
|
||||
showUploadModal = false
|
||||
showAddFolderModal = false
|
||||
loading = true
|
||||
|
||||
return async ({ result, update }) => {
|
||||
await update()
|
||||
loading = false
|
||||
|
||||
if (result.status === 200) {
|
||||
switch (result.data.endpoint) {
|
||||
case 'createCapKey': {
|
||||
newCapKey = result.data.capKey
|
||||
break
|
||||
}
|
||||
case 'listDirectories': {
|
||||
capKey = result.data.capKey
|
||||
list = result.data.list
|
||||
break
|
||||
}
|
||||
case 'uploadFile': {
|
||||
listForm.requestSubmit()
|
||||
break
|
||||
}
|
||||
case 'deletePath': {
|
||||
listForm.requestsubmit()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
beforeNavigate(({ cancel }) => {
|
||||
if (newCapKey && !capKey) {
|
||||
cancel()
|
||||
modalTitle = 'Warning'
|
||||
modalText = 'Please confirm you copied and saved the cap key.'
|
||||
showModal = true
|
||||
}
|
||||
})
|
||||
|
||||
// Store cap key in a variable for use while current page
|
||||
// is on screen
|
||||
$effect(() => {
|
||||
if (form?.capKey) capKey = form.capKey
|
||||
})
|
||||
|
||||
// Show errors
|
||||
$effect(() => {
|
||||
if (form?.error) {
|
||||
modalTitle = 'Error'
|
||||
modalText = form.error
|
||||
showModal = true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Private Facts dashboard</title>
|
||||
<meta name='description' content='Private Facts dashboard.'>
|
||||
</svelte:head>
|
||||
|
||||
{#if loading}
|
||||
<div class='loader' transition:fade|local>
|
||||
<Loading />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<h1>Dashboard</h1>
|
||||
|
||||
{#if !capKey && !newCapKey}
|
||||
<div class='cap-key-div add'>
|
||||
<form action='?/listDirectories' method='post' enctype='form-data' use:enhance={enhanceForm} bind:this={listForm}>
|
||||
<label for='capKeyInput'>Cap key:</label>
|
||||
<input type='text' name='capKeyInput' value={capKey} />
|
||||
|
||||
<button type='submit'>Submit</button>
|
||||
</form>
|
||||
|
||||
<form action='?/createCapKey' method='post' enctype='form-data' use:enhance={enhanceForm}>
|
||||
<button type='submit'>New cap key</button>
|
||||
</form>
|
||||
</div>
|
||||
{:else if !capKey && newCapKey}
|
||||
<div class='cap-key-div get'>
|
||||
<label for='newCapKey'><h2>New cap key</h2></label>
|
||||
<input type='text' id='newCapKey' name='newCapKey' value={newCapKey} />
|
||||
|
||||
<div class='warning'>
|
||||
<h3>Attention!</h3>
|
||||
|
||||
<p>This is your new cap key. You need it to access your folders and files. It will not be saved nor ever shown again.</p>
|
||||
|
||||
<p><strong>Copy it now and save it somewhere safe.</strong></p>
|
||||
|
||||
<p>If you lose your cap key you will not be able to access your files anymore. You will have to create a new cap key and upload new files and folders.</p>
|
||||
|
||||
<div class='confirm-copy'>
|
||||
<input type='checkbox' id='checkbox' name='checkbox' bind:checked />
|
||||
<label for='copyCheckbox'>Copied and saved.</label>
|
||||
</div>
|
||||
|
||||
<button disabled={!checked} onclick={persistCapKey}>Ok</button>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<h2>File tree</h2>
|
||||
|
||||
{#if list}
|
||||
<ul>
|
||||
{#each Object.keys(list[1].children) as item}
|
||||
<li>{item}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{/if}
|
||||
|
||||
<button onclick={() => showAddFolderModal = true}>Add folder</button>
|
||||
<button onclick={() => showUploadModal = true}>Upload file</button>
|
||||
<button onclick={() => showDelModal = true}>Unlink file / folder</button>
|
||||
<button onclick={() => capKey = undefined}>Change cap key</button>
|
||||
{/if}
|
||||
|
||||
<!-- Modals -->
|
||||
|
||||
<Modal {showModal} escape={() => showModal = false}>
|
||||
<h2>{modalTitle}</h2>
|
||||
<p>{modalText}</p>
|
||||
<button onclick={() => showModal = false}>Ok</button>
|
||||
</Modal>
|
||||
|
||||
<Modal showModal={showDelModal} escape={() => showDelModal = false}>
|
||||
<h2>Unlink</h2>
|
||||
<p>Specify path of file or folder to unlink.</p>
|
||||
<p>Ex.: /Documents/File-1.txt</p>
|
||||
|
||||
<form action='?/deletePath' method='post' enctype='form-data' use:enhance={enhanceForm}>
|
||||
<input type='hidden' name='capKey' value={capKey} />
|
||||
|
||||
<label for='path'>Path:</label>
|
||||
<input type='text' name='path' class='path-input' />
|
||||
|
||||
<div class='form-actions'>
|
||||
<button onclick={() => showDelModal = false}>Cancel</button>
|
||||
<button type='submit'>Confirm</button>
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
|
||||
<Modal showModal={showUploadModal} escape={() => showUploadModal = false}>
|
||||
<h2>Upload file</h2>
|
||||
|
||||
<form action='?/uploadFile' method='post' enctype='multipart/form-data' use:enhance={enhanceForm}>
|
||||
<input type='hidden' name='capKey' value={capKey} />
|
||||
|
||||
<div class='file-input'>
|
||||
<label for='file'>File:</label>
|
||||
<input type='file' name='file' placeholder='file' required />
|
||||
</div>
|
||||
|
||||
<label for='path'>Path:</label>
|
||||
<input type='text' name='path' class='path-input' />
|
||||
|
||||
<div class='form-actions'>
|
||||
<button onclick={() => showUploadModal = false}>Cancel</button>
|
||||
<button type='submit'>Upload</button>
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
|
||||
<Modal showModal={showAddFolderModal} escape={() => showAddFolderModal = false}>
|
||||
<h2>Add folder</h2>
|
||||
|
||||
<form action='?/createDirectory' method='post' enctype='form-data' use:enhance={enhanceForm}>
|
||||
<input type='hidden' name='capKey' value={capKey} />
|
||||
|
||||
<div class='new-folder-input'>
|
||||
<label for='dirName'>New folder name:</label>
|
||||
<input type='text' name='dirName' />
|
||||
|
||||
<label for='path'>Path:</label>
|
||||
<input type='text' name='path' />
|
||||
</div>
|
||||
|
||||
<div class='form-actions'>
|
||||
<button onclick={() => showAddFolderModal = false}>Cancel</button>
|
||||
<button type='submit'>Confirm</button>
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
|
||||
<style>
|
||||
.cap-key-div form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.cap-key-div form button {
|
||||
margin: 0 0 1em auto;
|
||||
}
|
||||
|
||||
form input {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.cap-key-div {
|
||||
max-width: 45em;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.cap-key-div.get {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.confirm-copy {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.confirm-copy input {
|
||||
height: unset;
|
||||
margin-right: 1em;
|
||||
border: solid thin var(--border-color);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.warning {
|
||||
border: solid thin var(--border-color);
|
||||
border-radius: 10px;
|
||||
background-color: var(--shade-color);
|
||||
padding: 0.5em;
|
||||
margin: 2em auto;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
text-align: left;
|
||||
background: var(--shade-color);
|
||||
padding: 1em;
|
||||
border: solid thin var(--border-color);
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.path-input {
|
||||
width: 30em;
|
||||
}
|
||||
|
||||
.new-folder-input {
|
||||
text-align: left;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
|
@ -2,9 +2,19 @@ import { defineConfig } from 'vitest/config';
|
|||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()],
|
||||
plugins: [sveltekit()],
|
||||
|
||||
test: {
|
||||
include: ['src/**/*.{test,spec}.{js,ts}']
|
||||
}
|
||||
server:{
|
||||
port:5555,
|
||||
strictPort:false,
|
||||
},
|
||||
|
||||
preview:{
|
||||
port:5554,
|
||||
strictPort:false,
|
||||
},
|
||||
|
||||
test: {
|
||||
include: ['src/**/*.{test,spec}.{js,ts}']
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue