envio 2.16.1 → 2.17.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.
@@ -0,0 +1,179 @@
1
+ open Pino
2
+
3
+ type logStrategyType =
4
+ | @as("ecs-file") EcsFile
5
+ | @as("ecs-console") EcsConsole
6
+ | @as("ecs-console-multistream") EcsConsoleMultistream
7
+ | @as("file-only") FileOnly
8
+ | @as("console-raw") ConsoleRaw
9
+ | @as("console-pretty") ConsolePretty
10
+ | @as("both-prettyconsole") Both
11
+
12
+ let logLevels = [
13
+ // custom levels
14
+ ("udebug", 32),
15
+ ("uinfo", 34),
16
+ ("uwarn", 36),
17
+ ("uerror", 38),
18
+ // Default levels
19
+ ("trace", 10),
20
+ ("debug", 20),
21
+ ("info", 30),
22
+ ("warn", 40),
23
+ ("error", 50),
24
+ ("fatal", 60),
25
+ ]->Js.Dict.fromArray
26
+
27
+ %%private(let logger = ref(None))
28
+
29
+ let setLogger = (~logStrategy, ~logFilePath, ~defaultFileLogLevel, ~userLogLevel) => {
30
+ // Currently unused - useful if using multiple transports.
31
+ // let pinoRaw = {"target": "pino/file", "level": Config.userLogLevel}
32
+ let pinoFile: Transport.transportTarget = {
33
+ target: "pino/file",
34
+ options: {
35
+ "destination": logFilePath,
36
+ "append": true,
37
+ "mkdir": true,
38
+ }->Transport.makeTransportOptions,
39
+ level: defaultFileLogLevel,
40
+ }
41
+
42
+ let makeMultiStreamLogger =
43
+ MultiStreamLogger.make(~userLogLevel, ~defaultFileLogLevel, ~customLevels=logLevels, ...)
44
+
45
+ logger :=
46
+ Some(
47
+ switch logStrategy {
48
+ | EcsFile =>
49
+ makeWithOptionsAndTransport(
50
+ {
51
+ ...Pino.ECS.make(),
52
+ customLevels: logLevels,
53
+ },
54
+ Transport.make(pinoFile),
55
+ )
56
+ | EcsConsoleMultistream =>
57
+ makeMultiStreamLogger(~logFile=None, ~options=Some(Pino.ECS.make()))
58
+ | EcsConsole =>
59
+ make({
60
+ ...Pino.ECS.make(),
61
+ level: userLogLevel,
62
+ customLevels: logLevels,
63
+ })
64
+ | FileOnly =>
65
+ makeWithOptionsAndTransport(
66
+ {
67
+ customLevels: logLevels,
68
+ level: defaultFileLogLevel,
69
+ },
70
+ Transport.make(pinoFile),
71
+ )
72
+ | ConsoleRaw => makeMultiStreamLogger(~logFile=None, ~options=None)
73
+ | ConsolePretty => makeMultiStreamLogger(~logFile=None, ~options=None)
74
+ | Both => makeMultiStreamLogger(~logFile=Some(logFilePath), ~options=None)
75
+ },
76
+ )
77
+ }
78
+
79
+ let getLogger = () => {
80
+ switch logger.contents {
81
+ | Some(logger) => logger
82
+ | None => Js.Exn.raiseError("Unreachable code. Logger not initialized")
83
+ }
84
+ }
85
+
86
+ let setLogLevel = (level: Pino.logLevel) => {
87
+ getLogger()->setLevel(level)
88
+ }
89
+
90
+ let trace = message => {
91
+ getLogger().trace(message->createPinoMessage)
92
+ }
93
+
94
+ let debug = message => {
95
+ getLogger().debug(message->createPinoMessage)
96
+ }
97
+
98
+ let info = message => {
99
+ getLogger().info(message->createPinoMessage)
100
+ }
101
+
102
+ let warn = message => {
103
+ getLogger().warn(message->createPinoMessage)
104
+ }
105
+
106
+ let error = message => {
107
+ getLogger().error(message->createPinoMessage)
108
+ }
109
+ let errorWithExn = (error, message) => {
110
+ getLogger()->Pino.errorExn(message->createPinoMessageWithError(error))
111
+ }
112
+
113
+ let fatal = message => {
114
+ getLogger().fatal(message->createPinoMessage)
115
+ }
116
+
117
+ let childTrace = (logger, params: 'a) => {
118
+ logger.trace(params->createPinoMessage)
119
+ }
120
+ let childDebug = (logger, params: 'a) => {
121
+ logger.debug(params->createPinoMessage)
122
+ }
123
+ let childInfo = (logger, params: 'a) => {
124
+ logger.info(params->createPinoMessage)
125
+ }
126
+ let childWarn = (logger, params: 'a) => {
127
+ logger.warn(params->createPinoMessage)
128
+ }
129
+ let childError = (logger, params: 'a) => {
130
+ logger.error(params->createPinoMessage)
131
+ }
132
+ let childErrorWithExn = (logger, error, params: 'a) => {
133
+ logger->Pino.errorExn(params->createPinoMessageWithError(error))
134
+ }
135
+
136
+ let childFatal = (logger, params: 'a) => {
137
+ logger.fatal(params->createPinoMessage)
138
+ }
139
+
140
+ let createChild = (~params: 'a) => {
141
+ getLogger()->child(params->createChildParams)
142
+ }
143
+ let createChildFrom = (~logger: t, ~params: 'a) => {
144
+ logger->child(params->createChildParams)
145
+ }
146
+
147
+ let getEventLogger = (eventItem: Internal.eventItem) => {
148
+ switch eventItem.loggerCache {
149
+ | Some(l) => l
150
+ | None => {
151
+ let l = getLogger()->child(
152
+ {
153
+ "context": `Event '${eventItem.eventConfig.name}' for contract '${eventItem.eventConfig.contractName}'`,
154
+ "chainId": eventItem.chain->ChainMap.Chain.toChainId,
155
+ "block": eventItem.blockNumber,
156
+ "logIndex": eventItem.logIndex,
157
+ }->createChildParams,
158
+ )
159
+ eventItem.loggerCache = Some(l)
160
+ l
161
+ }
162
+ }
163
+ }
164
+
165
+ let getUserLogger = {
166
+ @inline
167
+ let log = (eventItem, level: Pino.logLevelUser, message: string, ~params) => {
168
+ (eventItem->getEventLogger->Utils.magic->Js.Dict.unsafeGet((level :> string)))(params, message)
169
+ }
170
+
171
+ (eventItem): Envio.logger => {
172
+ info: (message: string, ~params=?) => eventItem->log(#uinfo, message, ~params),
173
+ debug: (message: string, ~params=?) => eventItem->log(#udebug, message, ~params),
174
+ warn: (message: string, ~params=?) => eventItem->log(#uwarn, message, ~params),
175
+ error: (message: string, ~params=?) => eventItem->log(#uerror, message, ~params),
176
+ errorWithExn: (message: string, exn) =>
177
+ eventItem->log(#uerror, message, ~params={"err": exn->Internal.prettifyExn}),
178
+ }
179
+ }
package/src/Time.res ADDED
@@ -0,0 +1,41 @@
1
+ let resolvePromiseAfterDelay = (~delayMilliseconds) => Utils.delay(delayMilliseconds)
2
+
3
+ let rec retryAsyncWithExponentialBackOff = async (
4
+ ~backOffMillis=100,
5
+ ~multiplicative=4,
6
+ ~retryCount=0,
7
+ ~maxRetries=5,
8
+ ~logger: Pino.t,
9
+ f: unit => promise<'a>,
10
+ ) => {
11
+ try {
12
+ await f()
13
+ } catch {
14
+ | exn =>
15
+ if retryCount < maxRetries {
16
+ let nextRetryCount = retryCount + 1
17
+ let log = retryCount === 0 ? Logging.childTrace : Logging.childWarn
18
+ logger->log({
19
+ "msg": `Retrying query ${nextRetryCount->Belt.Int.toString}/${maxRetries->Belt.Int.toString} in ${backOffMillis->Belt.Int.toString}ms - waiting for correct result.`,
20
+ "err": exn->Internal.prettifyExn,
21
+ })
22
+ await resolvePromiseAfterDelay(~delayMilliseconds=backOffMillis)
23
+
24
+ await f->retryAsyncWithExponentialBackOff(
25
+ ~backOffMillis=backOffMillis * multiplicative,
26
+ ~multiplicative,
27
+ ~retryCount=nextRetryCount,
28
+ ~maxRetries,
29
+ ~logger,
30
+ )
31
+ } else {
32
+ exn
33
+ ->ErrorHandling.make(
34
+ ~logger,
35
+ ~msg=`Failure. Max retries ${retryCount->Belt.Int.toString}/${maxRetries->Belt.Int.toString} exceeded`,
36
+ )
37
+ ->ErrorHandling.log
38
+ await Promise.reject(exn->Js.Exn.anyToExnInternal)
39
+ }
40
+ }
41
+ }
package/src/Types.ts ADDED
@@ -0,0 +1,22 @@
1
+ export type Invalid = never;
2
+
3
+ export type Address = string;
4
+
5
+ export type Logger = {
6
+ readonly debug: (
7
+ message: string,
8
+ params?: Record<string, unknown> | Error
9
+ ) => void;
10
+ readonly info: (
11
+ message: string,
12
+ params?: Record<string, unknown> | Error
13
+ ) => void;
14
+ readonly warn: (
15
+ message: string,
16
+ params?: Record<string, unknown> | Error
17
+ ) => void;
18
+ readonly error: (
19
+ message: string,
20
+ params?: Record<string, unknown> | Error
21
+ ) => void;
22
+ };
package/src/Utils.res CHANGED
@@ -22,6 +22,11 @@ module Object = {
22
22
  external defineProperty: ('obj, string, propertyDescriptor<'a>) => 'obj = "defineProperty"
23
23
  }
24
24
 
25
+ module Error = {
26
+ @new
27
+ external make: string => exn = "Error"
28
+ }
29
+
25
30
  module Option = {
26
31
  let mapNone = (opt: option<'a>, val: 'b): option<'b> => {
27
32
  switch opt {
@@ -123,6 +128,9 @@ module Math = {
123
128
  }
124
129
 
125
130
  module Array = {
131
+ @send
132
+ external forEachAsync: (array<'a>, 'a => promise<unit>) => unit = "forEach"
133
+
126
134
  @val external jsArrayCreate: int => array<'a> = "Array"
127
135
 
128
136
  /* Given a comaprator and two sorted lists, combine them into a single sorted list */
@@ -452,3 +460,10 @@ module Map = {
452
460
  @send external set: (t<'k, 'v>, 'k, 'v) => t<'k, 'v> = "set"
453
461
  @send external delete: (t<'k, 'v>, 'k) => bool = "delete"
454
462
  }
463
+
464
+ module Proxy = {
465
+ type traps<'a> = {get?: (~target: 'a, ~prop: unknown) => unknown}
466
+
467
+ @new
468
+ external make: ('a, traps<'a>) => 'a = "Proxy"
469
+ }
@@ -7,7 +7,11 @@ type app
7
7
  @module external makeCjs: unit => app = "express"
8
8
  @module("express") external make: unit => app = "default"
9
9
 
10
- type req
10
+ type req = private {
11
+ headers: dict<string>,
12
+ method: Rest.method,
13
+ query: dict<string>,
14
+ }
11
15
  type res
12
16
 
13
17
  type handler = (req, res) => unit
@@ -16,14 +20,18 @@ type middleware = (req, res, unit => unit) => unit
16
20
  @module("express") external jsonMiddleware: unit => middleware = "json"
17
21
 
18
22
  @send external use: (app, middleware) => unit = "use"
23
+ @send external useFor: (app, string, middleware) => unit = "use"
19
24
 
20
25
  @send external get: (app, string, handler) => unit = "get"
26
+ @send external post: (app, string, handler) => unit = "post"
21
27
 
22
28
  type server
23
29
 
24
30
  @send external listen: (app, int) => server = "listen"
25
31
 
26
32
  // res methods
27
- @send external sendStatus: (res, int) => res = "sendStatus"
33
+ @send external sendStatus: (res, int) => unit = "sendStatus"
28
34
  @send external set: (res, string, string) => unit = "set"
35
+ @send external json: (res, Js.Json.t) => unit = "json"
29
36
  @send external endWithData: (res, 'a) => res = "end"
37
+ @send external setHeader: (res, string, string) => unit = "setHeader"
@@ -0,0 +1,81 @@
1
+ type t
2
+ @module external process: t = "process"
3
+ @send external exit: (t, unit) => unit = "exit"
4
+ type exitCode = | @as(0) Success | @as(1) Failure
5
+ @send external exitWithCode: (t, exitCode) => unit = "exit"
6
+
7
+ module Util = {
8
+ @unboxed
9
+ type depth = Int(int) | @as(null) Null
10
+ @unboxed
11
+ type compact = Bool(bool) | Int(int)
12
+ @unboxed
13
+ type sorted = Bool(bool) | Fn((string, string) => int)
14
+ @unboxed
15
+ type getters = | @as(true) True | @as(false) False | @as("get") Get | @as("set") Set
16
+
17
+ @unbox
18
+ type inspectOptions = {
19
+ showHidden?: bool,
20
+ depth?: depth,
21
+ colors?: bool,
22
+ customInspect?: bool,
23
+ showProxy?: bool,
24
+ maxArrayLength?: int,
25
+ maxStringLength?: int,
26
+ breakLength?: int,
27
+ @as("compact") compact?: compact,
28
+ sorted?: sorted,
29
+ getters?: string,
30
+ numericSeparator?: bool,
31
+ }
32
+
33
+ @module("util") external inspect: ('a, inspectOptions) => string = "inspect"
34
+
35
+ let inspectObj = a => inspect(a, {showHidden: false, depth: Null, colors: true})
36
+ }
37
+
38
+ module Path = {
39
+ type t
40
+
41
+ @module("path") @variadic
42
+ external resolve: array<string> => t = "resolve"
43
+
44
+ @module("path") external join: (t, string) => t = "join"
45
+
46
+ external toString: t => string = "%identity"
47
+
48
+ external __dirname: t = "__dirname"
49
+ }
50
+
51
+ module Fs = {
52
+ type writeFileOptions = {
53
+ mode?: int,
54
+ // flag?: Flag.t,
55
+ encoding?: string,
56
+ }
57
+
58
+ module Promises = {
59
+ @module("fs") @scope("promises")
60
+ external writeFile: (
61
+ ~filepath: Path.t,
62
+ ~content: string,
63
+ ~options: writeFileOptions=?,
64
+ ) => promise<unit> = "writeFile"
65
+
66
+ @module("fs") @scope("promises")
67
+ external appendFile: (
68
+ ~filepath: Path.t,
69
+ ~content: string,
70
+ ~options: writeFileOptions=?,
71
+ ) => Js.Promise.t<unit> = "appendFile"
72
+
73
+ @module("fs") @scope("promises")
74
+ external access: Path.t => Js.Promise.t<unit> = "access"
75
+
76
+ type encoding = | @as("utf8") Utf8
77
+
78
+ @module("fs") @scope("promises")
79
+ external readFile: (~filepath: Path.t, ~encoding: encoding) => promise<string> = "readFile"
80
+ }
81
+ }
@@ -186,7 +186,7 @@ let fromTable = (table: table, ~schema: S.t<'entity>): t<'entity> => {
186
186
 
187
187
  let currentHistoryFields =
188
188
  currentChangeFieldNames->Belt.Array.map(fieldName =>
189
- mkField(fieldName, Integer, ~isPrimaryKey=true)
189
+ mkField(fieldName, Integer, ~fieldSchema=S.never, ~isPrimaryKey=true)
190
190
  )
191
191
 
192
192
  let previousChangeFieldNames =
@@ -194,7 +194,7 @@ let fromTable = (table: table, ~schema: S.t<'entity>): t<'entity> => {
194
194
 
195
195
  let previousHistoryFields =
196
196
  previousChangeFieldNames->Belt.Array.map(fieldName =>
197
- mkField(fieldName, Integer, ~isNullable=true)
197
+ mkField(fieldName, Integer, ~fieldSchema=S.never, ~isNullable=true)
198
198
  )
199
199
 
200
200
  let id = "id"
@@ -224,9 +224,9 @@ let fromTable = (table: table, ~schema: S.t<'entity>): t<'entity> => {
224
224
 
225
225
  let actionFieldName = "action"
226
226
 
227
- let actionField = mkField(actionFieldName, Custom(RowAction.enum.name))
227
+ let actionField = mkField(actionFieldName, Custom(RowAction.enum.name), ~fieldSchema=S.never)
228
228
 
229
- let serialField = mkField("serial", Serial, ~isNullable=true, ~isIndex=true)
229
+ let serialField = mkField("serial", Serial, ~fieldSchema=S.never, ~isNullable=true, ~isIndex=true)
230
230
 
231
231
  let dataFieldNames = dataFields->Belt.Array.map(field => field->getFieldName)
232
232
 
package/src/db/Table.res CHANGED
@@ -19,6 +19,7 @@ type fieldType =
19
19
  type field = {
20
20
  fieldName: string,
21
21
  fieldType: fieldType,
22
+ fieldSchema: S.t<unknown>,
22
23
  isArray: bool,
23
24
  isNullable: bool,
24
25
  isPrimaryKey: bool,
@@ -36,18 +37,20 @@ type derivedFromField = {
36
37
  type fieldOrDerived = Field(field) | DerivedFrom(derivedFromField)
37
38
 
38
39
  let mkField = (
40
+ fieldName,
41
+ fieldType,
42
+ ~fieldSchema,
39
43
  ~default=?,
40
44
  ~isArray=false,
41
45
  ~isNullable=false,
42
46
  ~isPrimaryKey=false,
43
47
  ~isIndex=false,
44
48
  ~linkedEntity=?,
45
- fieldName,
46
- fieldType,
47
49
  ) =>
48
50
  {
49
51
  fieldName,
50
52
  fieldType,
53
+ fieldSchema: fieldSchema->S.toUnknown,
51
54
  isArray,
52
55
  isNullable,
53
56
  isPrimaryKey,
@@ -0,0 +1,37 @@
1
+ type receiptType =
2
+ | @as(0) Call
3
+ | @as(1) Return
4
+ | @as(2) ReturnData
5
+ | @as(3) Panic
6
+ | @as(4) Revert
7
+ | @as(5) Log
8
+ | @as(6) LogData
9
+ // Transfer is to another contract, TransferOut is to wallet address
10
+ | @as(7) Transfer
11
+ | @as(8) TransferOut
12
+ | @as(9) ScriptResult
13
+ | @as(10) MessageOut
14
+ | @as(11) Mint
15
+ | @as(12) Burn
16
+
17
+ @module("./vendored-fuel-abi-coder.js")
18
+ external transpileAbi: Js.Json.t => Ethers.abi = "transpileAbi"
19
+
20
+ @module("./vendored-fuel-abi-coder.js") @scope("AbiCoder")
21
+ external getLogDecoder: (~abi: Ethers.abi, ~logId: string) => string => unknown = "getLogDecoder"
22
+
23
+ module Receipt = {
24
+ @tag("receiptType")
25
+ type t =
26
+ | @as(0) Call({assetId: string, amount: bigint, to: string})
27
+ | @as(6) LogData({data: string, rb: bigint})
28
+ | @as(7) Transfer({amount: bigint, assetId: string, to: string})
29
+ | @as(8) TransferOut({amount: bigint, assetId: string, toAddress: string})
30
+ | @as(11) Mint({val: bigint, subId: string})
31
+ | @as(12) Burn({val: bigint, subId: string})
32
+
33
+ let getLogDataDecoder = (~abi: Ethers.abi, ~logId: string) => {
34
+ let decode = getLogDecoder(~abi, ~logId)
35
+ data => data->decode->Utils.magic
36
+ }
37
+ }