envio 2.31.1 → 2.32.0

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/index.d.ts CHANGED
@@ -4,6 +4,8 @@ export type {
4
4
  effectContext as EffectContext,
5
5
  effectArgs as EffectArgs,
6
6
  effectOptions as EffectOptions,
7
+ rateLimitDuration as RateLimitDuration,
8
+ rateLimit as RateLimit,
7
9
  blockEvent as BlockEvent,
8
10
  onBlockArgs as OnBlockArgs,
9
11
  onBlockOptions as OnBlockOptions,
@@ -13,6 +15,7 @@ export type { EffectCaller } from "./src/Types.ts";
13
15
  import type {
14
16
  effect as Effect,
15
17
  effectArgs as EffectArgs,
18
+ rateLimit as RateLimit,
16
19
  } from "./src/Envio.gen.ts";
17
20
 
18
21
  import { schema as bigDecimalSchema } from "./src/bindings/BigDecimal.gen.ts";
@@ -73,6 +76,33 @@ type Flatten<T> = T extends object
73
76
  // })
74
77
  // The behaviour is inspired by Sury code:
75
78
  // https://github.com/DZakh/sury/blob/551f8ee32c1af95320936d00c086e5fb337f59fa/packages/sury/src/S.d.ts#L344C1-L355C50
79
+ export function createEffect<
80
+ IS,
81
+ OS,
82
+ I = UnknownToOutput<IS>,
83
+ O = UnknownToOutput<OS>,
84
+ // A hack to enforce that the inferred return type
85
+ // matches the output schema type
86
+ R extends O = O
87
+ >(
88
+ options: {
89
+ /** The name of the effect. Used for logging and debugging. */
90
+ readonly name: string;
91
+ /** The input schema of the effect. */
92
+ readonly input: IS;
93
+ /** The output schema of the effect. */
94
+ readonly output: OS;
95
+ /** Rate limit for the effect. Set to false to disable or provide {calls: number, per: "second" | "minute"} to enable. */
96
+ readonly rateLimit: RateLimit;
97
+ /** Whether the effect should be cached. */
98
+ readonly cache?: boolean;
99
+ },
100
+ handler: (args: EffectArgs<I>) => Promise<R>
101
+ ): Effect<I, O>;
102
+
103
+ /**
104
+ * @deprecated Use createEffect instead. The only difference is that rateLimit option becomes required. Set it to false to keep the same behaviour.
105
+ */
76
106
  export function experimental_createEffect<
77
107
  IS,
78
108
  OS,
@@ -89,6 +119,8 @@ export function experimental_createEffect<
89
119
  readonly input: IS;
90
120
  /** The output schema of the effect. */
91
121
  readonly output: OS;
122
+ /** Rate limit for the effect. Set to false to disable or provide {calls: number, per: "second" | "minute"} to enable. */
123
+ readonly rateLimit?: RateLimit;
92
124
  /** Whether the effect should be cached. */
93
125
  readonly cache?: boolean;
94
126
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "envio",
3
- "version": "v2.31.1",
3
+ "version": "v2.32.0",
4
4
  "description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
5
5
  "bin": "./bin.js",
6
6
  "main": "./index.js",
@@ -25,10 +25,10 @@
25
25
  },
26
26
  "homepage": "https://envio.dev",
27
27
  "optionalDependencies": {
28
- "envio-linux-x64": "v2.31.1",
29
- "envio-linux-arm64": "v2.31.1",
30
- "envio-darwin-x64": "v2.31.1",
31
- "envio-darwin-arm64": "v2.31.1"
28
+ "envio-linux-x64": "v2.32.0",
29
+ "envio-linux-arm64": "v2.32.0",
30
+ "envio-darwin-x64": "v2.32.0",
31
+ "envio-darwin-arm64": "v2.32.0"
32
32
  },
33
33
  "dependencies": {
34
34
  "@envio-dev/hypersync-client": "0.6.6",
package/src/Batch.res CHANGED
@@ -84,7 +84,7 @@ let hasUnorderedReadyItem = (fetchStates: ChainMap.t<FetchState.t>) => {
84
84
 
85
85
  let hasMultichainReadyItem = (
86
86
  fetchStates: ChainMap.t<FetchState.t>,
87
- ~multichain: InternalConfig.multichain,
87
+ ~multichain: Config.multichain,
88
88
  ) => {
89
89
  switch multichain {
90
90
  | Ordered => hasOrderedReadyItem(fetchStates)
@@ -496,7 +496,7 @@ let prepareUnorderedBatch = (
496
496
  let make = (
497
497
  ~checkpointIdBeforeBatch,
498
498
  ~chainsBeforeBatch: ChainMap.t<chainBeforeBatch>,
499
- ~multichain: InternalConfig.multichain,
499
+ ~multichain: Config.multichain,
500
500
  ~batchSizeTarget,
501
501
  ) => {
502
502
  if (
@@ -528,3 +528,23 @@ let findFirstEventBlockNumber = (batch: t, ~chainId) => {
528
528
  }
529
529
  result.contents
530
530
  }
531
+
532
+ let findLastEventItem = (batch: t, ~chainId) => {
533
+ let idx = ref(batch.items->Array.length - 1)
534
+ let result = ref(None)
535
+ while idx.contents >= 0 && result.contents === None {
536
+ let item = batch.items->Array.getUnsafe(idx.contents)
537
+ switch item {
538
+ | Internal.Event(_) as eventItem => {
539
+ let eventItem = eventItem->Internal.castUnsafeEventItem
540
+ if eventItem.chain->ChainMap.Chain.toChainId === chainId {
541
+ result := Some(eventItem)
542
+ } else {
543
+ idx := idx.contents - 1
544
+ }
545
+ }
546
+ | Internal.Block(_) => idx := idx.contents - 1
547
+ }
548
+ }
549
+ result.contents
550
+ }
package/src/Batch.res.js CHANGED
@@ -361,6 +361,20 @@ function findFirstEventBlockNumber(batch, chainId) {
361
361
  return result;
362
362
  }
363
363
 
364
+ function findLastEventItem(batch, chainId) {
365
+ var idx = batch.items.length - 1;
366
+ var result;
367
+ while(idx >= 0 && result === undefined) {
368
+ var item = batch.items[idx];
369
+ if (item.kind === 0 && item.chain === chainId) {
370
+ result = item;
371
+ } else {
372
+ idx = idx - 1;
373
+ }
374
+ };
375
+ return result;
376
+ }
377
+
364
378
  exports.getOrderedNextChain = getOrderedNextChain;
365
379
  exports.immutableEmptyBatchSizePerChain = immutableEmptyBatchSizePerChain;
366
380
  exports.hasOrderedReadyItem = hasOrderedReadyItem;
@@ -372,4 +386,5 @@ exports.prepareOrderedBatch = prepareOrderedBatch;
372
386
  exports.prepareUnorderedBatch = prepareUnorderedBatch;
373
387
  exports.make = make;
374
388
  exports.findFirstEventBlockNumber = findFirstEventBlockNumber;
389
+ exports.findLastEventItem = findLastEventItem;
375
390
  /* Utils Not a pure module */
package/src/Config.res ADDED
@@ -0,0 +1,124 @@
1
+ open Belt
2
+
3
+ type ecosystem = | @as("evm") Evm | @as("fuel") Fuel
4
+
5
+ type sourceSyncOptions = {
6
+ initialBlockInterval?: int,
7
+ backoffMultiplicative?: float,
8
+ accelerationAdditive?: int,
9
+ intervalCeiling?: int,
10
+ backoffMillis?: int,
11
+ queryTimeoutMillis?: int,
12
+ fallbackStallTimeout?: int,
13
+ }
14
+
15
+ type contract = {
16
+ name: string,
17
+ abi: EvmTypes.Abi.t,
18
+ addresses: array<Address.t>,
19
+ events: array<Internal.eventConfig>,
20
+ startBlock: option<int>,
21
+ }
22
+
23
+ type chain = {
24
+ id: int,
25
+ startBlock: int,
26
+ endBlock?: int,
27
+ maxReorgDepth: int,
28
+ contracts: array<contract>,
29
+ sources: array<Source.t>,
30
+ }
31
+
32
+ type sourceSync = {
33
+ initialBlockInterval: int,
34
+ backoffMultiplicative: float,
35
+ accelerationAdditive: int,
36
+ intervalCeiling: int,
37
+ backoffMillis: int,
38
+ queryTimeoutMillis: int,
39
+ fallbackStallTimeout: int,
40
+ }
41
+
42
+ type multichain = | @as("ordered") Ordered | @as("unordered") Unordered
43
+
44
+ type t = {
45
+ shouldRollbackOnReorg: bool,
46
+ shouldSaveFullHistory: bool,
47
+ multichain: multichain,
48
+ chainMap: ChainMap.t<chain>,
49
+ defaultChain: option<chain>,
50
+ ecosystem: ecosystem,
51
+ enableRawEvents: bool,
52
+ preloadHandlers: bool,
53
+ maxAddrInPartition: int,
54
+ batchSize: int,
55
+ lowercaseAddresses: bool,
56
+ addContractNameToContractNameMapping: dict<string>,
57
+ }
58
+
59
+ let make = (
60
+ ~shouldRollbackOnReorg=true,
61
+ ~shouldSaveFullHistory=false,
62
+ ~chains: array<chain>=[],
63
+ ~enableRawEvents=false,
64
+ ~preloadHandlers=false,
65
+ ~ecosystem=Evm,
66
+ ~batchSize=5000,
67
+ ~lowercaseAddresses=false,
68
+ ~multichain=Unordered,
69
+ ~shouldUseHypersyncClientDecoder=true,
70
+ ~maxAddrInPartition=5000,
71
+ ) => {
72
+ // Validate that lowercase addresses is not used with viem decoder
73
+ if lowercaseAddresses && !shouldUseHypersyncClientDecoder {
74
+ Js.Exn.raiseError(
75
+ "lowercase addresses is not supported when event_decoder is 'viem'. Please set event_decoder to 'hypersync-client' or change address_format to 'checksum'.",
76
+ )
77
+ }
78
+
79
+ let chainMap =
80
+ chains
81
+ ->Js.Array2.map(n => {
82
+ (ChainMap.Chain.makeUnsafe(~chainId=n.id), n)
83
+ })
84
+ ->ChainMap.fromArrayUnsafe
85
+
86
+ // Build the contract name mapping for efficient lookup
87
+ let addContractNameToContractNameMapping = Js.Dict.empty()
88
+ chains->Array.forEach(chainConfig => {
89
+ chainConfig.contracts->Array.forEach(contract => {
90
+ let addKey = "add" ++ contract.name->Utils.String.capitalize
91
+ addContractNameToContractNameMapping->Js.Dict.set(addKey, contract.name)
92
+ })
93
+ })
94
+
95
+ {
96
+ shouldRollbackOnReorg,
97
+ shouldSaveFullHistory,
98
+ multichain,
99
+ chainMap,
100
+ defaultChain: chains->Array.get(0),
101
+ enableRawEvents,
102
+ ecosystem,
103
+ maxAddrInPartition,
104
+ preloadHandlers,
105
+ batchSize,
106
+ lowercaseAddresses,
107
+ addContractNameToContractNameMapping,
108
+ }
109
+ }
110
+
111
+ let shouldSaveHistory = (config, ~isInReorgThreshold) =>
112
+ config.shouldSaveFullHistory || (config.shouldRollbackOnReorg && isInReorgThreshold)
113
+
114
+ let shouldPruneHistory = (config, ~isInReorgThreshold) =>
115
+ !config.shouldSaveFullHistory && (config.shouldRollbackOnReorg && isInReorgThreshold)
116
+
117
+ let getChain = (config, ~chainId) => {
118
+ let chain = ChainMap.Chain.makeUnsafe(~chainId)
119
+ config.chainMap->ChainMap.has(chain)
120
+ ? chain
121
+ : Js.Exn.raiseError(
122
+ "No chain with id " ++ chain->ChainMap.Chain.toString ++ " found in config.yaml",
123
+ )
124
+ }
@@ -0,0 +1,84 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+ 'use strict';
3
+
4
+ var Utils = require("./Utils.res.js");
5
+ var Js_exn = require("rescript/lib/js/js_exn.js");
6
+ var ChainMap = require("./ChainMap.res.js");
7
+ var Belt_Array = require("rescript/lib/js/belt_Array.js");
8
+
9
+ function make(shouldRollbackOnReorgOpt, shouldSaveFullHistoryOpt, chainsOpt, enableRawEventsOpt, preloadHandlersOpt, ecosystemOpt, batchSizeOpt, lowercaseAddressesOpt, multichainOpt, shouldUseHypersyncClientDecoderOpt, maxAddrInPartitionOpt) {
10
+ var shouldRollbackOnReorg = shouldRollbackOnReorgOpt !== undefined ? shouldRollbackOnReorgOpt : true;
11
+ var shouldSaveFullHistory = shouldSaveFullHistoryOpt !== undefined ? shouldSaveFullHistoryOpt : false;
12
+ var chains = chainsOpt !== undefined ? chainsOpt : [];
13
+ var enableRawEvents = enableRawEventsOpt !== undefined ? enableRawEventsOpt : false;
14
+ var preloadHandlers = preloadHandlersOpt !== undefined ? preloadHandlersOpt : false;
15
+ var ecosystem = ecosystemOpt !== undefined ? ecosystemOpt : "evm";
16
+ var batchSize = batchSizeOpt !== undefined ? batchSizeOpt : 5000;
17
+ var lowercaseAddresses = lowercaseAddressesOpt !== undefined ? lowercaseAddressesOpt : false;
18
+ var multichain = multichainOpt !== undefined ? multichainOpt : "unordered";
19
+ var shouldUseHypersyncClientDecoder = shouldUseHypersyncClientDecoderOpt !== undefined ? shouldUseHypersyncClientDecoderOpt : true;
20
+ var maxAddrInPartition = maxAddrInPartitionOpt !== undefined ? maxAddrInPartitionOpt : 5000;
21
+ if (lowercaseAddresses && !shouldUseHypersyncClientDecoder) {
22
+ Js_exn.raiseError("lowercase addresses is not supported when event_decoder is 'viem'. Please set event_decoder to 'hypersync-client' or change address_format to 'checksum'.");
23
+ }
24
+ var chainMap = ChainMap.fromArrayUnsafe(chains.map(function (n) {
25
+ return [
26
+ ChainMap.Chain.makeUnsafe(n.id),
27
+ n
28
+ ];
29
+ }));
30
+ var addContractNameToContractNameMapping = {};
31
+ Belt_Array.forEach(chains, (function (chainConfig) {
32
+ Belt_Array.forEach(chainConfig.contracts, (function (contract) {
33
+ var addKey = "add" + Utils.$$String.capitalize(contract.name);
34
+ addContractNameToContractNameMapping[addKey] = contract.name;
35
+ }));
36
+ }));
37
+ return {
38
+ shouldRollbackOnReorg: shouldRollbackOnReorg,
39
+ shouldSaveFullHistory: shouldSaveFullHistory,
40
+ multichain: multichain,
41
+ chainMap: chainMap,
42
+ defaultChain: Belt_Array.get(chains, 0),
43
+ ecosystem: ecosystem,
44
+ enableRawEvents: enableRawEvents,
45
+ preloadHandlers: preloadHandlers,
46
+ maxAddrInPartition: maxAddrInPartition,
47
+ batchSize: batchSize,
48
+ lowercaseAddresses: lowercaseAddresses,
49
+ addContractNameToContractNameMapping: addContractNameToContractNameMapping
50
+ };
51
+ }
52
+
53
+ function shouldSaveHistory(config, isInReorgThreshold) {
54
+ if (config.shouldSaveFullHistory) {
55
+ return true;
56
+ } else if (config.shouldRollbackOnReorg) {
57
+ return isInReorgThreshold;
58
+ } else {
59
+ return false;
60
+ }
61
+ }
62
+
63
+ function shouldPruneHistory(config, isInReorgThreshold) {
64
+ if (!config.shouldSaveFullHistory && config.shouldRollbackOnReorg) {
65
+ return isInReorgThreshold;
66
+ } else {
67
+ return false;
68
+ }
69
+ }
70
+
71
+ function getChain(config, chainId) {
72
+ var chain = ChainMap.Chain.makeUnsafe(chainId);
73
+ if (ChainMap.has(config.chainMap, chain)) {
74
+ return chain;
75
+ } else {
76
+ return Js_exn.raiseError("No chain with id " + ChainMap.Chain.toString(chain) + " found in config.yaml");
77
+ }
78
+ }
79
+
80
+ exports.make = make;
81
+ exports.shouldSaveHistory = shouldSaveHistory;
82
+ exports.shouldPruneHistory = shouldPruneHistory;
83
+ exports.getChain = getChain;
84
+ /* Utils Not a pure module */
package/src/Envio.gen.ts CHANGED
@@ -29,6 +29,25 @@ export type logger = $$logger;
29
29
 
30
30
  export type effect<input,output> = $$effect<input,output>;
31
31
 
32
+ export type rateLimitDuration = "second" | "minute" | number;
33
+
34
+ export type rateLimit =
35
+ false
36
+ | { readonly calls: number; readonly per: rateLimitDuration };
37
+
38
+ export type experimental_effectOptions<input,output> = {
39
+ /** The name of the effect. Used for logging and debugging. */
40
+ readonly name: string;
41
+ /** The input schema of the effect. */
42
+ readonly input: RescriptSchema_S_t<input>;
43
+ /** The output schema of the effect. */
44
+ readonly output: RescriptSchema_S_t<output>;
45
+ /** Rate limit for the effect. Set to false to disable or provide {calls: number, per: "second" | "minute"} to enable. */
46
+ readonly rateLimit?: rateLimit;
47
+ /** Whether the effect should be cached. */
48
+ readonly cache?: boolean
49
+ };
50
+
32
51
  export type effectOptions<input,output> = {
33
52
  /** The name of the effect. Used for logging and debugging. */
34
53
  readonly name: string;
@@ -36,6 +55,8 @@ export type effectOptions<input,output> = {
36
55
  readonly input: RescriptSchema_S_t<input>;
37
56
  /** The output schema of the effect. */
38
57
  readonly output: RescriptSchema_S_t<output>;
58
+ /** Rate limit for the effect. Set to false to disable or provide {calls: number, per: "second" | "minute"} to enable. */
59
+ readonly rateLimit: rateLimit;
39
60
  /** Whether the effect should be cached. */
40
61
  readonly cache?: boolean
41
62
  };
package/src/Envio.res CHANGED
@@ -32,6 +32,28 @@ type logger = {
32
32
  @@warning("-30") // Duplicated type names (input)
33
33
  @genType.import(("./Types.ts", "Effect"))
34
34
  type rec effect<'input, 'output>
35
+ @genType @unboxed
36
+ and rateLimitDuration =
37
+ | @as("second") Second
38
+ | @as("minute") Minute
39
+ | Milliseconds(int)
40
+ @genType @unboxed
41
+ and rateLimit =
42
+ | @as(false) Disable
43
+ | Enable({calls: int, per: rateLimitDuration})
44
+ @genType
45
+ and experimental_effectOptions<'input, 'output> = {
46
+ /** The name of the effect. Used for logging and debugging. */
47
+ name: string,
48
+ /** The input schema of the effect. */
49
+ input: S.t<'input>,
50
+ /** The output schema of the effect. */
51
+ output: S.t<'output>,
52
+ /** Rate limit for the effect. Set to false to disable or provide {calls: number, per: "second" | "minute"} to enable. */
53
+ rateLimit?: rateLimit,
54
+ /** Whether the effect should be cached. */
55
+ cache?: bool,
56
+ }
35
57
  @genType
36
58
  and effectOptions<'input, 'output> = {
37
59
  /** The name of the effect. Used for logging and debugging. */
@@ -40,6 +62,8 @@ and effectOptions<'input, 'output> = {
40
62
  input: S.t<'input>,
41
63
  /** The output schema of the effect. */
42
64
  output: S.t<'output>,
65
+ /** Rate limit for the effect. Set to false to disable or provide {calls: number, per: "second" | "minute"} to enable. */
66
+ rateLimit: rateLimit,
43
67
  /** Whether the effect should be cached. */
44
68
  cache?: bool,
45
69
  }
@@ -47,6 +71,7 @@ and effectOptions<'input, 'output> = {
47
71
  and effectContext = {
48
72
  log: logger,
49
73
  effect: 'input 'output. (effect<'input, 'output>, 'input) => promise<'output>,
74
+ mutable cache: bool,
50
75
  }
51
76
  @genType
52
77
  and effectArgs<'input> = {
@@ -55,12 +80,23 @@ and effectArgs<'input> = {
55
80
  }
56
81
  @@warning("+30")
57
82
 
58
- let experimental_createEffect = (
83
+ let durationToMs = (duration: rateLimitDuration) =>
84
+ switch duration {
85
+ | Second => 1000
86
+ | Minute => 60000
87
+ | Milliseconds(ms) => ms
88
+ }
89
+
90
+ let createEffect = (
59
91
  options: effectOptions<'input, 'output>,
60
92
  handler: effectArgs<'input> => promise<'output>,
61
93
  ) => {
62
94
  let outputSchema =
63
95
  S.schema(_ => options.output)->(Utils.magic: S.t<S.t<'output>> => S.t<Internal.effectOutput>)
96
+ let itemSchema = S.schema((s): Internal.effectCacheItem => {
97
+ id: s.matches(S.string),
98
+ output: s.matches(outputSchema),
99
+ })
64
100
  {
65
101
  name: options.name,
66
102
  handler: handler->(
@@ -68,7 +104,8 @@ let experimental_createEffect = (
68
104
  Internal.effectOutput,
69
105
  >
70
106
  ),
71
- callsCount: 0,
107
+ activeCallsCount: 0,
108
+ prevCallStartTimerRef: %raw(`null`),
72
109
  // This is the way to make the createEffect API
73
110
  // work without the need for users to call S.schema themselves,
74
111
  // but simply pass the desired object/tuple/etc.
@@ -77,20 +114,48 @@ let experimental_createEffect = (
77
114
  Utils.magic: S.t<S.t<'input>> => S.t<Internal.effectInput>
78
115
  ),
79
116
  output: outputSchema,
80
- cache: switch options.cache {
81
- | Some(true) =>
82
- let itemSchema = S.schema((s): Internal.effectCacheItem => {
83
- id: s.matches(S.string),
84
- output: s.matches(outputSchema),
85
- })
117
+ storageMeta: {
118
+ table: Internal.makeCacheTable(~effectName=options.name),
119
+ outputSchema,
120
+ itemSchema,
121
+ },
122
+ defaultShouldCache: switch options.cache {
123
+ | Some(true) => true
124
+ | _ => false
125
+ },
126
+ rateLimit: switch options.rateLimit {
127
+ | Disable => None
128
+ | Enable({calls, per}) =>
86
129
  Some({
87
- table: Internal.makeCacheTable(~effectName=options.name),
88
- outputSchema,
89
- itemSchema,
130
+ callsPerDuration: calls,
131
+ durationMs: per->durationToMs,
132
+ availableCalls: calls,
133
+ windowStartTime: Js.Date.now(),
134
+ queueCount: 0,
135
+ nextWindowPromise: None,
90
136
  })
91
- | None
92
- | Some(false) =>
93
- None
94
137
  },
95
138
  }->(Utils.magic: Internal.effect => effect<'input, 'output>)
96
139
  }
140
+
141
+ @deprecated(
142
+ "Use createEffect instead. The only difference is that rateLimit option becomes required. Set it to false to keep the same behaviour."
143
+ )
144
+ let experimental_createEffect = (
145
+ options: experimental_effectOptions<'input, 'output>,
146
+ handler: effectArgs<'input> => promise<'output>,
147
+ ) => {
148
+ createEffect(
149
+ {
150
+ name: options.name,
151
+ input: options.input,
152
+ output: options.output,
153
+ rateLimit: switch options.rateLimit {
154
+ | Some(rateLimit) => rateLimit
155
+ | None => Disable
156
+ },
157
+ cache: ?options.cache,
158
+ },
159
+ handler,
160
+ )
161
+ }
package/src/Envio.res.js CHANGED
@@ -4,38 +4,75 @@
4
4
  var Internal = require("./Internal.res.js");
5
5
  var S$RescriptSchema = require("rescript-schema/src/S.res.js");
6
6
 
7
- function experimental_createEffect(options, handler) {
7
+ function durationToMs(duration) {
8
+ if (typeof duration !== "number") {
9
+ if (duration === "second") {
10
+ return 1000;
11
+ } else {
12
+ return 60000;
13
+ }
14
+ } else {
15
+ return duration;
16
+ }
17
+ }
18
+
19
+ function createEffect(options, handler) {
8
20
  var outputSchema = S$RescriptSchema.schema(function (param) {
9
21
  return options.output;
10
22
  });
23
+ var itemSchema = S$RescriptSchema.schema(function (s) {
24
+ return {
25
+ id: s.m(S$RescriptSchema.string),
26
+ output: s.m(outputSchema)
27
+ };
28
+ });
11
29
  var match = options.cache;
30
+ var match$1 = options.rateLimit;
12
31
  var tmp;
13
- if (match !== undefined && match) {
14
- var itemSchema = S$RescriptSchema.schema(function (s) {
15
- return {
16
- id: s.m(S$RescriptSchema.string),
17
- output: s.m(outputSchema)
18
- };
19
- });
32
+ if (typeof match$1 !== "object") {
33
+ tmp = undefined;
34
+ } else {
35
+ var calls = match$1.calls;
20
36
  tmp = {
21
- itemSchema: itemSchema,
22
- outputSchema: outputSchema,
23
- table: Internal.makeCacheTable(options.name)
37
+ callsPerDuration: calls,
38
+ durationMs: durationToMs(match$1.per),
39
+ availableCalls: calls,
40
+ windowStartTime: Date.now(),
41
+ queueCount: 0,
42
+ nextWindowPromise: undefined
24
43
  };
25
- } else {
26
- tmp = undefined;
27
44
  }
28
45
  return {
29
46
  name: options.name,
30
47
  handler: handler,
31
- cache: tmp,
48
+ storageMeta: {
49
+ itemSchema: itemSchema,
50
+ outputSchema: outputSchema,
51
+ table: Internal.makeCacheTable(options.name)
52
+ },
53
+ defaultShouldCache: match !== undefined && match ? true : false,
32
54
  output: outputSchema,
33
55
  input: S$RescriptSchema.schema(function (param) {
34
56
  return options.input;
35
57
  }),
36
- callsCount: 0
58
+ activeCallsCount: 0,
59
+ prevCallStartTimerRef: null,
60
+ rateLimit: tmp
37
61
  };
38
62
  }
39
63
 
64
+ function experimental_createEffect(options, handler) {
65
+ var rateLimit = options.rateLimit;
66
+ return createEffect({
67
+ name: options.name,
68
+ input: options.input,
69
+ output: options.output,
70
+ rateLimit: rateLimit !== undefined ? rateLimit : false,
71
+ cache: options.cache
72
+ }, handler);
73
+ }
74
+
75
+ exports.durationToMs = durationToMs;
76
+ exports.createEffect = createEffect;
40
77
  exports.experimental_createEffect = experimental_createEffect;
41
78
  /* Internal Not a pure module */
@@ -4,8 +4,8 @@ type registrations = {
4
4
  }
5
5
 
6
6
  type activeRegistration = {
7
- ecosystem: InternalConfig.ecosystem,
8
- multichain: InternalConfig.multichain,
7
+ ecosystem: Config.ecosystem,
8
+ multichain: Config.multichain,
9
9
  preloadHandlers: bool,
10
10
  registrations: registrations,
11
11
  mutable finished: bool,
@@ -4,8 +4,8 @@ type registrations = {
4
4
  }
5
5
 
6
6
  let startRegistration: (
7
- ~ecosystem: InternalConfig.ecosystem,
8
- ~multichain: InternalConfig.multichain,
7
+ ~ecosystem: Config.ecosystem,
8
+ ~multichain: Config.multichain,
9
9
  ~preloadHandlers: bool,
10
10
  ) => unit
11
11
  let finishRegistration: unit => registrations