Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move shared package into cli #148

Merged
merged 2 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions cryptgeon.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@
},
{
"path": "packages/cli"
},
{
"path": "packages/shared"
}
],
"settings": {
Expand Down
5 changes: 3 additions & 2 deletions packages/cli/build.js
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
15 changes: 9 additions & 6 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand All @@ -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"
Expand Down
Original file line number Diff line number Diff line change
@@ -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')
})

Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Note, 'views' | 'expiration'> & { password?: string }

Expand Down Expand Up @@ -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
}
20 changes: 10 additions & 10 deletions packages/cli/src/cli.ts
Original file line number Diff line number Diff line change
@@ -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 <url>', 'the cryptgeon server to use').default(defaultServer)
Expand All @@ -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),
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down
8 changes: 4 additions & 4 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
@@ -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'
File renamed without changes.
24 changes: 17 additions & 7 deletions packages/shared/src/api.ts → packages/cli/src/shared/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ export let client: ClientOptions = {
server: '',
}

export function setOptions(options: Partial<ClientOptions>) {
function setOptions(options: Partial<ClientOptions>) {
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,
Expand All @@ -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,
Expand All @@ -79,7 +79,7 @@ export async function create(note: Note) {
return data as { id: string }
}

export async function get(id: string): Promise<NotePublic> {
async function get(id: string): Promise<NotePublic> {
const data = await call({
url: `notes/${id}`,
method: 'delete',
Expand All @@ -93,7 +93,7 @@ export async function get(id: string): Promise<NotePublic> {
return note
}

export async function info(id: string): Promise<NoteInfo> {
async function info(id: string): Promise<NoteInfo> {
const data = await call({
url: `notes/${id}`,
method: 'get',
Expand All @@ -112,17 +112,27 @@ export type Status = {
max_views: number
max_expiration: number
allow_advanced: boolean
allow_files: boolean
theme_image: string
theme_text: string
theme_favicon: string
theme_page_title: string
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,
}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export function getStdin(timeout: number = 10): Promise<string> {
resolve('')
}, timeout)

process.stdin.on('error', reject)
process.stdin.on('data', dataHandler)
process.stdin.on('end', endHandler)
})
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/utils.ts → packages/cli/src/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"compilerOptions": {
"target": "es2022",
"module": "es2022",
"moduleResolution": "node",
"moduleResolution": "Bundler",
"declaration": true,
"emitDeclarationOnly": true,
"strict": true,
Expand Down
7 changes: 2 additions & 5 deletions packages/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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"
}
Expand Down
4 changes: 2 additions & 2 deletions packages/frontend/src/lib/stores/status.ts
Original file line number Diff line number Diff line change
@@ -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 | Status>(null)

export async function init() {
status.set(await getStatus())
status.set(await API.status())
}
6 changes: 3 additions & 3 deletions packages/frontend/src/lib/toast.ts
Original file line number Diff line number Diff line change
@@ -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<NotifyType, SvelteToastOptions['theme']> = {
const themeMapping: Record<NotifyType, Record<string, string>> = {
[NotifyType.Success]: {
'--toastBackground': 'var(--ui-clr-primary)',
'--toastBarBackground': 'var(--ui-clr-primary-alt)',
Expand All @@ -17,7 +17,7 @@ const themeMapping: Record<NotifyType, SvelteToastOptions['theme']> = {
}

function notifyFN(message: string, type: NotifyType = NotifyType.Success) {
const options: SvelteToastOptions = {
const options = {
duration: 5_000,
theme: {
...themeMapping[type],
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/lib/ui/AdvancedParameters.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/lib/ui/FileUpload.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = []
Expand Down
16 changes: 13 additions & 3 deletions packages/frontend/src/lib/ui/ShowNote.svelte
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
<script lang="ts" context="module">
export type DecryptedNote = Omit<NotePublic, 'contents'> & { contents: any }

function saveAs(file: File) {
const url = window.URL.createObjectURL(file)
const a = document.createElement('a')
a.style.display = 'none'
a.href = url
a.download = file.name
document.body.appendChild(a)
a.click()
window.URL.revokeObjectURL(url)
a.remove()
}
</script>

<script lang="ts">
import pkg from 'file-saver'
const { saveAs } = pkg
import prettyBytes from 'pretty-bytes'
import { t } from 'svelte-intl-precompile'

import Button from '$lib/ui/Button.svelte'
import { copy } from '$lib/utils'
import type { FileDTO, NotePublic } from '@cryptgeon/shared'
import type { FileDTO, NotePublic } from 'cryptgeon/shared'

export let note: DecryptedNote

Expand Down
Loading