@hugomrdias/foxer 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -0
- package/dist/src/api/index.d.ts +2 -0
- package/dist/src/api/index.d.ts.map +1 -0
- package/dist/src/api/index.js +2 -0
- package/dist/src/api/index.js.map +1 -0
- package/dist/src/api/runner.d.ts +12 -0
- package/dist/src/api/runner.d.ts.map +1 -0
- package/dist/src/api/runner.js +29 -0
- package/dist/src/api/runner.js.map +1 -0
- package/dist/src/api/server.d.ts +18 -0
- package/dist/src/api/server.d.ts.map +1 -0
- package/dist/src/api/server.js +21 -0
- package/dist/src/api/server.js.map +1 -0
- package/dist/src/api/sql-middleware.d.ts +7 -0
- package/dist/src/api/sql-middleware.d.ts.map +1 -0
- package/dist/src/api/sql-middleware.js +95 -0
- package/dist/src/api/sql-middleware.js.map +1 -0
- package/dist/src/api/sql.d.ts +14 -0
- package/dist/src/api/sql.d.ts.map +1 -0
- package/dist/src/api/sql.js +108 -0
- package/dist/src/api/sql.js.map +1 -0
- package/dist/src/api/sse.d.ts +3 -0
- package/dist/src/api/sse.d.ts.map +1 -0
- package/dist/src/api/sse.js +11 -0
- package/dist/src/api/sse.js.map +1 -0
- package/dist/src/bin/dev.d.ts +3 -0
- package/dist/src/bin/dev.d.ts.map +1 -0
- package/dist/src/bin/dev.js +76 -0
- package/dist/src/bin/dev.js.map +1 -0
- package/dist/src/bin/flags.d.ts +32 -0
- package/dist/src/bin/flags.d.ts.map +1 -0
- package/dist/src/bin/flags.js +55 -0
- package/dist/src/bin/flags.js.map +1 -0
- package/dist/src/bin/index.d.ts +3 -0
- package/dist/src/bin/index.d.ts.map +1 -0
- package/dist/src/bin/index.js +22 -0
- package/dist/src/bin/index.js.map +1 -0
- package/dist/src/bin/utils.d.ts +4 -0
- package/dist/src/bin/utils.d.ts.map +1 -0
- package/dist/src/bin/utils.js +52 -0
- package/dist/src/bin/utils.js.map +1 -0
- package/dist/src/client/index.d.ts +18 -0
- package/dist/src/client/index.d.ts.map +1 -0
- package/dist/src/client/index.js +150 -0
- package/dist/src/client/index.js.map +1 -0
- package/dist/src/config/config.d.ts +157 -0
- package/dist/src/config/config.d.ts.map +1 -0
- package/dist/src/config/config.js +65 -0
- package/dist/src/config/config.js.map +1 -0
- package/dist/src/config/env.d.ts +25 -0
- package/dist/src/config/env.d.ts.map +1 -0
- package/dist/src/config/env.js +21 -0
- package/dist/src/config/env.js.map +1 -0
- package/dist/src/contants.d.ts +4 -0
- package/dist/src/contants.d.ts.map +1 -0
- package/dist/src/contants.js +4 -0
- package/dist/src/contants.js.map +1 -0
- package/dist/src/db/actions/blocks.d.ts +44 -0
- package/dist/src/db/actions/blocks.d.ts.map +1 -0
- package/dist/src/db/actions/blocks.js +152 -0
- package/dist/src/db/actions/blocks.js.map +1 -0
- package/dist/src/db/actions/index.d.ts +2 -0
- package/dist/src/db/actions/index.d.ts.map +1 -0
- package/dist/src/db/actions/index.js +2 -0
- package/dist/src/db/actions/index.js.map +1 -0
- package/dist/src/db/actions/transactions.d.ts +11 -0
- package/dist/src/db/actions/transactions.d.ts.map +1 -0
- package/dist/src/db/actions/transactions.js +22 -0
- package/dist/src/db/actions/transactions.js.map +1 -0
- package/dist/src/db/client.d.ts +329 -0
- package/dist/src/db/client.d.ts.map +1 -0
- package/dist/src/db/client.js +108 -0
- package/dist/src/db/client.js.map +1 -0
- package/dist/src/db/column-types.d.ts +132 -0
- package/dist/src/db/column-types.d.ts.map +1 -0
- package/dist/src/db/column-types.js +86 -0
- package/dist/src/db/column-types.js.map +1 -0
- package/dist/src/db/encode.d.ts +10 -0
- package/dist/src/db/encode.d.ts.map +1 -0
- package/dist/src/db/encode.js +79 -0
- package/dist/src/db/encode.js.map +1 -0
- package/dist/src/db/migrate.d.ts +31 -0
- package/dist/src/db/migrate.d.ts.map +1 -0
- package/dist/src/db/migrate.js +147 -0
- package/dist/src/db/migrate.js.map +1 -0
- package/dist/src/db/schema/blocks.d.ts +369 -0
- package/dist/src/db/schema/blocks.d.ts.map +1 -0
- package/dist/src/db/schema/blocks.js +24 -0
- package/dist/src/db/schema/blocks.js.map +1 -0
- package/dist/src/db/schema/index.d.ts +1415 -0
- package/dist/src/db/schema/index.d.ts.map +1 -0
- package/dist/src/db/schema/index.js +18 -0
- package/dist/src/db/schema/index.js.map +1 -0
- package/dist/src/db/schema/transactions.d.ts +336 -0
- package/dist/src/db/schema/transactions.d.ts.map +1 -0
- package/dist/src/db/schema/transactions.js +33 -0
- package/dist/src/db/schema/transactions.js.map +1 -0
- package/dist/src/db/transaction.d.ts +7 -0
- package/dist/src/db/transaction.d.ts.map +1 -0
- package/dist/src/db/transaction.js +8 -0
- package/dist/src/db/transaction.js.map +1 -0
- package/dist/src/hooks/default-hooks.d.ts +2 -0
- package/dist/src/hooks/default-hooks.d.ts.map +1 -0
- package/dist/src/hooks/default-hooks.js +107 -0
- package/dist/src/hooks/default-hooks.js.map +1 -0
- package/dist/src/hooks/registry.d.ts +51 -0
- package/dist/src/hooks/registry.d.ts.map +1 -0
- package/dist/src/hooks/registry.js +32 -0
- package/dist/src/hooks/registry.js.map +1 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/indexer/backfill.d.ts +15 -0
- package/dist/src/indexer/backfill.d.ts.map +1 -0
- package/dist/src/indexer/backfill.js +95 -0
- package/dist/src/indexer/backfill.js.map +1 -0
- package/dist/src/indexer/live.d.ts +20 -0
- package/dist/src/indexer/live.d.ts.map +1 -0
- package/dist/src/indexer/live.js +51 -0
- package/dist/src/indexer/live.js.map +1 -0
- package/dist/src/indexer/process-block.d.ts +29 -0
- package/dist/src/indexer/process-block.d.ts.map +1 -0
- package/dist/src/indexer/process-block.js +91 -0
- package/dist/src/indexer/process-block.js.map +1 -0
- package/dist/src/indexer/queue-block.d.ts +18 -0
- package/dist/src/indexer/queue-block.d.ts.map +1 -0
- package/dist/src/indexer/queue-block.js +38 -0
- package/dist/src/indexer/queue-block.js.map +1 -0
- package/dist/src/indexer/reorg.d.ts +24 -0
- package/dist/src/indexer/reorg.d.ts.map +1 -0
- package/dist/src/indexer/reorg.js +83 -0
- package/dist/src/indexer/reorg.js.map +1 -0
- package/dist/src/indexer/runner.d.ts +14 -0
- package/dist/src/indexer/runner.d.ts.map +1 -0
- package/dist/src/indexer/runner.js +22 -0
- package/dist/src/indexer/runner.js.map +1 -0
- package/dist/src/rpc/client.d.ts +11 -0
- package/dist/src/rpc/client.d.ts.map +1 -0
- package/dist/src/rpc/client.js +18 -0
- package/dist/src/rpc/client.js.map +1 -0
- package/dist/src/rpc/get-block.d.ts +16 -0
- package/dist/src/rpc/get-block.d.ts.map +1 -0
- package/dist/src/rpc/get-block.js +77 -0
- package/dist/src/rpc/get-block.js.map +1 -0
- package/dist/src/rpc/get-logs.d.ts +11 -0
- package/dist/src/rpc/get-logs.d.ts.map +1 -0
- package/dist/src/rpc/get-logs.js +23 -0
- package/dist/src/rpc/get-logs.js.map +1 -0
- package/dist/src/schema.d.ts +3 -0
- package/dist/src/schema.d.ts.map +1 -0
- package/dist/src/schema.js +9 -0
- package/dist/src/schema.js.map +1 -0
- package/dist/src/types.d.ts +22 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +1 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/bloom.d.ts +6 -0
- package/dist/src/utils/bloom.d.ts.map +1 -0
- package/dist/src/utils/bloom.js +30 -0
- package/dist/src/utils/bloom.js.map +1 -0
- package/dist/src/utils/build-conflict-columns.d.ts +4 -0
- package/dist/src/utils/build-conflict-columns.d.ts.map +1 -0
- package/dist/src/utils/build-conflict-columns.js +14 -0
- package/dist/src/utils/build-conflict-columns.js.map +1 -0
- package/dist/src/utils/common.d.ts +2 -0
- package/dist/src/utils/common.d.ts.map +1 -0
- package/dist/src/utils/common.js +4 -0
- package/dist/src/utils/common.js.map +1 -0
- package/dist/src/utils/cursor.d.ts +5 -0
- package/dist/src/utils/cursor.d.ts.map +1 -0
- package/dist/src/utils/cursor.js +8 -0
- package/dist/src/utils/cursor.js.map +1 -0
- package/dist/src/utils/format.d.ts +2 -0
- package/dist/src/utils/format.d.ts.map +1 -0
- package/dist/src/utils/format.js +16 -0
- package/dist/src/utils/format.js.map +1 -0
- package/dist/src/utils/hash.d.ts +9 -0
- package/dist/src/utils/hash.d.ts.map +1 -0
- package/dist/src/utils/hash.js +15 -0
- package/dist/src/utils/hash.js.map +1 -0
- package/dist/src/utils/json.d.ts +5 -0
- package/dist/src/utils/json.d.ts.map +1 -0
- package/dist/src/utils/json.js +11 -0
- package/dist/src/utils/json.js.map +1 -0
- package/dist/src/utils/logger.d.ts +11 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/logger.js +111 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/dist/src/utils/shutdown.d.ts +9 -0
- package/dist/src/utils/shutdown.d.ts.map +1 -0
- package/dist/src/utils/shutdown.js +24 -0
- package/dist/src/utils/shutdown.js.map +1 -0
- package/dist/src/utils/timer.d.ts +6 -0
- package/dist/src/utils/timer.d.ts.map +1 -0
- package/dist/src/utils/timer.js +9 -0
- package/dist/src/utils/timer.js.map +1 -0
- package/dist/src/utils/types.d.ts +39 -0
- package/dist/src/utils/types.d.ts.map +1 -0
- package/dist/src/utils/types.js +1 -0
- package/dist/src/utils/types.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/hello/apps/foc-api/README.md +69 -0
- package/hello/apps/foc-api/biome.json +8 -0
- package/hello/apps/foc-api/index.html +13 -0
- package/hello/apps/foc-api/package.json +39 -0
- package/hello/apps/foc-api/public/vite.svg +1 -0
- package/hello/apps/foc-api/src/app.css +45 -0
- package/hello/apps/foc-api/src/app.tsx +43 -0
- package/hello/apps/foc-api/src/assets/Cloudflare_Logo.svg +51 -0
- package/hello/apps/foc-api/src/assets/react.svg +1 -0
- package/hello/apps/foc-api/src/client.ts +41 -0
- package/hello/apps/foc-api/src/components/account.tsx +100 -0
- package/hello/apps/foc-api/src/components/wallet-options.tsx +43 -0
- package/hello/apps/foc-api/src/index.css +68 -0
- package/hello/apps/foc-api/src/main.tsx +38 -0
- package/hello/apps/foc-api/src/vite-env.d.ts +1 -0
- package/hello/apps/foc-api/tsconfig.app.json +44 -0
- package/hello/apps/foc-api/tsconfig.json +17 -0
- package/hello/apps/foc-api/tsconfig.node.json +25 -0
- package/hello/apps/foc-api/tsconfig.worker.json +8 -0
- package/hello/apps/foc-api/vite.config.ts +8 -0
- package/hello/apps/foc-api/worker/capabilities.ts +25 -0
- package/hello/apps/foc-api/worker/index.ts +64 -0
- package/hello/apps/foc-api/worker/router.ts +35 -0
- package/hello/apps/foc-api/worker-configuration.d.ts +7357 -0
- package/hello/apps/foc-api/wrangler.jsonc +50 -0
- package/hello/apps/foc-app/README.md +69 -0
- package/hello/apps/foc-app/biome.json +8 -0
- package/hello/apps/foc-app/index.html +13 -0
- package/hello/apps/foc-app/package.json +39 -0
- package/hello/apps/foc-app/public/vite.svg +1 -0
- package/hello/apps/foc-app/src/app.css +45 -0
- package/hello/apps/foc-app/src/app.tsx +43 -0
- package/hello/apps/foc-app/src/assets/Cloudflare_Logo.svg +51 -0
- package/hello/apps/foc-app/src/assets/react.svg +1 -0
- package/hello/apps/foc-app/src/client.ts +41 -0
- package/hello/apps/foc-app/src/components/account.tsx +100 -0
- package/hello/apps/foc-app/src/components/wallet-options.tsx +43 -0
- package/hello/apps/foc-app/src/index.css +68 -0
- package/hello/apps/foc-app/src/main.tsx +38 -0
- package/hello/apps/foc-app/src/vite-env.d.ts +1 -0
- package/hello/apps/foc-app/tsconfig.app.json +44 -0
- package/hello/apps/foc-app/tsconfig.json +17 -0
- package/hello/apps/foc-app/tsconfig.node.json +25 -0
- package/hello/apps/foc-app/tsconfig.worker.json +8 -0
- package/hello/apps/foc-app/vite.config.ts +8 -0
- package/hello/apps/foc-app/worker/capabilities.ts +25 -0
- package/hello/apps/foc-app/worker/index.ts +64 -0
- package/hello/apps/foc-app/worker/router.ts +35 -0
- package/hello/apps/foc-app/worker-configuration.d.ts +7357 -0
- package/hello/apps/foc-app/wrangler.jsonc +50 -0
- package/hello/biome.json +50 -0
- package/hello/package.json +22 -0
- package/hello/pnpm-workspace.yaml +3 -0
- package/hello/tsconfig.json +37 -0
- package/package.json +78 -0
- package/src/api/index.ts +1 -0
- package/src/api/runner.ts +43 -0
- package/src/api/server.ts +38 -0
- package/src/api/sql-middleware.ts +131 -0
- package/src/api/sql.ts +149 -0
- package/src/api/sse.ts +12 -0
- package/src/bin/create.ts +199 -0
- package/src/bin/dev.ts +91 -0
- package/src/bin/flags.ts +65 -0
- package/src/bin/index.ts +28 -0
- package/src/bin/utils.ts +55 -0
- package/src/config/config.ts +221 -0
- package/src/config/env.ts +28 -0
- package/src/contants.ts +3 -0
- package/src/db/actions/blocks.ts +209 -0
- package/src/db/actions/index.ts +1 -0
- package/src/db/actions/transactions.ts +32 -0
- package/src/db/client.ts +186 -0
- package/src/db/column-types.ts +105 -0
- package/src/db/encode.ts +99 -0
- package/src/db/migrate.ts +222 -0
- package/src/db/schema/blocks.ts +24 -0
- package/src/db/schema/index.ts +21 -0
- package/src/db/schema/transactions.ts +39 -0
- package/src/db/transaction.ts +20 -0
- package/src/hooks/registry.ts +107 -0
- package/src/index.ts +9 -0
- package/src/indexer/backfill.ts +133 -0
- package/src/indexer/live.ts +76 -0
- package/src/indexer/process-block.ts +142 -0
- package/src/indexer/queue-block.ts +74 -0
- package/src/indexer/reorg.ts +120 -0
- package/src/indexer/runner.ts +35 -0
- package/src/rpc/client.ts +27 -0
- package/src/rpc/get-block.ts +100 -0
- package/src/rpc/get-logs.ts +38 -0
- package/src/schema.ts +10 -0
- package/src/types.ts +32 -0
- package/src/utils/bloom.ts +41 -0
- package/src/utils/build-conflict-columns.ts +26 -0
- package/src/utils/common.ts +3 -0
- package/src/utils/cursor.ts +7 -0
- package/src/utils/format.ts +18 -0
- package/src/utils/hash.ts +17 -0
- package/src/utils/json.ts +11 -0
- package/src/utils/logger.ts +149 -0
- package/src/utils/shutdown.ts +36 -0
- package/src/utils/timer.ts +8 -0
- package/src/utils/types.ts +87 -0
- package/template/biome.json +50 -0
- package/template/package.json +22 -0
- package/template/pnpm-workspace.yaml +3 -0
- package/template/tsconfig.json +37 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import {
|
|
2
|
+
copyFileSync,
|
|
3
|
+
existsSync,
|
|
4
|
+
mkdirSync,
|
|
5
|
+
readdirSync,
|
|
6
|
+
readFileSync,
|
|
7
|
+
statSync,
|
|
8
|
+
writeFileSync,
|
|
9
|
+
} from 'node:fs'
|
|
10
|
+
import { basename, dirname, relative, resolve } from 'node:path'
|
|
11
|
+
import { fileURLToPath } from 'node:url'
|
|
12
|
+
import { downloadTemplate } from '@bluwy/giget-core'
|
|
13
|
+
import * as p from '@clack/prompts'
|
|
14
|
+
import { type Command, command } from 'cleye'
|
|
15
|
+
|
|
16
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
17
|
+
|
|
18
|
+
const possibleTemplates = ['app', 'cli'] as const
|
|
19
|
+
type Templates = (typeof possibleTemplates)[number]
|
|
20
|
+
|
|
21
|
+
const Template = (template: Templates) => {
|
|
22
|
+
if (!possibleTemplates.includes(template)) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
`Invalid template: "${template}" (must be one of ${possibleTemplates.join(', ')})`
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
return template
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface PkgInfo {
|
|
31
|
+
name: string
|
|
32
|
+
version: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function pkgFromUserAgent(userAgent: string | undefined): PkgInfo | undefined {
|
|
36
|
+
if (!userAgent) return undefined
|
|
37
|
+
const pkgSpec = userAgent.split(' ')[0]
|
|
38
|
+
const pkgSpecArr = pkgSpec.split('/')
|
|
39
|
+
return {
|
|
40
|
+
name: pkgSpecArr[0],
|
|
41
|
+
version: pkgSpecArr[1],
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function formatTargetDir(targetDir: string) {
|
|
46
|
+
return targetDir
|
|
47
|
+
.trim()
|
|
48
|
+
.replace(/[<>:"\\|?*]/g, '')
|
|
49
|
+
.replace(/\/+$/g, '')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function isEmpty(path: string) {
|
|
53
|
+
const files = readdirSync(path)
|
|
54
|
+
return files.length === 0 || (files.length === 1 && files[0] === '.git')
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isValidPackageName(projectName: string) {
|
|
58
|
+
return /^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(
|
|
59
|
+
projectName
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function toValidPackageName(projectName: string) {
|
|
64
|
+
return projectName
|
|
65
|
+
.trim()
|
|
66
|
+
.toLowerCase()
|
|
67
|
+
.replace(/\s+/g, '-')
|
|
68
|
+
.replace(/^[._]/, '')
|
|
69
|
+
.replace(/[^a-z\d\-~]+/g, '-')
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function copy(src: string, dest: string) {
|
|
73
|
+
const stat = statSync(src)
|
|
74
|
+
if (stat.isDirectory()) {
|
|
75
|
+
copyDir(src, dest)
|
|
76
|
+
} else {
|
|
77
|
+
copyFileSync(src, dest)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function copyDir(srcDir: string, destDir: string) {
|
|
82
|
+
mkdirSync(destDir, { recursive: true })
|
|
83
|
+
for (const file of readdirSync(srcDir)) {
|
|
84
|
+
const srcFile = resolve(srcDir, file)
|
|
85
|
+
const destFile = resolve(destDir, file)
|
|
86
|
+
copy(srcFile, destFile)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function getInstallCommand(agent: string) {
|
|
91
|
+
if (agent === 'yarn') {
|
|
92
|
+
return [agent]
|
|
93
|
+
}
|
|
94
|
+
return [agent, 'install']
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function getRunCommand(agent: string, script: string) {
|
|
98
|
+
switch (agent) {
|
|
99
|
+
case 'yarn':
|
|
100
|
+
case 'pnpm':
|
|
101
|
+
case 'bun':
|
|
102
|
+
return [agent, script]
|
|
103
|
+
case 'deno':
|
|
104
|
+
return [agent, 'task', script]
|
|
105
|
+
default:
|
|
106
|
+
return [agent, 'run', script]
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export const create: Command = command(
|
|
111
|
+
{
|
|
112
|
+
name: 'create',
|
|
113
|
+
parameters: ['<name>'],
|
|
114
|
+
flags: {
|
|
115
|
+
template: {
|
|
116
|
+
type: Template,
|
|
117
|
+
default: 'app',
|
|
118
|
+
description: 'The template to use for the new project (app, cli)',
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
help: {
|
|
122
|
+
description: 'Create a new project',
|
|
123
|
+
examples: [`foxer create <name>`],
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
async (argv) => {
|
|
127
|
+
const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent)
|
|
128
|
+
const pm = pkgInfo ? pkgInfo.name : 'npm'
|
|
129
|
+
const targetDir = formatTargetDir(argv._.name)
|
|
130
|
+
const cwd = process.cwd()
|
|
131
|
+
const root = resolve(cwd, targetDir)
|
|
132
|
+
|
|
133
|
+
if (existsSync(root) && !isEmpty(root)) {
|
|
134
|
+
p.log.error('Directory already exists and is not empty')
|
|
135
|
+
process.exit(1)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let packageName = basename(resolve(targetDir))
|
|
139
|
+
if (!isValidPackageName(packageName)) {
|
|
140
|
+
packageName = toValidPackageName(packageName)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
let template = argv.flags.template
|
|
144
|
+
if (!possibleTemplates.includes(template as Templates)) {
|
|
145
|
+
template = 'app'
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
mkdirSync(root, { recursive: true })
|
|
149
|
+
p.log.step(`Scaffolding project in ${root}...`)
|
|
150
|
+
|
|
151
|
+
const pkg = JSON.parse(
|
|
152
|
+
readFileSync(resolve(__dirname, `../../template/package.json`), 'utf-8')
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
pkg.name = packageName
|
|
156
|
+
|
|
157
|
+
writeFileSync(
|
|
158
|
+
resolve(root, 'package.json'),
|
|
159
|
+
`${JSON.stringify(pkg, null, 2)}\n`
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
if (pm === 'pnpm') {
|
|
163
|
+
copy(
|
|
164
|
+
resolve(__dirname, `../../template/pnpm-workspace.yaml`),
|
|
165
|
+
resolve(root, 'pnpm-workspace.yaml')
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
copy(
|
|
170
|
+
resolve(__dirname, `../../template/biome.json`),
|
|
171
|
+
resolve(root, 'biome.json')
|
|
172
|
+
)
|
|
173
|
+
copy(
|
|
174
|
+
resolve(__dirname, `../../template/tsconfig.json`),
|
|
175
|
+
resolve(root, 'tsconfig.json')
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
// copy apps/foc-api
|
|
179
|
+
await downloadTemplate('hugomrdias/foxer/examples/api', {
|
|
180
|
+
dir: resolve(root, 'apps/api'),
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
await downloadTemplate('hugomrdias/foxer/examples/app', {
|
|
184
|
+
dir: resolve(root, 'apps/app'),
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
let doneMessage = ''
|
|
188
|
+
const cdProjectName = relative(cwd, root)
|
|
189
|
+
doneMessage += `Done. Now run:\n`
|
|
190
|
+
if (root !== cwd) {
|
|
191
|
+
doneMessage += `\n cd ${
|
|
192
|
+
cdProjectName.includes(' ') ? `"${cdProjectName}"` : cdProjectName
|
|
193
|
+
}`
|
|
194
|
+
}
|
|
195
|
+
doneMessage += `\n ${getInstallCommand(pm).join(' ')}`
|
|
196
|
+
doneMessage += `\n ${getRunCommand(pm, 'dev').join(' ')}`
|
|
197
|
+
p.outro(doneMessage)
|
|
198
|
+
}
|
|
199
|
+
)
|
package/src/bin/dev.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { type Command, command } from 'cleye'
|
|
4
|
+
import { gracefulExit } from 'exit-hook'
|
|
5
|
+
import { bootstrapApiServer } from '../api/runner.ts'
|
|
6
|
+
import { createEnv } from '../config/env.ts'
|
|
7
|
+
import { createDatabase } from '../db/client.ts'
|
|
8
|
+
import { runMigrations } from '../db/migrate.ts'
|
|
9
|
+
import * as InternalSchema from '../db/schema/index.ts'
|
|
10
|
+
import { HookRegistry } from '../hooks/registry.ts'
|
|
11
|
+
import { bootstrapIndexer } from '../indexer/runner.ts'
|
|
12
|
+
import { createLogger } from '../utils/logger.ts'
|
|
13
|
+
import { createExit, registerUnhandled } from '../utils/shutdown.ts'
|
|
14
|
+
import { globalFlags } from './flags.ts'
|
|
15
|
+
import { loadConfig } from './utils.ts'
|
|
16
|
+
|
|
17
|
+
export const dev: Command = command(
|
|
18
|
+
{
|
|
19
|
+
name: 'dev',
|
|
20
|
+
flags: { ...globalFlags },
|
|
21
|
+
help: {
|
|
22
|
+
description: 'Start the development server with hot reloading',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
async (argv) => {
|
|
26
|
+
const logger = createLogger({
|
|
27
|
+
level: argv.flags.logLevel,
|
|
28
|
+
mode: argv.flags.logMode,
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
registerUnhandled({ logger })
|
|
32
|
+
|
|
33
|
+
if (!fs.existsSync(path.join(argv.flags.root, '.env.local'))) {
|
|
34
|
+
logger.warn({
|
|
35
|
+
msg: 'Local environment file (.env.local) not found',
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const env = createEnv(logger)
|
|
41
|
+
|
|
42
|
+
const config = await loadConfig(
|
|
43
|
+
logger,
|
|
44
|
+
argv.flags.root,
|
|
45
|
+
argv.flags.config
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
const dbContext = createDatabase({
|
|
49
|
+
env,
|
|
50
|
+
schema: { ...config.schema, ...InternalSchema.schema },
|
|
51
|
+
relations: { ...config.relations, ...InternalSchema.relations },
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
await runMigrations({
|
|
55
|
+
dbContext,
|
|
56
|
+
folder: path.resolve(argv.flags.root, config.drizzleFolder),
|
|
57
|
+
logger,
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const registry = new HookRegistry()
|
|
61
|
+
config.hooks({ registry })
|
|
62
|
+
|
|
63
|
+
const [api, indexer] = await Promise.all([
|
|
64
|
+
bootstrapApiServer({
|
|
65
|
+
db: dbContext.db,
|
|
66
|
+
config,
|
|
67
|
+
logger,
|
|
68
|
+
port: argv.flags.port,
|
|
69
|
+
}),
|
|
70
|
+
bootstrapIndexer({
|
|
71
|
+
logger,
|
|
72
|
+
db: dbContext.db,
|
|
73
|
+
registry,
|
|
74
|
+
config,
|
|
75
|
+
}),
|
|
76
|
+
])
|
|
77
|
+
|
|
78
|
+
createExit({
|
|
79
|
+
logger,
|
|
80
|
+
stop: async () => {
|
|
81
|
+
indexer.stop()
|
|
82
|
+
api.stop()
|
|
83
|
+
await dbContext.close()
|
|
84
|
+
},
|
|
85
|
+
})
|
|
86
|
+
} catch (error) {
|
|
87
|
+
logger.error({ error }, 'dev server failed')
|
|
88
|
+
gracefulExit(1)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
)
|
package/src/bin/flags.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
|
|
3
|
+
const Root = (dir: string) => {
|
|
4
|
+
return path.resolve(dir)
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const possibleLogModes = ['pretty', 'json'] as const
|
|
8
|
+
|
|
9
|
+
type LogModes = (typeof possibleLogModes)[number]
|
|
10
|
+
|
|
11
|
+
// Custom type function
|
|
12
|
+
const LogMode = (logMode: LogModes) => {
|
|
13
|
+
if (!possibleLogModes.includes(logMode)) {
|
|
14
|
+
throw new Error(`Invalid log mode: "${logMode}"`)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return logMode
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const LogLevels = [
|
|
21
|
+
'trace',
|
|
22
|
+
'debug',
|
|
23
|
+
'info',
|
|
24
|
+
'warn',
|
|
25
|
+
'error',
|
|
26
|
+
'fatal',
|
|
27
|
+
'silent',
|
|
28
|
+
] as const
|
|
29
|
+
type LogLevels = (typeof LogLevels)[number]
|
|
30
|
+
|
|
31
|
+
// Custom type function
|
|
32
|
+
const LogLevel = (logLevel: LogLevels) => {
|
|
33
|
+
if (!LogLevels.includes(logLevel)) {
|
|
34
|
+
throw new Error(`Invalid log level: "${logLevel}"`)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return logLevel
|
|
38
|
+
}
|
|
39
|
+
export const globalFlags = {
|
|
40
|
+
config: {
|
|
41
|
+
type: String,
|
|
42
|
+
description: 'The path to the config file',
|
|
43
|
+
},
|
|
44
|
+
root: {
|
|
45
|
+
type: Root,
|
|
46
|
+
description: 'The root directory of the project',
|
|
47
|
+
default: process.cwd(),
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
logLevel: {
|
|
51
|
+
type: LogLevel,
|
|
52
|
+
description: 'The log level to use',
|
|
53
|
+
default: LogLevel((process.env.LOG_LEVEL as LogLevels) ?? 'info'),
|
|
54
|
+
},
|
|
55
|
+
logMode: {
|
|
56
|
+
type: LogMode,
|
|
57
|
+
description: 'The log mode to use',
|
|
58
|
+
default: LogMode(process.env.NODE_ENV !== 'production' ? 'pretty' : 'json'),
|
|
59
|
+
},
|
|
60
|
+
port: {
|
|
61
|
+
type: Number,
|
|
62
|
+
description: 'The port to use for the API server',
|
|
63
|
+
default: process.env.PORT ? Number(process.env.PORT) : 4200,
|
|
64
|
+
},
|
|
65
|
+
} as const
|
package/src/bin/index.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFileSync } from 'node:fs'
|
|
4
|
+
import { dirname, resolve } from 'node:path'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
import { cli } from 'cleye'
|
|
7
|
+
import { create } from './create.ts'
|
|
8
|
+
import { dev } from './dev.ts'
|
|
9
|
+
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
11
|
+
const packageJsonPath = resolve(__dirname, '../../package.json')
|
|
12
|
+
const packageJson = JSON.parse(
|
|
13
|
+
readFileSync(packageJsonPath, { encoding: 'utf8' })
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
const argv = cli({
|
|
17
|
+
name: 'foxer',
|
|
18
|
+
version: packageJson.version,
|
|
19
|
+
commands: [dev, create],
|
|
20
|
+
help: {
|
|
21
|
+
version: packageJson.version,
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
if (!argv.command) {
|
|
26
|
+
argv.showHelp()
|
|
27
|
+
process.exit(1)
|
|
28
|
+
}
|
package/src/bin/utils.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import { pathToFileURL } from 'node:url'
|
|
3
|
+
import { type LilconfigResult, lilconfig } from 'lilconfig'
|
|
4
|
+
import type { InternalConfig } from '../config/config'
|
|
5
|
+
import type { Logger } from '../utils/logger'
|
|
6
|
+
|
|
7
|
+
const CLI_NAME = 'foxer'
|
|
8
|
+
|
|
9
|
+
const loadEsm = async (filepath: string) => {
|
|
10
|
+
const res = await import(pathToFileURL(filepath).href)
|
|
11
|
+
return res.default ?? res
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const configLoaders = {
|
|
15
|
+
'.js': loadEsm,
|
|
16
|
+
'.mjs': loadEsm,
|
|
17
|
+
'.ts': loadEsm,
|
|
18
|
+
'.mts': loadEsm,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function loadConfig(
|
|
22
|
+
logger: Logger,
|
|
23
|
+
root: string,
|
|
24
|
+
filePath?: string
|
|
25
|
+
) {
|
|
26
|
+
let configFile: LilconfigResult | undefined
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
if (filePath) {
|
|
30
|
+
const configPath = path.resolve(root, filePath)
|
|
31
|
+
|
|
32
|
+
configFile = await lilconfig(configPath, {
|
|
33
|
+
loaders: configLoaders,
|
|
34
|
+
searchPlaces: [],
|
|
35
|
+
}).load(configPath)
|
|
36
|
+
} else {
|
|
37
|
+
configFile = await lilconfig(CLI_NAME, {
|
|
38
|
+
loaders: configLoaders,
|
|
39
|
+
searchPlaces: [`${CLI_NAME}.config.ts`, `${CLI_NAME}.config.mts`],
|
|
40
|
+
}).search()
|
|
41
|
+
}
|
|
42
|
+
} catch (error) {
|
|
43
|
+
logger.error(error, 'config evaluation failed')
|
|
44
|
+
// ignore
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!configFile || configFile.isEmpty) {
|
|
48
|
+
logger.error({
|
|
49
|
+
msg: 'Config file not found',
|
|
50
|
+
})
|
|
51
|
+
process.exit(1)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return configFile.config.config as InternalConfig
|
|
55
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import type { Abi, AbiEvent } from 'abitype'
|
|
2
|
+
import type { AnyRelations, EmptyRelations } from 'drizzle-orm/relations'
|
|
3
|
+
import type { Hono } from 'hono'
|
|
4
|
+
import type { BlankEnv, BlankSchema } from 'hono/types'
|
|
5
|
+
import type { PoolConfig } from 'pg'
|
|
6
|
+
import type { SetRequired, Simplify, UnknownRecord } from 'type-fest'
|
|
7
|
+
import {
|
|
8
|
+
type Address,
|
|
9
|
+
type FallbackTransport,
|
|
10
|
+
getAbiItem,
|
|
11
|
+
type HttpTransport,
|
|
12
|
+
type Narrow,
|
|
13
|
+
type PublicClientConfig,
|
|
14
|
+
type WebSocketTransport,
|
|
15
|
+
} from 'viem'
|
|
16
|
+
import type { Database } from '../db/client.ts'
|
|
17
|
+
import type { HookRegistry } from '../hooks/registry.ts'
|
|
18
|
+
import { createRpcClients, type RpcClients } from '../rpc/client.ts'
|
|
19
|
+
import type { UnknownObject } from '../types.ts'
|
|
20
|
+
import type { Logger } from '../utils/logger.ts'
|
|
21
|
+
import type {
|
|
22
|
+
ContractConfig,
|
|
23
|
+
ContractsConfig,
|
|
24
|
+
GetContract,
|
|
25
|
+
} from '../utils/types.ts'
|
|
26
|
+
|
|
27
|
+
export type ClientConfig = Simplify<
|
|
28
|
+
SetRequired<PublicClientConfig, 'chain'> & {
|
|
29
|
+
realtimeTransport?: HttpTransport | WebSocketTransport | FallbackTransport
|
|
30
|
+
}
|
|
31
|
+
>
|
|
32
|
+
|
|
33
|
+
export type HonoConfig<
|
|
34
|
+
TSchema extends UnknownRecord = UnknownRecord,
|
|
35
|
+
TRelations extends AnyRelations = EmptyRelations,
|
|
36
|
+
> = (options: {
|
|
37
|
+
logger: Logger
|
|
38
|
+
db: Database<TSchema, TRelations>
|
|
39
|
+
}) => Hono<BlankEnv, BlankSchema, '/'>
|
|
40
|
+
|
|
41
|
+
export type HooksConfig<
|
|
42
|
+
contracts extends ContractsConfig<UnknownObject>,
|
|
43
|
+
TSchema extends UnknownRecord,
|
|
44
|
+
TRelations extends AnyRelations,
|
|
45
|
+
> = (context: {
|
|
46
|
+
registry: HookRegistry<
|
|
47
|
+
ContractsConfig<Narrow<contracts>>,
|
|
48
|
+
TSchema,
|
|
49
|
+
TRelations
|
|
50
|
+
>
|
|
51
|
+
}) => void
|
|
52
|
+
|
|
53
|
+
export type DatabaseConfig =
|
|
54
|
+
| {
|
|
55
|
+
driver: 'postgres'
|
|
56
|
+
url?: string
|
|
57
|
+
options?: PoolConfig
|
|
58
|
+
}
|
|
59
|
+
| {
|
|
60
|
+
driver: 'pglite'
|
|
61
|
+
directory: string
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export type Config<
|
|
65
|
+
contracts extends ContractsConfig<UnknownObject>,
|
|
66
|
+
TSchema extends UnknownRecord,
|
|
67
|
+
TRelations extends AnyRelations = EmptyRelations,
|
|
68
|
+
> = {
|
|
69
|
+
/**
|
|
70
|
+
* The batch size for the backfill. How many blocks to process at a time.
|
|
71
|
+
* @default 100
|
|
72
|
+
*/
|
|
73
|
+
batchSize?: number
|
|
74
|
+
/**
|
|
75
|
+
* The finality of the chain.
|
|
76
|
+
* @default 30
|
|
77
|
+
*/
|
|
78
|
+
finality?: number
|
|
79
|
+
/**
|
|
80
|
+
* The folder where the drizzle schema is stored.
|
|
81
|
+
* @default './drizzle'
|
|
82
|
+
*/
|
|
83
|
+
drizzleFolder?: string
|
|
84
|
+
/**
|
|
85
|
+
* The database configuration.
|
|
86
|
+
*/
|
|
87
|
+
database?: DatabaseConfig
|
|
88
|
+
/**
|
|
89
|
+
* The contracts to index.
|
|
90
|
+
*/
|
|
91
|
+
contracts: ContractsConfig<Narrow<contracts>>
|
|
92
|
+
/**
|
|
93
|
+
* The RPC clients configuration.
|
|
94
|
+
*/
|
|
95
|
+
client: ClientConfig
|
|
96
|
+
/**
|
|
97
|
+
* The Hono configuration.
|
|
98
|
+
*/
|
|
99
|
+
hono: HonoConfig<TSchema, TRelations>
|
|
100
|
+
/**
|
|
101
|
+
* The drizzle schema.
|
|
102
|
+
*/
|
|
103
|
+
schema: TSchema
|
|
104
|
+
/**
|
|
105
|
+
* The drizzle relations.
|
|
106
|
+
*/
|
|
107
|
+
relations?: TRelations
|
|
108
|
+
/**
|
|
109
|
+
* The hooks configuration.
|
|
110
|
+
*/
|
|
111
|
+
hooks: HooksConfig<contracts, TSchema, TRelations>
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export type InternalConfig<
|
|
115
|
+
TSchema extends UnknownRecord = UnknownRecord,
|
|
116
|
+
TRelations extends AnyRelations = EmptyRelations,
|
|
117
|
+
> = {
|
|
118
|
+
batchSize: bigint
|
|
119
|
+
finality: bigint
|
|
120
|
+
drizzleFolder: string
|
|
121
|
+
contracts: { [contractName: string]: GetContract }
|
|
122
|
+
database?: DatabaseConfig
|
|
123
|
+
client: ClientConfig
|
|
124
|
+
hono: HonoConfig<TSchema, TRelations>
|
|
125
|
+
schema: TSchema
|
|
126
|
+
relations: TRelations
|
|
127
|
+
hooks: (context: { registry: HookRegistry }) => void
|
|
128
|
+
startBlockNumber: bigint
|
|
129
|
+
contractsForLive: ContractConfig<Abi, readonly string[]>[]
|
|
130
|
+
clients: RpcClients
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function createConfig<
|
|
134
|
+
contracts extends ContractsConfig<UnknownObject>,
|
|
135
|
+
TSchema extends UnknownRecord = UnknownRecord,
|
|
136
|
+
TRelations extends AnyRelations = EmptyRelations,
|
|
137
|
+
>(config: Config<contracts, TSchema, TRelations>) {
|
|
138
|
+
let startBlockNumber: bigint = 0n
|
|
139
|
+
const contractsForLive: ContractConfig<Abi, readonly string[]>[] = []
|
|
140
|
+
|
|
141
|
+
for (const contract of Object.values(
|
|
142
|
+
config.contracts as { [contractName: string]: GetContract }
|
|
143
|
+
)) {
|
|
144
|
+
if (contract.endBlock == null) {
|
|
145
|
+
contractsForLive.push(contract)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (startBlockNumber === 0n && contract.startBlock != null) {
|
|
149
|
+
startBlockNumber = contract.startBlock
|
|
150
|
+
continue
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (contract.startBlock != null && contract.startBlock < startBlockNumber) {
|
|
154
|
+
startBlockNumber = contract.startBlock
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const clients = createRpcClients(config.client)
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
...config,
|
|
162
|
+
batchSize: BigInt(config.batchSize ?? 100),
|
|
163
|
+
finality: BigInt(config.finality ?? 30),
|
|
164
|
+
drizzleFolder: config.drizzleFolder ?? './drizzle',
|
|
165
|
+
relations: config.relations ? config.relations : ({} as TRelations),
|
|
166
|
+
startBlockNumber,
|
|
167
|
+
contractsForLive,
|
|
168
|
+
clients,
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export type FilteredContracts = {
|
|
173
|
+
eventAbis: AbiEvent[]
|
|
174
|
+
addresses: Address[]
|
|
175
|
+
eventNames: Set<string>
|
|
176
|
+
contractNameByAddress: Record<Address, string>
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function filterContracts(
|
|
180
|
+
config: InternalConfig,
|
|
181
|
+
fromBlock: bigint,
|
|
182
|
+
toBlock: bigint
|
|
183
|
+
) {
|
|
184
|
+
const eventAbis: AbiEvent[] = []
|
|
185
|
+
const addresses: Address[] = []
|
|
186
|
+
const eventNames: Set<string> = new Set()
|
|
187
|
+
const contractNameByAddress: Record<Address, string> = {}
|
|
188
|
+
for (const [contractName, contract] of Object.entries(config.contracts)) {
|
|
189
|
+
const address = contract.address.toLowerCase() as `0x${string}`
|
|
190
|
+
const startBlock = contract.startBlock ?? 0n
|
|
191
|
+
|
|
192
|
+
if (startBlock > toBlock) {
|
|
193
|
+
continue
|
|
194
|
+
}
|
|
195
|
+
if (contract.endBlock != null && contract.endBlock < fromBlock) {
|
|
196
|
+
continue
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
addresses.push(address)
|
|
200
|
+
contractNameByAddress[address] = contractName
|
|
201
|
+
|
|
202
|
+
for (const event of contract.events) {
|
|
203
|
+
eventNames.add(event)
|
|
204
|
+
const eventAbi = getAbiItem({
|
|
205
|
+
abi: contract.abi,
|
|
206
|
+
name: event,
|
|
207
|
+
})
|
|
208
|
+
if (!eventAbi) {
|
|
209
|
+
throw new Error(`Event ${event} not found in contract ${contractName}`)
|
|
210
|
+
}
|
|
211
|
+
eventAbis.push(eventAbi as AbiEvent)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
eventAbis: eventAbis,
|
|
217
|
+
addresses: addresses,
|
|
218
|
+
contractNameByAddress: contractNameByAddress,
|
|
219
|
+
eventNames: eventNames,
|
|
220
|
+
}
|
|
221
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import dotenv from 'dotenv'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
import type { Logger } from '../utils/logger'
|
|
4
|
+
|
|
5
|
+
dotenv.config({
|
|
6
|
+
path: '.env.local',
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
export type Env = z.infer<typeof envSchema>
|
|
10
|
+
const envSchema = z.object({
|
|
11
|
+
DATABASE_URL: z.url().optional(),
|
|
12
|
+
LOG_LEVEL: z
|
|
13
|
+
.enum(['trace', 'debug', 'info', 'warn', 'error', 'fatal'])
|
|
14
|
+
.default('info'),
|
|
15
|
+
LOG_MODE: z.enum(['pretty', 'json']).default('pretty'),
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
export function createEnv(logger: Logger) {
|
|
19
|
+
const parsed = envSchema.safeParse(process.env)
|
|
20
|
+
|
|
21
|
+
if (!parsed.success) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`Failed to parse environment variables: \n ${z.flattenError(parsed.error)}`
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
logger.debug({ env: parsed.data }, 'env parsed')
|
|
27
|
+
return parsed.data
|
|
28
|
+
}
|
package/src/contants.ts
ADDED