Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kentcdodds/dropbox

src/upload.ts

79 lines · 2.2 KB · TypeScript
import { request } from './request.ts'
import type { DropboxRequestResult, JsonRecord } from './types.ts'
import {
	optionalBoolean,
	optionalString,
	requireDropboxPath,
	requireRecord,
} from './types.ts'

export type UploadInput = {
	path: string
	text?: string
	bytesBase64?: string
	mode?: 'add' | 'overwrite'
	autorename?: boolean
	mute?: boolean
	strictConflict?: boolean
	confirm?: boolean
	dryRun?: boolean
}

export async function upload(
	input: UploadInput,
): Promise<DropboxRequestResult | JsonRecord> {
	const path = requireDropboxPath(input.path)
	const text = optionalString(input.text, 'text')
	const suppliedBase64 = optionalString(input.bytesBase64, 'bytesBase64')
	if ((text === undefined) === (suppliedBase64 === undefined)) {
		throw new Error('Provide exactly one of text or bytesBase64.')
	}
	const mode = input.mode ?? 'add'
	if (mode !== 'add' && mode !== 'overwrite') {
		throw new Error('mode must be "add" or "overwrite".')
	}

	const bytesBase64 = suppliedBase64 ?? encodeTextBase64(text ?? '')
	return request({
		endpoint: 'files/upload',
		kind: 'upload',
		apiArg: {
			path,
			mode,
			autorename: optionalBoolean(input.autorename, 'autorename') ?? false,
			mute: optionalBoolean(input.mute, 'mute') ?? false,
			strict_conflict: optionalBoolean(input.strictConflict, 'strictConflict') ?? false,
		},
		bytesBase64,
		confirm: input.confirm,
		dryRun: input.dryRun,
	})
}

function encodeTextBase64(value: string): string {
	const bytes = new TextEncoder().encode(value)
	const chunks: string[] = []
	const chunkSize = 0x8000
	for (let index = 0; index < bytes.length; index += chunkSize) {
		chunks.push(String.fromCharCode(...bytes.subarray(index, index + chunkSize)))
	}
	return btoa(chunks.join(''))
}

/**
 * Upload UTF-8 text or base64 bytes to Dropbox.
 * Requires `confirm: true`; use `dryRun: true` to preview the request.
 * @example
 * import upload from 'kody:@kentcdodds/dropbox/upload'
 * const result = await upload({
 *   path: '/notes/hello.txt',
 *   text: 'Hello',
 *   mode: 'overwrite',
 *   confirm: true,
 * })
 */
export default async function uploadEntrypoint(
	params: Partial<UploadInput> & Record<string, unknown> = {},
) {
	return upload(requireRecord(params, 'upload') as UploadInput)
}