diff --git a/cryptgeon.code-workspace b/cryptgeon.code-workspace index d659d68..1d5ce37 100644 --- a/cryptgeon.code-workspace +++ b/cryptgeon.code-workspace @@ -11,9 +11,6 @@ }, { "path": "packages/cli" - }, - { - "path": "packages/shared" } ], "settings": { diff --git a/packages/cli/build.js b/packages/cli/build.js index 7a81d9d..a977c85 100644 --- a/packages/cli/build.js +++ b/packages/cli/build.js @@ -1,13 +1,14 @@ -import pkg from './package.json' with { type: 'json' } import { build } from 'tsup' +import pkg from './package.json' with { type: 'json' } const watch = process.argv.slice(2)[0] === '--watch' await build({ - entry: ['src/index.ts', 'src/cli.ts'], + entry: ['src/index.ts', 'src/cli.ts', 'src/shared/shared.ts'], dts: true, minify: true, format: ['esm', 'cjs'], + target: 'es2020', clean: true, define: { VERSION: `"${pkg.version}"` }, watch, diff --git a/packages/cli/package.json b/packages/cli/package.json index c59b0c7..b07dfe9 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -9,7 +9,11 @@ }, "type": "module", "exports": { - ".": "./dist/index.js" + ".": "./dist/index.js", + "./shared": { + "import": "./dist/shared/shared.js", + "types": "./dist/shared/shared.d.ts" + } }, "types": "./dist/index.d.ts", "bin": { @@ -25,15 +29,14 @@ "prepublishOnly": "run-s build" }, "devDependencies": { - "@commander-js/extra-typings": "^12.0.1", - "@cryptgeon/shared": "workspace:*", + "@commander-js/extra-typings": "^12.1.0", "@types/inquirer": "^9.0.7", - "@types/mime": "^3.0.4", + "@types/mime": "^4.0.0", "@types/node": "^20.11.24", - "commander": "^12.0.0", + "commander": "^12.1.0", "inquirer": "^9.2.15", "mime": "^4.0.1", - "occulto": "^2.0.3", + "occulto": "^2.0.6", "pretty-bytes": "^6.1.1", "tsup": "^8.2.4", "typescript": "^5.3.3" diff --git a/packages/cli/src/download.ts b/packages/cli/src/actions/download.ts similarity index 92% rename from packages/cli/src/download.ts rename to packages/cli/src/actions/download.ts index ae64264..7aa04f1 100644 --- a/packages/cli/src/download.ts +++ b/packages/cli/src/actions/download.ts @@ -1,14 +1,15 @@ -import { Adapters, get, info, setOptions } from '@cryptgeon/shared' import inquirer from 'inquirer' import { access, constants, writeFile } from 'node:fs/promises' import { basename, resolve } from 'node:path' import { AES, Hex } from 'occulto' import pretty from 'pretty-bytes' +import { Adapters } from '../shared/adapters.js' +import { API } from '../shared/api.js' export async function download(url: URL, all: boolean, suggestedPassword?: string) { - setOptions({ server: url.origin }) + API.setOptions({ server: url.origin }) const id = url.pathname.split('/')[2] - const preview = await info(id).catch(() => { + const preview = await API.info(id).catch(() => { throw new Error('Note does not exist or is expired') }) @@ -33,7 +34,7 @@ export async function download(url: URL, all: boolean, suggestedPassword?: strin } const key = derivation ? (await AES.derive(password, derivation))[0] : Hex.decode(password) - const note = await get(id) + const note = await API.get(id) const couldNotDecrypt = new Error('Could not decrypt note. Probably an invalid password') switch (note.meta.type) { diff --git a/packages/cli/src/upload.ts b/packages/cli/src/actions/upload.ts similarity index 87% rename from packages/cli/src/upload.ts rename to packages/cli/src/actions/upload.ts index ef04f9c..3bb1258 100644 --- a/packages/cli/src/upload.ts +++ b/packages/cli/src/actions/upload.ts @@ -1,9 +1,10 @@ import { readFile, stat } from 'node:fs/promises' import { basename } from 'node:path' -import { Adapters, create, getOptions, FileDTO, Note, NoteMeta } from '@cryptgeon/shared' import mime from 'mime' import { AES, Hex } from 'occulto' +import { Adapters } from '../shared/adapters.js' +import { API, FileDTO, Note, NoteMeta } from '../shared/api.js' export type UploadOptions = Pick & { password?: string } @@ -38,8 +39,8 @@ export async function upload(input: string | string[], options: UploadOptions): // Create the actual note and upload it. const note: Note = { ...noteOptions, contents, meta: { type, derivation: derived?.[1] } } - const result = await create(note) - let url = `${getOptions().server}/note/${result.id}` + const result = await API.create(note) + let url = `${API.getOptions().server}/note/${result.id}` if (!derived) url += `#${Hex.encode(key)}` return url } diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index bcd9b85..e505df3 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -1,14 +1,14 @@ #!/usr/bin/env node import { Argument, Option, program } from '@commander-js/extra-typings' -import { setOptions, status } from '@cryptgeon/shared' import prettyBytes from 'pretty-bytes' -import { download } from './download.js' -import { parseFile, parseNumber } from './parsers.js' -import { getStdin } from './stdin.js' -import { upload } from './upload.js' -import { checkConstrains, exit } from './utils.js' +import { download } from './actions/download.js' +import { upload } from './actions/upload.js' +import { API } from './shared/api.js' +import { parseFile, parseNumber } from './utils/parsers.js' +import { getStdin } from './utils/stdin.js' +import { checkConstrains, exit } from './utils/utils.js' const defaultServer = process.env['CRYPTGEON_SERVER'] || 'https://cryptgeon.org' const server = new Option('-s --server ', 'the cryptgeon server to use').default(defaultServer) @@ -33,8 +33,8 @@ program .description('show information about the server') .addOption(server) .action(async (options) => { - setOptions({ server: options.server }) - const response = await status() + API.setOptions({ server: options.server }) + const response = await API.status() const formatted = { ...response, max_size: prettyBytes(response.max_size), @@ -54,7 +54,7 @@ send .addOption(minutes) .addOption(password) .action(async (files, options) => { - setOptions({ server: options.server }) + API.setOptions({ server: options.server }) await checkConstrains(options) options.password ||= await getStdin() try { @@ -72,7 +72,7 @@ send .addOption(minutes) .addOption(password) .action(async (text, options) => { - setOptions({ server: options.server }) + API.setOptions({ server: options.server }) await checkConstrains(options) options.password ||= await getStdin() try { diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index ce1fca2..a22bcf6 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -1,4 +1,4 @@ -export * from '@cryptgeon/shared' -export * from './download.js' -export * from './upload.js' -export * from './utils.js' +export * from './actions/download.js' +export * from './actions/upload.js' +export * from './shared/adapters.js' +export * from './shared/api.js' diff --git a/packages/shared/src/adapters.ts b/packages/cli/src/shared/adapters.ts similarity index 100% rename from packages/shared/src/adapters.ts rename to packages/cli/src/shared/adapters.ts diff --git a/packages/shared/src/api.ts b/packages/cli/src/shared/api.ts similarity index 85% rename from packages/shared/src/api.ts rename to packages/cli/src/shared/api.ts index e210f40..fa085ac 100644 --- a/packages/shared/src/api.ts +++ b/packages/cli/src/shared/api.ts @@ -39,15 +39,15 @@ export let client: ClientOptions = { server: '', } -export function setOptions(options: Partial) { +function setOptions(options: Partial) { client = { ...client, ...options } } -export function getOptions(): ClientOptions { +function getOptions(): ClientOptions { return client } -export async function call(options: CallOptions) { +async function call(options: CallOptions) { const url = client.server + '/api/' + options.url const response = await fetch(url, { method: options.method, @@ -65,7 +65,7 @@ export async function call(options: CallOptions) { return response.json() } -export async function create(note: Note) { +async function create(note: Note) { const { meta, ...rest } = note const body: NoteCreate = { ...rest, @@ -79,7 +79,7 @@ export async function create(note: Note) { return data as { id: string } } -export async function get(id: string): Promise { +async function get(id: string): Promise { const data = await call({ url: `notes/${id}`, method: 'delete', @@ -93,7 +93,7 @@ export async function get(id: string): Promise { return note } -export async function info(id: string): Promise { +async function info(id: string): Promise { const data = await call({ url: `notes/${id}`, method: 'get', @@ -112,6 +112,7 @@ export type Status = { max_views: number max_expiration: number allow_advanced: boolean + allow_files: boolean theme_image: string theme_text: string theme_favicon: string @@ -119,10 +120,19 @@ export type Status = { theme_new_note_notice: boolean } -export async function status() { +async function status() { const data = await call({ url: 'status/', method: 'get', }) return data as Status } + +export const API = { + setOptions, + getOptions, + create, + get, + info, + status, +} diff --git a/packages/shared/src/index.ts b/packages/cli/src/shared/shared.ts similarity index 100% rename from packages/shared/src/index.ts rename to packages/cli/src/shared/shared.ts diff --git a/packages/cli/src/parsers.ts b/packages/cli/src/utils/parsers.ts similarity index 85% rename from packages/cli/src/parsers.ts rename to packages/cli/src/utils/parsers.ts index 33cac70..24bc676 100644 --- a/packages/cli/src/parsers.ts +++ b/packages/cli/src/utils/parsers.ts @@ -21,7 +21,7 @@ export function parseURL(value: string, _: URL): URL { } export function parseNumber(value: string, _: number): number { - const n = parseInt(value, 10) - if (isNaN(n)) throw new InvalidOptionArgumentError('invalid number') + const n = Number.parseInt(value, 10) + if (Number.isNaN(n)) throw new InvalidOptionArgumentError('invalid number') return n } diff --git a/packages/cli/src/stdin.ts b/packages/cli/src/utils/stdin.ts similarity index 95% rename from packages/cli/src/stdin.ts rename to packages/cli/src/utils/stdin.ts index d94b46a..4e1a67b 100644 --- a/packages/cli/src/stdin.ts +++ b/packages/cli/src/utils/stdin.ts @@ -18,6 +18,7 @@ export function getStdin(timeout: number = 10): Promise { resolve('') }, timeout) + process.stdin.on('error', reject) process.stdin.on('data', dataHandler) process.stdin.on('end', endHandler) }) diff --git a/packages/cli/src/utils.ts b/packages/cli/src/utils/utils.ts similarity index 89% rename from packages/cli/src/utils.ts rename to packages/cli/src/utils/utils.ts index 37ebb65..18da6a1 100644 --- a/packages/cli/src/utils.ts +++ b/packages/cli/src/utils/utils.ts @@ -1,5 +1,5 @@ -import { status } from '@cryptgeon/shared' import { exit as exitNode } from 'node:process' +import { API } from '../shared/api.js' export function exit(message: string) { console.error(message) @@ -11,7 +11,7 @@ export async function checkConstrains(constrains: { views?: number; minutes?: nu if (views && minutes) exit('cannot set view and minutes constrains simultaneously') if (!views && !minutes) constrains.views = 1 - const response = await status() + const response = await API.status() if (views && views > response.max_views) exit(`Only a maximum of ${response.max_views} views allowed. ${views} given.`) if (minutes && minutes > response.max_expiration) diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json index 4aab889..5514c3b 100644 --- a/packages/cli/tsconfig.json +++ b/packages/cli/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "es2022", "module": "es2022", - "moduleResolution": "node", + "moduleResolution": "Bundler", "declaration": true, "emitDeclarationOnly": true, "strict": true, diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 1a61488..91a147e 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -17,7 +17,6 @@ "@sveltejs/adapter-static": "^3.0.1", "@sveltejs/kit": "^2.5.2", "@sveltejs/vite-plugin-svelte": "^3.0.2", - "@types/file-saver": "^2.0.7", "@zerodevx/svelte-toast": "^0.9.5", "adm-zip": "^0.5.10", "dotenv": "^16.4.5", @@ -29,11 +28,9 @@ "vite": "^5.1.7" }, "dependencies": { - "@cryptgeon/shared": "workspace:*", + "cryptgeon": "workspace:*", "@fontsource/fira-mono": "^5.0.8", - "copy-to-clipboard": "^3.3.3", - "file-saver": "^2.0.5", - "occulto": "^2.0.3", + "occulto": "^2.0.6", "pretty-bytes": "^6.1.1", "qrious": "^4.0.2" } diff --git a/packages/frontend/src/lib/stores/status.ts b/packages/frontend/src/lib/stores/status.ts index 4cc347c..b020413 100644 --- a/packages/frontend/src/lib/stores/status.ts +++ b/packages/frontend/src/lib/stores/status.ts @@ -1,8 +1,8 @@ -import { status as getStatus, type Status } from '@cryptgeon/shared' +import { API, type Status } from 'cryptgeon/shared' import { writable } from 'svelte/store' export const status = writable(null) export async function init() { - status.set(await getStatus()) + status.set(await API.status()) } diff --git a/packages/frontend/src/lib/toast.ts b/packages/frontend/src/lib/toast.ts index 9e2dfd8..10a5ec7 100644 --- a/packages/frontend/src/lib/toast.ts +++ b/packages/frontend/src/lib/toast.ts @@ -1,11 +1,11 @@ -import { toast, type SvelteToastOptions } from '@zerodevx/svelte-toast' +import { toast } from '@zerodevx/svelte-toast' export enum NotifyType { Success = 'success', Error = 'error', } -const themeMapping: Record = { +const themeMapping: Record> = { [NotifyType.Success]: { '--toastBackground': 'var(--ui-clr-primary)', '--toastBarBackground': 'var(--ui-clr-primary-alt)', @@ -17,7 +17,7 @@ const themeMapping: Record = { } function notifyFN(message: string, type: NotifyType = NotifyType.Success) { - const options: SvelteToastOptions = { + const options = { duration: 5_000, theme: { ...themeMapping[type], diff --git a/packages/frontend/src/lib/ui/AdvancedParameters.svelte b/packages/frontend/src/lib/ui/AdvancedParameters.svelte index e3d18f4..89d5dff 100644 --- a/packages/frontend/src/lib/ui/AdvancedParameters.svelte +++ b/packages/frontend/src/lib/ui/AdvancedParameters.svelte @@ -4,7 +4,7 @@ import { status } from '$lib/stores/status' import Switch from '$lib/ui/Switch.svelte' import TextInput from '$lib/ui/TextInput.svelte' - import type { Note } from '@cryptgeon/shared' + import type { Note } from 'cryptgeon/shared' export let note: Note export let timeExpiration = false diff --git a/packages/frontend/src/lib/ui/FileUpload.svelte b/packages/frontend/src/lib/ui/FileUpload.svelte index fea73f3..f4ae69b 100644 --- a/packages/frontend/src/lib/ui/FileUpload.svelte +++ b/packages/frontend/src/lib/ui/FileUpload.svelte @@ -3,7 +3,7 @@ import Button from '$lib/ui/Button.svelte' import MaxSize from '$lib/ui/MaxSize.svelte' - import type { FileDTO } from '@cryptgeon/shared' + import type { FileDTO } from 'cryptgeon/shared' export let label: string = '' export let files: FileDTO[] = [] diff --git a/packages/frontend/src/lib/ui/ShowNote.svelte b/packages/frontend/src/lib/ui/ShowNote.svelte index 2198c98..d1408ef 100644 --- a/packages/frontend/src/lib/ui/ShowNote.svelte +++ b/packages/frontend/src/lib/ui/ShowNote.svelte @@ -1,16 +1,26 @@