diff --git a/src/hooks/useSigitMeta.tsx b/src/hooks/useSigitMeta.tsx
index fea5154..088940e 100644
--- a/src/hooks/useSigitMeta.tsx
+++ b/src/hooks/useSigitMeta.tsx
@@ -11,7 +11,6 @@ import {
hexToNpub,
parseNostrEvent,
parseCreateSignatureEventContent,
- SigitMetaParseError,
SigitStatus,
SignStatus
} from '../utils'
@@ -21,6 +20,7 @@ import { Event } from 'nostr-tools'
import store from '../store/store'
import { AuthState } from '../store/auth/types'
import { NostrController } from '../controllers'
+import { MetaParseError } from '../types/errors/MetaParseError'
/**
* Flattened interface that combines properties `Meta`, `CreateSignatureEventContent`,
@@ -247,7 +247,7 @@ export const useSigitMeta = (meta: Meta): FlatMeta => {
)
}
} catch (error) {
- if (error instanceof SigitMetaParseError) {
+ if (error instanceof MetaParseError) {
toast.error(error.message)
}
console.error(error)
diff --git a/src/layouts/StickySideColumns.tsx b/src/layouts/StickySideColumns.tsx
index 43dc430..d27ad4b 100644
--- a/src/layouts/StickySideColumns.tsx
+++ b/src/layouts/StickySideColumns.tsx
@@ -17,8 +17,10 @@ export const StickySideColumns = ({
- {children}
+
{right}
diff --git a/src/pages/create/index.tsx b/src/pages/create/index.tsx
index 2bcd063..2c32f7d 100644
--- a/src/pages/create/index.tsx
+++ b/src/pages/create/index.tsx
@@ -514,6 +514,9 @@ export const CreatePage = () => {
return (
file.pages?.flatMap((page, index) => {
return page.drawnFields.map((drawnField) => {
+ if (!drawnField.counterpart) {
+ throw new Error('Missing counterpart')
+ }
return {
type: drawnField.type,
location: {
@@ -670,6 +673,7 @@ export const CreatePage = () => {
}
const generateCreateSignature = async (
+ markConfig: Mark[],
fileHashes: {
[key: string]: string
},
@@ -677,7 +681,6 @@ export const CreatePage = () => {
) => {
const signers = users.filter((user) => user.role === UserRole.signer)
const viewers = users.filter((user) => user.role === UserRole.viewer)
- const markConfig = createMarks(fileHashes)
const content: CreateSignatureEventContent = {
signers: signers.map((signer) => hexToNpub(signer.pubkey)),
@@ -721,131 +724,128 @@ export const CreatePage = () => {
}
const handleCreate = async () => {
- if (!validateInputs()) return
+ try {
+ if (!validateInputs()) return
- setIsLoading(true)
- setLoadingSpinnerDesc('Generating file hashes')
- const fileHashes = await generateFileHashes()
- if (!fileHashes) {
+ setIsLoading(true)
+ setLoadingSpinnerDesc('Generating file hashes')
+ const fileHashes = await generateFileHashes()
+ if (!fileHashes) return
+
+ setLoadingSpinnerDesc('Generating encryption key')
+ const encryptionKey = await generateEncryptionKey()
+
+ if (await isOnline()) {
+ setLoadingSpinnerDesc('generating files.zip')
+ const arrayBuffer = await generateFilesZip()
+ if (!arrayBuffer) return
+
+ setLoadingSpinnerDesc('Encrypting files.zip')
+ const encryptedArrayBuffer = await encryptZipFile(
+ arrayBuffer,
+ encryptionKey
+ )
+
+ const markConfig = createMarks(fileHashes)
+
+ setLoadingSpinnerDesc('Uploading files.zip to file storage')
+ const fileUrl = await uploadFile(encryptedArrayBuffer)
+ if (!fileUrl) return
+
+ setLoadingSpinnerDesc('Generating create signature')
+ const createSignature = await generateCreateSignature(
+ markConfig,
+ fileHashes,
+ fileUrl
+ )
+ if (!createSignature) return
+
+ setLoadingSpinnerDesc('Generating keys for decryption')
+
+ // generate key pairs for decryption
+ const pubkeys = users.map((user) => user.pubkey)
+ // also add creator in the list
+ if (pubkeys.includes(usersPubkey!)) {
+ pubkeys.push(usersPubkey!)
+ }
+
+ const keys = await generateKeys(pubkeys, encryptionKey)
+ if (!keys) return
+
+ const meta: Meta = {
+ createSignature,
+ keys,
+ modifiedAt: unixNow(),
+ docSignatures: {}
+ }
+
+ setLoadingSpinnerDesc('Updating user app data')
+ const event = await updateUsersAppData(meta)
+ if (!event) return
+
+ setLoadingSpinnerDesc('Sending notifications to counterparties')
+ const promises = sendNotifications(meta)
+
+ await Promise.all(promises)
+ .then(() => {
+ toast.success('Notifications sent successfully')
+ })
+ .catch(() => {
+ toast.error('Failed to publish notifications')
+ })
+
+ navigate(appPrivateRoutes.sign, { state: { meta: meta } })
+ } else {
+ const zip = new JSZip()
+
+ selectedFiles.forEach((file) => {
+ zip.file(`files/${file.name}`, file)
+ })
+
+ const markConfig = createMarks(fileHashes)
+
+ setLoadingSpinnerDesc('Generating create signature')
+ const createSignature = await generateCreateSignature(
+ markConfig,
+ fileHashes,
+ ''
+ )
+ if (!createSignature) return
+
+ const meta: Meta = {
+ createSignature,
+ modifiedAt: unixNow(),
+ docSignatures: {}
+ }
+
+ // add meta to zip
+ try {
+ const stringifiedMeta = JSON.stringify(meta, null, 2)
+ zip.file('meta.json', stringifiedMeta)
+ } catch (err) {
+ console.error(err)
+ toast.error('An error occurred in converting meta json to string')
+ return null
+ }
+
+ const arrayBuffer = await generateZipFile(zip)
+ if (!arrayBuffer) return
+
+ setLoadingSpinnerDesc('Encrypting zip file')
+ const encryptedArrayBuffer = await encryptZipFile(
+ arrayBuffer,
+ encryptionKey
+ )
+
+ await handleOfflineFlow(encryptedArrayBuffer, encryptionKey)
+ }
+ } catch (error) {
+ if (error instanceof Error) {
+ toast.error(error.message)
+ }
+ console.error(error)
+ } finally {
setIsLoading(false)
- return
- }
-
- setLoadingSpinnerDesc('Generating encryption key')
- const encryptionKey = await generateEncryptionKey()
-
- if (await isOnline()) {
- setLoadingSpinnerDesc('generating files.zip')
- const arrayBuffer = await generateFilesZip()
- if (!arrayBuffer) {
- setIsLoading(false)
- return
- }
-
- setLoadingSpinnerDesc('Encrypting files.zip')
- const encryptedArrayBuffer = await encryptZipFile(
- arrayBuffer,
- encryptionKey
- )
-
- setLoadingSpinnerDesc('Uploading files.zip to file storage')
- const fileUrl = await uploadFile(encryptedArrayBuffer)
- if (!fileUrl) {
- setIsLoading(false)
- return
- }
-
- setLoadingSpinnerDesc('Generating create signature')
- const createSignature = await generateCreateSignature(fileHashes, fileUrl)
- if (!createSignature) {
- setIsLoading(false)
- return
- }
-
- setLoadingSpinnerDesc('Generating keys for decryption')
-
- // generate key pairs for decryption
- const pubkeys = users.map((user) => user.pubkey)
- // also add creator in the list
- if (pubkeys.includes(usersPubkey!)) {
- pubkeys.push(usersPubkey!)
- }
-
- const keys = await generateKeys(pubkeys, encryptionKey)
-
- if (!keys) {
- setIsLoading(false)
- return
- }
- const meta: Meta = {
- createSignature,
- keys,
- modifiedAt: unixNow(),
- docSignatures: {}
- }
-
- setLoadingSpinnerDesc('Updating user app data')
- const event = await updateUsersAppData(meta)
- if (!event) {
- setIsLoading(false)
- return
- }
-
- setLoadingSpinnerDesc('Sending notifications to counterparties')
- const promises = sendNotifications(meta)
-
- await Promise.all(promises)
- .then(() => {
- toast.success('Notifications sent successfully')
- })
- .catch(() => {
- toast.error('Failed to publish notifications')
- })
-
- navigate(appPrivateRoutes.sign, { state: { meta: meta } })
- } else {
- const zip = new JSZip()
-
- selectedFiles.forEach((file) => {
- zip.file(`files/${file.name}`, file)
- })
-
- setLoadingSpinnerDesc('Generating create signature')
- const createSignature = await generateCreateSignature(fileHashes, '')
- if (!createSignature) {
- setIsLoading(false)
- return
- }
-
- const meta: Meta = {
- createSignature,
- modifiedAt: unixNow(),
- docSignatures: {}
- }
-
- // add meta to zip
- try {
- const stringifiedMeta = JSON.stringify(meta, null, 2)
- zip.file('meta.json', stringifiedMeta)
- } catch (err) {
- console.error(err)
- toast.error('An error occurred in converting meta json to string')
- return null
- }
-
- const arrayBuffer = await generateZipFile(zip)
- if (!arrayBuffer) {
- setIsLoading(false)
- return
- }
-
- setLoadingSpinnerDesc('Encrypting zip file')
- const encryptedArrayBuffer = await encryptZipFile(
- arrayBuffer,
- encryptionKey
- )
-
- await handleOfflineFlow(encryptedArrayBuffer, encryptionKey)
}
}
@@ -893,7 +893,7 @@ export const CreatePage = () => {
{selectedFiles.length > 0 &&
selectedFiles.map((file, index) => (
- {
@@ -901,32 +901,32 @@ export const CreatePage = () => {
setCurrentFile(file)
}}
>
- <>
- {file.name}
-
- >
-
+ {file.name}
+
+
))}
+
}
right={
diff --git a/src/pages/sign/index.tsx b/src/pages/sign/index.tsx
index 7ca88e6..8720954 100644
--- a/src/pages/sign/index.tsx
+++ b/src/pages/sign/index.tsx
@@ -542,10 +542,13 @@ export const SignPage = () => {
setLoadingSpinnerDesc('Signing nostr event')
const prevSig = getPrevSignersSig(hexToNpub(usersPubkey!))
- if (!prevSig) return
+ if (!prevSig) {
+ setIsLoading(false)
+ toast.error('Previous signature is invalid')
+ return
+ }
- const marks = getSignerMarksForMeta()
- if (!marks) return
+ const marks = getSignerMarksForMeta() || []
const signedEvent = await signEventForMeta({ prevSig, marks })
if (!signedEvent) return
diff --git a/src/types/errors/MetaParseError.ts b/src/types/errors/MetaParseError.ts
new file mode 100644
index 0000000..96adab5
--- /dev/null
+++ b/src/types/errors/MetaParseError.ts
@@ -0,0 +1,23 @@
+import { Jsonable } from '.'
+
+// Reuse common error messages for meta parsing
+export enum MetaParseErrorType {
+ 'PARSE_ERROR_EVENT' = 'error occurred in parsing the create signature event',
+ 'PARSE_ERROR_SIGNATURE_EVENT_CONTENT' = "err in parsing the createSignature event's content"
+}
+
+export class MetaParseError extends Error {
+ public readonly context?: Jsonable
+
+ constructor(
+ message: string,
+ options: { cause?: Error; context?: Jsonable } = {}
+ ) {
+ const { cause, context } = options
+
+ super(message, { cause })
+ this.name = this.constructor.name
+
+ this.context = context
+ }
+}
diff --git a/src/types/errors/index.ts b/src/types/errors/index.ts
new file mode 100644
index 0000000..6ef8990
--- /dev/null
+++ b/src/types/errors/index.ts
@@ -0,0 +1,29 @@
+export type Jsonable =
+ | string
+ | number
+ | boolean
+ | null
+ | undefined
+ | readonly Jsonable[]
+ | { readonly [key: string]: Jsonable }
+ | { toJSON(): Jsonable }
+
+/**
+ * Handle errors
+ * Wraps the errors without message property and stringify to a message so we can use it later
+ * @param error
+ * @returns
+ */
+export function handleError(error: unknown): Error {
+ if (error instanceof Error) return error
+
+ // No message error, wrap it and stringify
+ let stringified = 'Unable to stringify the thrown value'
+ try {
+ stringified = JSON.stringify(error)
+ } catch (error) {
+ console.error(stringified, error)
+ }
+
+ return new Error(`Wrapped Error: ${stringified}`)
+}
diff --git a/src/utils/mark.ts b/src/utils/mark.ts
index effa2ba..44540c4 100644
--- a/src/utils/mark.ts
+++ b/src/utils/mark.ts
@@ -47,7 +47,7 @@ const filterMarksByPubkey = (marks: Mark[], pubkey: string): Mark[] => {
/**
* Takes Signed Doc Signatures part of Meta and extracts
- * all Marks into one flar array, regardless of the user.
+ * all Marks into one flat array, regardless of the user.
* @param meta
*/
const extractMarksFromSignedMeta = (meta: Meta): Mark[] => {
diff --git a/src/utils/meta.ts b/src/utils/meta.ts
index fd3481c..c915f66 100644
--- a/src/utils/meta.ts
+++ b/src/utils/meta.ts
@@ -3,6 +3,11 @@ import { fromUnixTimestamp, parseJson } from '.'
import { Event, verifyEvent } from 'nostr-tools'
import { toast } from 'react-toastify'
import { extractFileExtensions } from './file'
+import { handleError } from '../types/errors'
+import {
+ MetaParseError,
+ MetaParseErrorType
+} from '../types/errors/MetaParseError'
export enum SignStatus {
Signed = 'Signed',
@@ -17,58 +22,6 @@ export enum SigitStatus {
Complete = 'Completed'
}
-type Jsonable =
- | string
- | number
- | boolean
- | null
- | undefined
- | readonly Jsonable[]
- | { readonly [key: string]: Jsonable }
- | { toJSON(): Jsonable }
-
-export class SigitMetaParseError extends Error {
- public readonly context?: Jsonable
-
- constructor(
- message: string,
- options: { cause?: Error; context?: Jsonable } = {}
- ) {
- const { cause, context } = options
-
- super(message, { cause })
- this.name = this.constructor.name
-
- this.context = context
- }
-}
-
-/**
- * Handle meta errors
- * Wraps the errors without message property and stringify to a message so we can use it later
- * @param error
- * @returns
- */
-function handleError(error: unknown): Error {
- if (error instanceof Error) return error
-
- // No message error, wrap it and stringify
- let stringified = 'Unable to stringify the thrown value'
- try {
- stringified = JSON.stringify(error)
- } catch (error) {
- console.error(stringified, error)
- }
-
- return new Error(`[SiGit Error]: ${stringified}`)
-}
-
-// Reuse common error messages for meta parsing
-export enum SigitMetaParseErrorType {
- 'PARSE_ERROR_EVENT' = 'error occurred in parsing the create signature event',
- 'PARSE_ERROR_SIGNATURE_EVENT_CONTENT' = "err in parsing the createSignature event's content"
-}
-
export interface SigitCardDisplayInfo {
createdAt?: number
title?: string
@@ -89,7 +42,7 @@ export const parseNostrEvent = async (raw: string): Promise
=> {
const event = await parseJson(raw)
return event
} catch (error) {
- throw new SigitMetaParseError(SigitMetaParseErrorType.PARSE_ERROR_EVENT, {
+ throw new MetaParseError(MetaParseErrorType.PARSE_ERROR_EVENT, {
cause: handleError(error),
context: raw
})
@@ -109,8 +62,8 @@ export const parseCreateSignatureEventContent = async (
await parseJson(raw)
return createSignatureEventContent
} catch (error) {
- throw new SigitMetaParseError(
- SigitMetaParseErrorType.PARSE_ERROR_SIGNATURE_EVENT_CONTENT,
+ throw new MetaParseError(
+ MetaParseErrorType.PARSE_ERROR_SIGNATURE_EVENT_CONTENT,
{
cause: handleError(error),
context: raw
@@ -165,7 +118,7 @@ export const extractSigitCardDisplayInfo = async (meta: Meta) => {
return sigitInfo
} catch (error) {
- if (error instanceof SigitMetaParseError) {
+ if (error instanceof MetaParseError) {
toast.error(error.message)
console.error(error.name, error.message, error.cause, error.context)
} else {