mirror of
https://github.com/cupcakearmy/cryptgeon.git
synced 2024-12-22 00:06:28 +00:00
move shared package to cli
This commit is contained in:
parent
868b49c1c3
commit
7b919f2a53
@ -11,9 +11,6 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "packages/cli"
|
"path": "packages/cli"
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "packages/shared"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import pkg from './package.json' with { type: 'json' }
|
|
||||||
import { build } from 'tsup'
|
import { build } from 'tsup'
|
||||||
|
import pkg from './package.json' with { type: 'json' }
|
||||||
|
|
||||||
const watch = process.argv.slice(2)[0] === '--watch'
|
const watch = process.argv.slice(2)[0] === '--watch'
|
||||||
|
|
||||||
await build({
|
await build({
|
||||||
entry: ['src/index.ts', 'src/cli.ts'],
|
entry: ['src/index.ts', 'src/cli.ts', 'src/shared/shared.ts'],
|
||||||
dts: true,
|
dts: true,
|
||||||
minify: true,
|
minify: true,
|
||||||
format: ['esm', 'cjs'],
|
format: ['esm', 'cjs'],
|
||||||
|
target: 'es2020',
|
||||||
clean: true,
|
clean: true,
|
||||||
define: { VERSION: `"${pkg.version}"` },
|
define: { VERSION: `"${pkg.version}"` },
|
||||||
watch,
|
watch,
|
||||||
|
@ -9,7 +9,11 @@
|
|||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./dist/index.js"
|
".": "./dist/index.js",
|
||||||
|
"./shared": {
|
||||||
|
"import": "./dist/shared/shared.js",
|
||||||
|
"types": "./dist/shared/shared.d.ts"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"bin": {
|
"bin": {
|
||||||
@ -25,15 +29,14 @@
|
|||||||
"prepublishOnly": "run-s build"
|
"prepublishOnly": "run-s build"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commander-js/extra-typings": "^12.0.1",
|
"@commander-js/extra-typings": "^12.1.0",
|
||||||
"@cryptgeon/shared": "workspace:*",
|
|
||||||
"@types/inquirer": "^9.0.7",
|
"@types/inquirer": "^9.0.7",
|
||||||
"@types/mime": "^3.0.4",
|
"@types/mime": "^4.0.0",
|
||||||
"@types/node": "^20.11.24",
|
"@types/node": "^20.11.24",
|
||||||
"commander": "^12.0.0",
|
"commander": "^12.1.0",
|
||||||
"inquirer": "^9.2.15",
|
"inquirer": "^9.2.15",
|
||||||
"mime": "^4.0.1",
|
"mime": "^4.0.1",
|
||||||
"occulto": "^2.0.3",
|
"occulto": "^2.0.6",
|
||||||
"pretty-bytes": "^6.1.1",
|
"pretty-bytes": "^6.1.1",
|
||||||
"tsup": "^8.2.4",
|
"tsup": "^8.2.4",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3"
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
import { Adapters, get, info, setOptions } from '@cryptgeon/shared'
|
|
||||||
import inquirer from 'inquirer'
|
import inquirer from 'inquirer'
|
||||||
import { access, constants, writeFile } from 'node:fs/promises'
|
import { access, constants, writeFile } from 'node:fs/promises'
|
||||||
import { basename, resolve } from 'node:path'
|
import { basename, resolve } from 'node:path'
|
||||||
import { AES, Hex } from 'occulto'
|
import { AES, Hex } from 'occulto'
|
||||||
import pretty from 'pretty-bytes'
|
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) {
|
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 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')
|
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 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')
|
const couldNotDecrypt = new Error('Could not decrypt note. Probably an invalid password')
|
||||||
switch (note.meta.type) {
|
switch (note.meta.type) {
|
@ -1,9 +1,10 @@
|
|||||||
import { readFile, stat } from 'node:fs/promises'
|
import { readFile, stat } from 'node:fs/promises'
|
||||||
import { basename } from 'node:path'
|
import { basename } from 'node:path'
|
||||||
|
|
||||||
import { Adapters, create, getOptions, FileDTO, Note, NoteMeta } from '@cryptgeon/shared'
|
|
||||||
import mime from 'mime'
|
import mime from 'mime'
|
||||||
import { AES, Hex } from 'occulto'
|
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 }
|
export type UploadOptions = Pick<Note, 'views' | 'expiration'> & { password?: string }
|
||||||
|
|
||||||
@ -38,8 +39,8 @@ export async function upload(input: string | string[], options: UploadOptions):
|
|||||||
|
|
||||||
// Create the actual note and upload it.
|
// Create the actual note and upload it.
|
||||||
const note: Note = { ...noteOptions, contents, meta: { type, derivation: derived?.[1] } }
|
const note: Note = { ...noteOptions, contents, meta: { type, derivation: derived?.[1] } }
|
||||||
const result = await create(note)
|
const result = await API.create(note)
|
||||||
let url = `${getOptions().server}/note/${result.id}`
|
let url = `${API.getOptions().server}/note/${result.id}`
|
||||||
if (!derived) url += `#${Hex.encode(key)}`
|
if (!derived) url += `#${Hex.encode(key)}`
|
||||||
return url
|
return url
|
||||||
}
|
}
|
@ -1,14 +1,14 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
import { Argument, Option, program } from '@commander-js/extra-typings'
|
import { Argument, Option, program } from '@commander-js/extra-typings'
|
||||||
import { setOptions, status } from '@cryptgeon/shared'
|
|
||||||
import prettyBytes from 'pretty-bytes'
|
import prettyBytes from 'pretty-bytes'
|
||||||
|
|
||||||
import { download } from './download.js'
|
import { download } from './actions/download.js'
|
||||||
import { parseFile, parseNumber } from './parsers.js'
|
import { upload } from './actions/upload.js'
|
||||||
import { getStdin } from './stdin.js'
|
import { API } from './shared/api.js'
|
||||||
import { upload } from './upload.js'
|
import { parseFile, parseNumber } from './utils/parsers.js'
|
||||||
import { checkConstrains, exit } from './utils.js'
|
import { getStdin } from './utils/stdin.js'
|
||||||
|
import { checkConstrains, exit } from './utils/utils.js'
|
||||||
|
|
||||||
const defaultServer = process.env['CRYPTGEON_SERVER'] || 'https://cryptgeon.org'
|
const defaultServer = process.env['CRYPTGEON_SERVER'] || 'https://cryptgeon.org'
|
||||||
const server = new Option('-s --server <url>', 'the cryptgeon server to use').default(defaultServer)
|
const server = new Option('-s --server <url>', 'the cryptgeon server to use').default(defaultServer)
|
||||||
@ -33,8 +33,8 @@ program
|
|||||||
.description('show information about the server')
|
.description('show information about the server')
|
||||||
.addOption(server)
|
.addOption(server)
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
setOptions({ server: options.server })
|
API.setOptions({ server: options.server })
|
||||||
const response = await status()
|
const response = await API.status()
|
||||||
const formatted = {
|
const formatted = {
|
||||||
...response,
|
...response,
|
||||||
max_size: prettyBytes(response.max_size),
|
max_size: prettyBytes(response.max_size),
|
||||||
@ -54,7 +54,7 @@ send
|
|||||||
.addOption(minutes)
|
.addOption(minutes)
|
||||||
.addOption(password)
|
.addOption(password)
|
||||||
.action(async (files, options) => {
|
.action(async (files, options) => {
|
||||||
setOptions({ server: options.server })
|
API.setOptions({ server: options.server })
|
||||||
await checkConstrains(options)
|
await checkConstrains(options)
|
||||||
options.password ||= await getStdin()
|
options.password ||= await getStdin()
|
||||||
try {
|
try {
|
||||||
@ -72,7 +72,7 @@ send
|
|||||||
.addOption(minutes)
|
.addOption(minutes)
|
||||||
.addOption(password)
|
.addOption(password)
|
||||||
.action(async (text, options) => {
|
.action(async (text, options) => {
|
||||||
setOptions({ server: options.server })
|
API.setOptions({ server: options.server })
|
||||||
await checkConstrains(options)
|
await checkConstrains(options)
|
||||||
options.password ||= await getStdin()
|
options.password ||= await getStdin()
|
||||||
try {
|
try {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export * from '@cryptgeon/shared'
|
export * from './actions/download.js'
|
||||||
export * from './download.js'
|
export * from './actions/upload.js'
|
||||||
export * from './upload.js'
|
export * from './shared/adapters.js'
|
||||||
export * from './utils.js'
|
export * from './shared/api.js'
|
||||||
|
@ -39,15 +39,15 @@ export let client: ClientOptions = {
|
|||||||
server: '',
|
server: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setOptions(options: Partial<ClientOptions>) {
|
function setOptions(options: Partial<ClientOptions>) {
|
||||||
client = { ...client, ...options }
|
client = { ...client, ...options }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getOptions(): ClientOptions {
|
function getOptions(): ClientOptions {
|
||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function call(options: CallOptions) {
|
async function call(options: CallOptions) {
|
||||||
const url = client.server + '/api/' + options.url
|
const url = client.server + '/api/' + options.url
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: options.method,
|
method: options.method,
|
||||||
@ -65,7 +65,7 @@ export async function call(options: CallOptions) {
|
|||||||
return response.json()
|
return response.json()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function create(note: Note) {
|
async function create(note: Note) {
|
||||||
const { meta, ...rest } = note
|
const { meta, ...rest } = note
|
||||||
const body: NoteCreate = {
|
const body: NoteCreate = {
|
||||||
...rest,
|
...rest,
|
||||||
@ -79,7 +79,7 @@ export async function create(note: Note) {
|
|||||||
return data as { id: string }
|
return data as { id: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get(id: string): Promise<NotePublic> {
|
async function get(id: string): Promise<NotePublic> {
|
||||||
const data = await call({
|
const data = await call({
|
||||||
url: `notes/${id}`,
|
url: `notes/${id}`,
|
||||||
method: 'delete',
|
method: 'delete',
|
||||||
@ -93,7 +93,7 @@ export async function get(id: string): Promise<NotePublic> {
|
|||||||
return note
|
return note
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function info(id: string): Promise<NoteInfo> {
|
async function info(id: string): Promise<NoteInfo> {
|
||||||
const data = await call({
|
const data = await call({
|
||||||
url: `notes/${id}`,
|
url: `notes/${id}`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
@ -112,6 +112,7 @@ export type Status = {
|
|||||||
max_views: number
|
max_views: number
|
||||||
max_expiration: number
|
max_expiration: number
|
||||||
allow_advanced: boolean
|
allow_advanced: boolean
|
||||||
|
allow_files: boolean
|
||||||
theme_image: string
|
theme_image: string
|
||||||
theme_text: string
|
theme_text: string
|
||||||
theme_favicon: string
|
theme_favicon: string
|
||||||
@ -119,10 +120,19 @@ export type Status = {
|
|||||||
theme_new_note_notice: boolean
|
theme_new_note_notice: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function status() {
|
async function status() {
|
||||||
const data = await call({
|
const data = await call({
|
||||||
url: 'status/',
|
url: 'status/',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
})
|
})
|
||||||
return data as Status
|
return data as Status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const API = {
|
||||||
|
setOptions,
|
||||||
|
getOptions,
|
||||||
|
create,
|
||||||
|
get,
|
||||||
|
info,
|
||||||
|
status,
|
||||||
|
}
|
@ -21,7 +21,7 @@ export function parseURL(value: string, _: URL): URL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function parseNumber(value: string, _: number): number {
|
export function parseNumber(value: string, _: number): number {
|
||||||
const n = parseInt(value, 10)
|
const n = Number.parseInt(value, 10)
|
||||||
if (isNaN(n)) throw new InvalidOptionArgumentError('invalid number')
|
if (Number.isNaN(n)) throw new InvalidOptionArgumentError('invalid number')
|
||||||
return n
|
return n
|
||||||
}
|
}
|
@ -18,6 +18,7 @@ export function getStdin(timeout: number = 10): Promise<string> {
|
|||||||
resolve('')
|
resolve('')
|
||||||
}, timeout)
|
}, timeout)
|
||||||
|
|
||||||
|
process.stdin.on('error', reject)
|
||||||
process.stdin.on('data', dataHandler)
|
process.stdin.on('data', dataHandler)
|
||||||
process.stdin.on('end', endHandler)
|
process.stdin.on('end', endHandler)
|
||||||
})
|
})
|
@ -1,5 +1,5 @@
|
|||||||
import { status } from '@cryptgeon/shared'
|
|
||||||
import { exit as exitNode } from 'node:process'
|
import { exit as exitNode } from 'node:process'
|
||||||
|
import { API } from '../shared/api.js'
|
||||||
|
|
||||||
export function exit(message: string) {
|
export function exit(message: string) {
|
||||||
console.error(message)
|
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) exit('cannot set view and minutes constrains simultaneously')
|
||||||
if (!views && !minutes) constrains.views = 1
|
if (!views && !minutes) constrains.views = 1
|
||||||
|
|
||||||
const response = await status()
|
const response = await API.status()
|
||||||
if (views && views > response.max_views)
|
if (views && views > response.max_views)
|
||||||
exit(`Only a maximum of ${response.max_views} views allowed. ${views} given.`)
|
exit(`Only a maximum of ${response.max_views} views allowed. ${views} given.`)
|
||||||
if (minutes && minutes > response.max_expiration)
|
if (minutes && minutes > response.max_expiration)
|
@ -2,7 +2,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es2022",
|
"target": "es2022",
|
||||||
"module": "es2022",
|
"module": "es2022",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "Bundler",
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"emitDeclarationOnly": true,
|
"emitDeclarationOnly": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"private": true,
|
|
||||||
"name": "@cryptgeon/shared",
|
|
||||||
"type": "module",
|
|
||||||
"types": "./dist/index.d.ts",
|
|
||||||
"exports": {
|
|
||||||
".": {
|
|
||||||
"types": "./dist/index.d.ts",
|
|
||||||
"import": "./dist/index.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"dev": "tsc -w",
|
|
||||||
"build": "tsc"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"typescript": "^5.3.3"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"occulto": "^2.0.3"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"incremental": true,
|
|
||||||
"composite": true,
|
|
||||||
"target": "es2022",
|
|
||||||
"module": "es2022",
|
|
||||||
"rootDir": "./src",
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"outDir": "./dist",
|
|
||||||
"strict": true
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user