mirror of
https://github.com/cupcakearmy/cryptgeon.git
synced 2026-09-27 13:01:46 +00:00
Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ef162bd83 | ||
|
|
282fdb97d1 | ||
|
|
4dfed492bc | ||
|
|
5084ed59f0 | ||
|
|
055a48a38d | ||
|
|
d1126ace82 | ||
|
|
b58bf8af6d | ||
|
|
a57ead61b9 | ||
|
|
0d597edfee | ||
|
|
7653409473 | ||
|
|
f05707e033 | ||
|
|
8df6b6c7b5 | ||
|
|
2dc9d6aa16 | ||
|
|
98c56f6fb9 |
@@ -34,6 +34,9 @@ jobs:
|
|||||||
- name: Shared tests
|
- name: Shared tests
|
||||||
run: pnpm --filter @cryptgeon/shared test
|
run: pnpm --filter @cryptgeon/shared test
|
||||||
|
|
||||||
|
- name: Frontend type check
|
||||||
|
run: pnpm --filter @cryptgeon/web check
|
||||||
|
|
||||||
- name: Run your tests
|
- name: Run your tests
|
||||||
run: pnpm test
|
run: pnpm test
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -11,13 +11,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
- New shared TypeScript package `@cryptgeon/shared` as single source of truth for crypto, content codec and API client (crypto + compression + payload + types).
|
- New shared TypeScript package `@cryptgeon/shared` as single source of truth for crypto, content codec and API client (crypto + compression + payload + types).
|
||||||
- Shared payload codec: `packContent` / `unpackContent` (encode → LZ4 → XChaCha20-Poly1305 and reverse).
|
- Shared payload codec: `packContent` / `unpackContent` (encode → LZ4 → XChaCha20-Poly1305 and reverse).
|
||||||
- New `pg`-backend storage of note hashes in the cache.
|
- Cache-backed note storage using hashes (valkey/redis) with atomic view counting.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Encryption from AES to **XChaCha20-Poly1305** (client-side); dropped `occulto`.
|
- Encryption from AES to **XChaCha20-Poly1305** (client-side); dropped `occulto`.
|
||||||
- All API bodies switched to **MessagePack**.
|
- All API bodies switched to **MessagePack**.
|
||||||
- Frontend migrated to SvelteKit + `@cryptgeon/shared`.
|
- Frontend uses `@cryptgeon/shared` for crypto + payload codec (replacing the previous local `cryptgeon/shared`); heavy pack/unpack runs in a web worker.
|
||||||
- CLI rebuilt with `vite-plus` (bundles all deps) and imports from `@cryptgeon/shared`.
|
- CLI rebuilt with `vite-plus` (bundles all deps) and imports from `@cryptgeon/shared`.
|
||||||
|
|
||||||
### Breaking changes
|
### Breaking changes
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ services:
|
|||||||
- /data
|
- /data
|
||||||
|
|
||||||
app:
|
app:
|
||||||
image: cupcakearmy/cryptgeon:latest
|
image: cupcakearmy/cryptgeon:v3
|
||||||
depends_on:
|
depends_on:
|
||||||
- cache
|
- cache
|
||||||
environment:
|
environment:
|
||||||
@@ -169,6 +169,10 @@ See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|||||||
|
|
||||||
Please refer to the security section [here](./SECURITY.md).
|
Please refer to the security section [here](./SECURITY.md).
|
||||||
|
|
||||||
|
## Usage of LLMs
|
||||||
|
|
||||||
|
Starting from V3, I used LLMs heavily to implement _my own ideas_. This means that the direction and architecture choices are human. A lot of the implementation that derives from that, is automated with an LLM.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
_Attributions_
|
_Attributions_
|
||||||
|
|||||||
+5
-1
@@ -103,7 +103,7 @@ services:
|
|||||||
- /data
|
- /data
|
||||||
|
|
||||||
app:
|
app:
|
||||||
image: cupcakearmy/cryptgeon:latest
|
image: cupcakearmy/cryptgeon:v3
|
||||||
depends_on:
|
depends_on:
|
||||||
- cache
|
- cache
|
||||||
environment:
|
environment:
|
||||||
@@ -151,6 +151,10 @@ Ver [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|||||||
|
|
||||||
Por favor dirígete a la sección de seguridad [aquí](./SECURITY.md).
|
Por favor dirígete a la sección de seguridad [aquí](./SECURITY.md).
|
||||||
|
|
||||||
|
## Uso de LLMs
|
||||||
|
|
||||||
|
A partir de la V3, utilicé LLMs de forma intensiva para implementar _mis propias ideas_. Esto significa que la dirección y las decisiones de arquitectura son humanas. Gran parte de la implementación que deriva de eso está automatizada con un LLM.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
_Atribuciones_
|
_Atribuciones_
|
||||||
|
|||||||
+6
-2
@@ -91,7 +91,7 @@ services:
|
|||||||
- /data
|
- /data
|
||||||
|
|
||||||
app:
|
app:
|
||||||
image: cupcakearmy/cryptgeon:latest
|
image: cupcakearmy/cryptgeon:v3
|
||||||
depends_on:
|
depends_on:
|
||||||
- cache
|
- cache
|
||||||
environment:
|
environment:
|
||||||
@@ -131,7 +131,7 @@ services:
|
|||||||
- /data
|
- /data
|
||||||
|
|
||||||
app:
|
app:
|
||||||
image: cupcakearmy/cryptgeon:latest
|
image: cupcakearmy/cryptgeon:v3
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- cache
|
- cache
|
||||||
@@ -149,6 +149,10 @@ services:
|
|||||||
|
|
||||||
参见 [CONTRIBUTING.md](./CONTRIBUTING.md)。
|
参见 [CONTRIBUTING.md](./CONTRIBUTING.md)。
|
||||||
|
|
||||||
|
## LLM 的使用
|
||||||
|
|
||||||
|
从 V3 开始,我大量使用 LLM 来实现_我自己的想法_。这意味着项目的方向和架构选择均由人类决定。由此衍生的大部分实现由 LLM 自动完成。
|
||||||
|
|
||||||
###### Attributions
|
###### Attributions
|
||||||
|
|
||||||
- 测试数据:
|
- 测试数据:
|
||||||
|
|||||||
+2
-2
@@ -11,7 +11,7 @@ services:
|
|||||||
- /data
|
- /data
|
||||||
|
|
||||||
app:
|
app:
|
||||||
image: cupcakearmy/cryptgeon:latest
|
image: cupcakearmy/cryptgeon:v3
|
||||||
depends_on:
|
depends_on:
|
||||||
- cache
|
- cache
|
||||||
environment:
|
environment:
|
||||||
@@ -26,4 +26,4 @@ services:
|
|||||||
# interval: 1m
|
# interval: 1m
|
||||||
# timeout: 3s
|
# timeout: 3s
|
||||||
# retries: 2
|
# retries: 2
|
||||||
# start_period: 5s
|
# start_period: 5s
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
## Todo
|
## Todo
|
||||||
|
|
||||||
- Localize i18n readmes: `README_ES.md`, `README_zh-CN.md` still reference `REDIS` / `/api/v1`-era endpoint names — align to `CACHE` / `/healthz` (also sweep `CONTRIBUTING.md`, `examples/*`, postman collection).
|
|
||||||
- Add remaining shared tooling to the pnpm catalog (`vite`, `tsdown`).
|
- Add remaining shared tooling to the pnpm catalog (`vite`, `tsdown`).
|
||||||
- Move formatting, linting and type-checking + git hooks onto `vite-plus` (oxlint, oxfmt, vitest).
|
- Move formatting, linting and type-checking + git hooks onto `vite-plus` (oxlint, oxfmt, vitest).
|
||||||
- Re-add CSP (`Content-Security-Policy`) wired into the axum router (was in `csp.rs`, removed as unused).
|
- Re-add CSP (`Content-Security-Policy`) wired into the axum router (was in `csp.rs`, removed as unused).
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ services:
|
|||||||
- /data
|
- /data
|
||||||
|
|
||||||
app:
|
app:
|
||||||
image: cupcakearmy/cryptgeon:latest
|
image: cupcakearmy/cryptgeon:v3
|
||||||
depends_on:
|
depends_on:
|
||||||
- cache
|
- cache
|
||||||
|
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ services:
|
|||||||
- /data
|
- /data
|
||||||
|
|
||||||
app:
|
app:
|
||||||
image: cupcakearmy/cryptgeon:latest
|
image: cupcakearmy/cryptgeon:v3
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- cache
|
- cache
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ services:
|
|||||||
- /data
|
- /data
|
||||||
|
|
||||||
app:
|
app:
|
||||||
image: cupcakearmy/cryptgeon:latest
|
image: cupcakearmy/cryptgeon:v3
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- cache
|
- cache
|
||||||
@@ -70,7 +70,7 @@ services:
|
|||||||
- /data
|
- /data
|
||||||
|
|
||||||
cryptgeon:
|
cryptgeon:
|
||||||
image: cupcakearmy/cryptgeon
|
image: cupcakearmy/cryptgeon:v3
|
||||||
depends_on:
|
depends_on:
|
||||||
- cache
|
- cache
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
Generated
+1
-1
@@ -252,7 +252,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cryptgeon"
|
name = "cryptgeon"
|
||||||
version = "3.0.0-rc.1"
|
version = "3.0.0-rc.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"bs62",
|
"bs62",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cryptgeon"
|
name = "cryptgeon"
|
||||||
version = "3.0.0-rc.1"
|
version = "3.0.0-rc.4"
|
||||||
authors = ["cupcakearmy <hi@nicco.io>"]
|
authors = ["cupcakearmy <hi@nicco.io>"]
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
rust-version = "1.95"
|
rust-version = "1.95"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cryptgeon",
|
"name": "cryptgeon",
|
||||||
"version": "3.0.0-rc.1",
|
"version": "3.0.0-rc.4",
|
||||||
"homepage": "https://github.com/cupcakearmy/cryptgeon",
|
"homepage": "https://github.com/cupcakearmy/cryptgeon",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -21,19 +21,19 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vp pack",
|
"build": "vp pack",
|
||||||
"dev": "vp pack --watch",
|
"dev": "vp pack --watch",
|
||||||
"prepublishOnly": "run-s build"
|
"prepublishOnly": "pnpm run build"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@commander-js/extra-typings": "^15.0.0",
|
||||||
"@cryptgeon/shared": "workspace:*",
|
"@cryptgeon/shared": "workspace:*",
|
||||||
"@msgpack/msgpack": "^3.1.3",
|
"@msgpack/msgpack": "^3.1.3",
|
||||||
"@commander-js/extra-typings": "^12.1.0",
|
|
||||||
"@tsconfig/strictest": "catalog:",
|
"@tsconfig/strictest": "catalog:",
|
||||||
"@types/inquirer": "^9.0.9",
|
"@types/inquirer": "^9.0.10",
|
||||||
"@types/node": "^22.15.3",
|
"@types/node": "^22.20.1",
|
||||||
"commander": "^12.1.0",
|
"commander": "^15.0.0",
|
||||||
"inquirer": "^9.3.8",
|
"inquirer": "^14.2.1",
|
||||||
"mime": "^4.1.0",
|
"mime": "^4.1.0",
|
||||||
"pretty-bytes": "^6.1.1",
|
"pretty-bytes": "^7.1.3",
|
||||||
"typescript": "catalog:",
|
"typescript": "catalog:",
|
||||||
"vite-plus": "catalog:"
|
"vite-plus": "catalog:"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,21 +13,22 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/adapter-static": "^3.0.10",
|
"@sveltejs/adapter-static": "^3.0.10",
|
||||||
"@sveltejs/kit": "^2.61.1",
|
"@sveltejs/kit": "^2.70.3",
|
||||||
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|
"@sveltejs/vite-plugin-svelte": "^7.3.0",
|
||||||
"@zerodevx/svelte-toast": "^0.9.6",
|
"@zerodevx/svelte-toast": "^0.9.6",
|
||||||
"license-checker-rseidelsohn": "^5.0.1",
|
"license-checker-rseidelsohn": "^5.0.1",
|
||||||
"svelte": "^5.55.9",
|
"svelte": "^5.57.0",
|
||||||
"svelte-check": "^4.4.8",
|
"svelte-check": "^4.7.6",
|
||||||
"svelte-intl-precompile": "^0.12.3",
|
"svelte-intl-precompile": "^0.12.3",
|
||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^6.0.3",
|
"typescript": "^6.0.3",
|
||||||
"vite": "^8.0.14"
|
"vite": "^8.2.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cryptgeon/shared": "workspace:*",
|
"@cryptgeon/shared": "workspace:*",
|
||||||
"@fontsource/fira-mono": "^5.2.7",
|
"@fontsource/fira-mono": "^5.3.0",
|
||||||
"pretty-bytes": "^7.1.0",
|
"comlink": "^4.4.2",
|
||||||
|
"pretty-bytes": "^7.1.3",
|
||||||
"uqr": "^0.1.3"
|
"uqr": "^0.1.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,11 +46,11 @@ async function downloadFile(file: FileDTO) {
|
|||||||
files = note.contents
|
files = note.contents
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
let download = $derived(() => {
|
function downloadAll() {
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
downloadFile(file)
|
downloadFile(file)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
let links = $derived(typeof note.contents === 'string' ? note.contents.match(RE_URL) : [])
|
let links = $derived(typeof note.contents === 'string' ? note.contents.match(RE_URL) : [])
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ async function downloadFile(file: FileDTO) {
|
|||||||
{/key}
|
{/key}
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
<Button onclick={download}>{$t('show.download_all')}</Button>
|
<Button onclick={downloadAll}>{$t('show.download_all')}</Button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {
|
import {
|
||||||
bytesToHex,
|
|
||||||
create as apiCreate,
|
create as apiCreate,
|
||||||
|
bytesToHex,
|
||||||
packContent,
|
packContent,
|
||||||
type ServerNote
|
type FileDTO,
|
||||||
|
type NoteInput,
|
||||||
|
type ServerNote,
|
||||||
} from '@cryptgeon/shared'
|
} from '@cryptgeon/shared'
|
||||||
import { t } from 'svelte-intl-precompile'
|
import { t } from 'svelte-intl-precompile'
|
||||||
import { blur } from 'svelte/transition'
|
import { blur } from 'svelte/transition'
|
||||||
|
import { transfer } from 'comlink'
|
||||||
|
|
||||||
import { status } from '$lib/stores/status'
|
import { status } from '$lib/stores/status'
|
||||||
import { notify } from '$lib/toast'
|
import { notify } from '$lib/toast'
|
||||||
@@ -15,10 +18,12 @@
|
|||||||
import FileUpload from '$lib/ui/FileUpload.svelte'
|
import FileUpload from '$lib/ui/FileUpload.svelte'
|
||||||
import Loader from '$lib/ui/Loader.svelte'
|
import Loader from '$lib/ui/Loader.svelte'
|
||||||
import MaxSize from '$lib/ui/MaxSize.svelte'
|
import MaxSize from '$lib/ui/MaxSize.svelte'
|
||||||
import PastedFilesPreview from '$lib/ui/PastedFilesPreview.svelte'
|
|
||||||
import Result, { type NoteResult } from '$lib/ui/NoteResult.svelte'
|
import Result, { type NoteResult } from '$lib/ui/NoteResult.svelte'
|
||||||
|
import PastedFilesPreview from '$lib/ui/PastedFilesPreview.svelte'
|
||||||
import Switch from '$lib/ui/Switch.svelte'
|
import Switch from '$lib/ui/Switch.svelte'
|
||||||
import TextArea from '$lib/ui/TextArea.svelte'
|
import TextArea from '$lib/ui/TextArea.svelte'
|
||||||
|
import { createWorker } from '$lib/worker'
|
||||||
|
import { onMount } from 'svelte'
|
||||||
|
|
||||||
let note: { views: number; expiration: number } = $state({ views: 1, expiration: 60 })
|
let note: { views: number; expiration: number } = $state({ views: 1, expiration: 60 })
|
||||||
let files: FileDTO[] = $state([])
|
let files: FileDTO[] = $state([])
|
||||||
@@ -53,6 +58,8 @@
|
|||||||
if (!isFile) textContent = ''
|
if (!isFile) textContent = ''
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const worker = createWorker()
|
||||||
|
|
||||||
async function handlePaste(e: ClipboardEvent) {
|
async function handlePaste(e: ClipboardEvent) {
|
||||||
const data = e.clipboardData
|
const data = e.clipboardData
|
||||||
if (!data) return
|
if (!data) return
|
||||||
@@ -123,13 +130,21 @@
|
|||||||
throw new EmptyContentError()
|
throw new EmptyContentError()
|
||||||
}
|
}
|
||||||
|
|
||||||
const payload = packContent(
|
const noteInput: NoteInput = isFile
|
||||||
isFile ? { type: 'files', files } : { type: 'text', text: textContent },
|
? transfer(
|
||||||
customPassword || undefined
|
{
|
||||||
)
|
type: 'files',
|
||||||
|
files: $state.snapshot(files),
|
||||||
|
},
|
||||||
|
files.map((f) => f.data.buffer)
|
||||||
|
)
|
||||||
|
: { type: 'text', text: textContent }
|
||||||
|
const payload = await worker.pack(noteInput, customPassword || undefined)
|
||||||
const serverNote: ServerNote = {
|
const serverNote: ServerNote = {
|
||||||
meta: {
|
meta: {
|
||||||
...(timeExpiration ? { expiration: parseInt(note.expiration as any) } : { views: parseInt(note.views as any) }),
|
...(timeExpiration
|
||||||
|
? { expiration: parseInt(note.expiration as any) }
|
||||||
|
: { views: parseInt(note.views as any) }),
|
||||||
extra: payload.extra,
|
extra: payload.extra,
|
||||||
},
|
},
|
||||||
data: payload.data,
|
data: payload.data,
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { wrap } from 'comlink'
|
||||||
|
|
||||||
|
import CryptWorker from './worker?worker'
|
||||||
|
import type { packContent, unpackContent } from '@cryptgeon/shared'
|
||||||
|
|
||||||
|
export function createWorker() {
|
||||||
|
const worker = new CryptWorker()
|
||||||
|
return wrap<WorkerConract>(worker)
|
||||||
|
}
|
||||||
|
|
||||||
|
export type WorkerConract = {
|
||||||
|
pack: typeof packContent
|
||||||
|
unpack: typeof unpackContent
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import type { WorkerConract } from '$lib/worker'
|
||||||
|
import { packContent, unpackContent } from '@cryptgeon/shared'
|
||||||
|
import { expose, transfer } from 'comlink'
|
||||||
|
|
||||||
|
const contract: WorkerConract = {
|
||||||
|
pack(input, password) {
|
||||||
|
const content = packContent(input, password)
|
||||||
|
return transfer(content, [content.data.buffer, content.extra.buffer, content.key.buffer])
|
||||||
|
},
|
||||||
|
unpack(data, key) {
|
||||||
|
return unpackContent(data, key)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expose(contract)
|
||||||
@@ -1,5 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { deriveKey, hexToBytes, decode, info, get as apiGet, unpackContent, type FileDTO } from '@cryptgeon/shared'
|
import {
|
||||||
|
deriveKey,
|
||||||
|
hexToBytes,
|
||||||
|
decode,
|
||||||
|
info,
|
||||||
|
get as apiGet,
|
||||||
|
unpackContent,
|
||||||
|
type FileDTO,
|
||||||
|
} from '@cryptgeon/shared'
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import { t } from 'svelte-intl-precompile'
|
import { t } from 'svelte-intl-precompile'
|
||||||
|
|
||||||
@@ -8,6 +16,7 @@
|
|||||||
import ShowNote, { type DecryptedNote } from '$lib/ui/ShowNote.svelte'
|
import ShowNote, { type DecryptedNote } from '$lib/ui/ShowNote.svelte'
|
||||||
import TextInput from '$lib/ui/TextInput.svelte'
|
import TextInput from '$lib/ui/TextInput.svelte'
|
||||||
import type { PageData } from './$types'
|
import type { PageData } from './$types'
|
||||||
|
import { createWorker } from '$lib/worker'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
data: PageData
|
data: PageData
|
||||||
@@ -44,6 +53,8 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const worker = createWorker()
|
||||||
|
|
||||||
async function show(e: SubmitEvent) {
|
async function show(e: SubmitEvent) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
try {
|
try {
|
||||||
@@ -69,7 +80,7 @@
|
|||||||
key = hexToBytes(password!)
|
key = hexToBytes(password!)
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = unpackContent(serverNote.data, key)
|
const content = await worker.unpack(serverNote.data, key)
|
||||||
|
|
||||||
switch (content.type) {
|
switch (content.type) {
|
||||||
case 'text':
|
case 'text':
|
||||||
@@ -78,16 +89,16 @@
|
|||||||
contents: content.data,
|
contents: content.data,
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'files':
|
case 'files':
|
||||||
const files = (content.data as any[]).map((f: any) => ({
|
const files = (content.data as any[]).map((f: any) => ({
|
||||||
...f,
|
...f,
|
||||||
data: f.data instanceof Uint8Array ? f.data : new Uint8Array(f.data as any),
|
data: f.data instanceof Uint8Array ? f.data : new Uint8Array(f.data as any),
|
||||||
}))
|
}))
|
||||||
note = {
|
note = {
|
||||||
meta: { type: 'file' },
|
meta: { type: 'file' },
|
||||||
contents: files,
|
contents: files,
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
error = $t('show.errors.unsupported_type')
|
error = $t('show.errors.unsupported_type')
|
||||||
return
|
return
|
||||||
@@ -144,4 +155,4 @@ break
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Generated
+494
-491
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user