1
- import { Hono } from 'hono'
2
- import { HonoEnv } from '../utils/constants'
3
1
import { vValidator } from '@hono/valibot-validator'
4
- import { blob , object , union , array } from 'valibot'
5
- import { getUint8ArrayFromFile , getObjectSize , hashOf , keyOf } from '../utils/format'
2
+ import { Hono } from 'hono'
3
+ import { array , blob , object , union } from 'valibot'
4
+ import type { HonoEnv } from '../utils/constants'
5
+ import {
6
+ getObjectSize ,
7
+ getUint8ArrayFromFile ,
8
+ hashOf ,
9
+ keyOf ,
10
+ } from '../utils/format'
11
+ import toCar from '../utils/ipfs'
6
12
import { getS3 } from '../utils/s3'
7
- import { getDirectoryCID } from '../utils/helia'
8
13
9
14
const app = new Hono < HonoEnv > ( )
10
15
11
16
app . post ( '/pinJson' , vValidator ( 'json' , object ( { } ) ) , async ( c ) => {
12
- const body = await c . req . json ( )
13
- const type = 'application/json'
14
- const s3 = getS3 ( c )
15
-
16
- const content = JSON . stringify ( body )
17
- const cid = ( await hashOf ( content ) ) . toV0 ( ) . toString ( )
18
-
19
- await s3 . putObject ( {
20
- Body : content ,
21
- Bucket : c . env . FILEBASE_BUCKET_NAME ,
22
- Key : cid ,
23
- ContentType : type ,
24
- } )
25
-
26
- c . executionCtx . waitUntil ( c . env . BUCKET . put ( keyOf ( cid ) , new Blob ( [ content ] , { type } ) ) )
27
-
28
- return c . json (
29
- getPinResponse ( {
30
- cid : cid ,
31
- type : type ,
32
- size : getObjectSize ( body ) ,
33
- } ) ,
34
- )
17
+ const body = await c . req . json ( )
18
+ const type = 'application/json'
19
+ const s3 = getS3 ( c )
20
+
21
+ const content = JSON . stringify ( body )
22
+ const cid = ( await hashOf ( content ) ) . toV0 ( ) . toString ( )
23
+
24
+ await s3 . putObject ( {
25
+ Body : content ,
26
+ Bucket : c . env . FILEBASE_BUCKET_NAME ,
27
+ Key : cid ,
28
+ ContentType : type ,
29
+ } )
30
+
31
+ c . executionCtx . waitUntil (
32
+ c . env . BUCKET . put ( keyOf ( cid ) , new Blob ( [ content ] , { type } ) ) ,
33
+ )
34
+
35
+ return c . json (
36
+ getPinResponse ( {
37
+ cid : cid ,
38
+ type : type ,
39
+ size : getObjectSize ( body ) ,
40
+ } ) ,
41
+ )
35
42
} )
36
43
37
44
const fileRequiredMessage = 'File is required'
@@ -40,85 +47,85 @@ const fileKey = 'file'
40
47
type PinFile = { [ fileKey ] : File } | { [ fileKey ] : File [ ] }
41
48
42
49
const pinFileRequestSchema = object ( {
43
- [ fileKey ] : union ( [
44
- blob ( fileRequiredMessage ) ,
45
- array ( blob ( fileRequiredMessage ) ) ,
46
- ] ) ,
50
+ [ fileKey ] : union ( [
51
+ blob ( fileRequiredMessage ) ,
52
+ array ( blob ( fileRequiredMessage ) ) ,
53
+ ] ) ,
47
54
} )
48
55
49
56
app . post ( '/pinFile' , vValidator ( 'form' , pinFileRequestSchema ) , async ( c ) => {
50
- const body = ( await c . req . parseBody ( { all : true } ) ) as PinFile
51
-
52
- const files = await Promise . all (
53
- ( [ [ body [ fileKey ] ] ] . flat ( 2 ) . filter ( Boolean ) as File [ ] ) . map ( async ( file ) => ( {
54
- file,
55
- content : await getUint8ArrayFromFile ( file ) ,
56
- } ) ) ,
57
- )
58
-
59
- const hasMultipleFiles = files . length > 1
60
- const s3 = getS3 ( c )
61
-
62
- let directoryCId : string | undefined
63
-
64
- if ( hasMultipleFiles ) {
65
- directoryCId = ( await getDirectoryCID ( { files , c } ) ) . toV0 ( ) . toString ( )
66
- }
67
-
68
- const addedFiles : { file : File ; cid : string ; content : Uint8Array } [ ] =
69
- await Promise . all (
70
- files . map ( async ( { file , content } ) => {
71
- try {
72
- const cid = ( await hashOf ( content ) ) . toV0 ( ) . toString ( )
73
- const prefix = directoryCId ? ` ${ directoryCId } /` : ''
74
-
75
- await s3 . putObject ( {
76
- Body : content ,
77
- Bucket : c . env . FILEBASE_BUCKET_NAME ,
78
- Key : ` ${ prefix } ${ cid } ` ,
79
- ContentType : file . type ,
80
- } )
81
-
82
- console . log ( 'File added' , cid )
83
- return { file , cid , content }
84
- } catch ( error ) {
85
- throw new Error ( `Failed to add file ${ file . name } : ${ error ?. message } ` )
86
- }
87
- } ) ,
88
- )
89
-
90
- c . executionCtx . waitUntil (
91
- Promise . all (
92
- addedFiles . map ( ( { content , cid } ) => c . env . BUCKET . put ( keyOf ( cid ) , content ) ) ,
93
- ) ,
94
- )
95
-
96
- const size = files . reduce ( ( reducer , file ) => reducer + file . file . size , 0 )
97
- const { cid : addedFileCid , file } = addedFiles [ 0 ]
98
- let cid = addedFileCid
99
- let type = file . type
100
-
101
- if ( hasMultipleFiles ) {
102
- cid = directoryCId as string
103
- type = 'directory'
104
- }
105
-
106
- return c . json (
107
- getPinResponse ( {
108
- cid : cid ,
109
- type : type ,
110
- size : size ,
111
- } ) ,
112
- )
57
+ const body = ( await c . req . parseBody ( { all : true } ) ) as PinFile
58
+
59
+ const files = await Promise . all (
60
+ ( [ [ body [ fileKey ] ] ] . flat ( 2 ) . filter ( Boolean ) as File [ ] ) . map ( async ( file ) => ( {
61
+ file,
62
+ content : await getUint8ArrayFromFile ( file ) ,
63
+ } ) ) ,
64
+ )
65
+
66
+ const s3 = getS3 ( c )
67
+
68
+ let cid : string
69
+ let file : Uint8Array | File
70
+ let size : number
71
+ let type : string
72
+
73
+ if ( files . length > 1 ) {
74
+ const { root , car } = await toCar (
75
+ files . map ( ( { file, content } ) => ( {
76
+ path : file . name ,
77
+ content : content ,
78
+ } ) ) ,
79
+ )
80
+
81
+ cid = root . toString ( ) as string
82
+ file = car
83
+ size = file . byteLength
84
+ type = 'directory'
85
+
86
+ await s3 . putObject ( {
87
+ Body : car ,
88
+ Bucket : c . env . FILEBASE_BUCKET_NAME ,
89
+ Key : cid ,
90
+ ContentType : 'application/vnd.ipld.car' ,
91
+ Metadata : {
92
+ import : 'car' ,
93
+ } ,
94
+ } )
95
+ } else {
96
+ const { content , file : f } = files [ 0 ]
97
+ cid = ( await hashOf ( content ) ) . toV0 ( ) . toString ( )
98
+
99
+ file = f
100
+ size = f . size
101
+ type = f . type
102
+
103
+ await s3 . putObject ( {
104
+ Body : content ,
105
+ Bucket : c . env . FILEBASE_BUCKET_NAME ,
106
+ Key : cid ,
107
+ ContentType : f . type ,
108
+ } )
109
+ }
110
+
111
+ c . executionCtx . waitUntil ( c . env . BUCKET . put ( keyOf ( cid ) , file ) )
112
+
113
+ return c . json (
114
+ getPinResponse ( {
115
+ cid : cid ,
116
+ type : type ,
117
+ size : size ,
118
+ } ) ,
119
+ )
113
120
} )
114
121
115
122
const getPinResponse = ( value : {
116
- cid : string
117
- type : string
118
- size : number
123
+ cid : string
124
+ type : string
125
+ size : number
119
126
} ) => ( {
120
- ok : true ,
121
- value,
127
+ ok : true ,
128
+ value,
122
129
} )
123
130
124
131
export { app as pinning }
0 commit comments