feat(opentimestamps): adds OTS library and retrier function

This commit is contained in:
eugene 2024-09-26 15:50:28 +03:00
parent 9432e99b3b
commit edfe9a2954
7 changed files with 97 additions and 1 deletions

View File

@ -6,7 +6,7 @@ module.exports = {
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended'
],
ignorePatterns: ['dist', '.eslintrc.cjs', 'licenseChecker.cjs'],
ignorePatterns: ['dist', '.eslintrc.cjs', 'licenseChecker.cjs', "*.min.js"],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
rules: {

View File

@ -8,6 +8,7 @@
</head>
<body>
<div id="root"></div>
<script src="/opentimestamps.min.js"></script>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

2
public/opentimestamps.min.js vendored Normal file

File diff suppressed because one or more lines are too long

28
src/types/opentimestamps.d.ts vendored Normal file
View File

@ -0,0 +1,28 @@
interface OpenTimestamps {
// Create a detached timestamp file from a buffer or file hash
DetachedTimestampFile: {
fromHash(op: any, hash: Uint8Array): any
}
// Stamp the provided timestamp file and return a Promise
stamp(file: any): Promise<void>
// Verify the provided timestamp proof file
verify(file: any): Promise<void>
// Other utilities or operations (like OpSHA256, serialization)
Ops: {
OpSHA256: any
OpSHA1?: any
}
Context: {
StreamSerialization: any
}
// Load a timestamp file from a buffer
deserialize(bytes: Uint8Array): any
// Other potential methods based on repo functions
upgrade(file: any): Promise<void>
}

View File

@ -3,5 +3,6 @@ import type { WindowNostr } from 'nostr-tools/nip07'
declare global {
interface Window {
nostr?: WindowNostr
OpenTimestamps: OpenTimestamps
}
}

View File

@ -0,0 +1,39 @@
import { Timestamp } from '../types'
import { isPromiseFulfilled } from './utils.ts'
import { retryAll } from './retry.ts'
import { bytesToHex, hexToBytes } from '@noble/hashes/utils'
/**
* Generates a timestamp for the provided document hashes.
* @returns Timestamp in a hex string format
*/
export const generateTimestamps = async (
fileHashes: string[]
): Promise<Timestamp[] | undefined> => {
const promises = fileHashes.map((fileHash) => () => timestamp(fileHash))
const resolvedPromises = await retryAll(promises)
if (resolvedPromises.every(isPromiseFulfilled)) {
return resolvedPromises.map(({ value }, index) => {
return {
fileHash: fileHashes[index],
timestamp: value
}
})
}
}
const timestamp = async (hash: string) => {
const detachedTimestamp =
window.OpenTimestamps.DetachedTimestampFile.fromHash(
new window.OpenTimestamps.Ops.OpSHA256(),
hexToBytes(hash)
)
await window.OpenTimestamps.stamp(detachedTimestamp)
const ctx = new window.OpenTimestamps.Context.StreamSerialization()
detachedTimestamp.serialize(ctx)
const timestampBytes = ctx.getOutput()
const hex = bytesToHex(timestampBytes)
return hex
}

25
src/utils/retry.ts Normal file
View File

@ -0,0 +1,25 @@
export const retryAll = async <T>(
promises: (() => Promise<T>)[],
retries: number = 3,
delay: number = 1000
) => {
const wrappedPromises = promises.map((fn) => retry(fn, retries, delay))
return Promise.allSettled(wrappedPromises)
}
export const retry = async <T>(
fn: () => Promise<T>,
retries: number = 3,
delay: number = 1000
): Promise<T> => {
try {
return await fn()
} catch (err) {
if (retries === 0) {
return Promise.reject(err)
}
return new Promise((resolve) =>
setTimeout(() => resolve(retry(fn, retries - 1)), delay)
)
}
}