@api3/commons 0.7.0 → 0.8.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.
@@ -1,78 +1,21 @@
1
1
  import { ethers } from 'ethers';
2
+ import type { Address, Hex, Mnemonic } from './schema';
2
3
  export declare const PROTOCOL_IDS: {
3
- RRP: string;
4
- PSP: string;
5
- RELAYED_RRP: string;
6
- RELAYED_PSP: string;
7
- AIRSEEKER: string;
4
+ readonly RRP: "1";
5
+ readonly PSP: "2";
6
+ readonly RELAYED_RRP: "3";
7
+ readonly RELAYED_PSP: "4";
8
+ readonly AIRSEEKER: "5";
8
9
  };
9
- /**
10
- * An interface that reflects the structure of a Template
11
- */
12
- export interface Template {
13
- airnode: string;
14
- encodedParameters: string;
15
- endpointId: string;
16
- }
17
- /**
18
- * Derives a template ID from the input parameters
19
- *
20
- * @param airnode an Airnode address
21
- * @param encodedParameters encoded parameters, see the airnode/abi package's encode function
22
- * @param endpointId An endpointID (see deriveEndpointId)
23
- */
24
- export declare const deriveTemplateId: ({ airnode, encodedParameters, endpointId }: Template) => string;
25
- /**
26
- * Derives an endpoint ID
27
- *
28
- * @param oisTitle the OIS title
29
- * @param endpointName the endpoint name
30
- */
10
+ export type ProtocolId = (typeof PROTOCOL_IDS)[keyof typeof PROTOCOL_IDS];
11
+ export declare const deriveTemplateIdV0: (airnode: Address, endpointId: Hex, encodedParameters: Hex) => string;
12
+ export declare const deriveTemplateIdV1: (endpointId: Hex, encodedParameters: Hex) => string;
31
13
  export declare const deriveEndpointId: (oisTitle: string, endpointName: string) => string;
32
- /**
33
- * Derives an airnode address's xpub, required for allowing signed data consumers to verify authenticity
34
- *
35
- * @param airnodeMnemonic the airnode's mnemonic
36
- */
37
- export declare const deriveAirnodeXpub: (airnodeMnemonic: string) => string;
38
- /**
39
- * Derives a wallet path from a sponsor address, used for calculating a sponsor wallet.
40
- *
41
- * @param sponsorAddress an EVM-compatible address
42
- * @param protocolId an API application protocol ID
43
- */
44
- export declare function deriveWalletPathFromSponsorAddress(sponsorAddress: string, protocolId: string): string;
45
- /**
46
- * Encodes/formats a string as a hex-encoded bytes32 string.
47
- *
48
- * @param input the input string
49
- */
14
+ export declare const deriveAirnodeXpub: (airnodeMnemonic: Mnemonic) => string;
15
+ export declare function deriveWalletPathFromSponsorAddress(sponsorAddress: Address, protocolId: ProtocolId): string;
50
16
  export declare const toBytes32String: (input: string) => string;
51
- /**
52
- * Decodes a hex-encoded bytes32 string to a normal string.
53
- *
54
- * @param input the input hex string
55
- */
56
- export declare const fromBytes32String: (input: string) => string;
57
- /**
58
- * Derives a sponsor wallet, given a mnemonic and dapiName.
59
- *
60
- * @param sponsorWalletMnemonic the sponsor wallet mnemonic
61
- * @param dapiName the dapi name
62
- */
63
- export declare const deriveSponsorWallet: (sponsorWalletMnemonic: string, dapiName: string) => ethers.Wallet;
64
- /**
65
- * Derives the ID of a single beacon
66
- *
67
- * @param airnodeAddress the airnode address of the provider that supplies the data used to update this beacon
68
- * @param templateId the templateId of the template used to generate the data used to update this beacon
69
- */
70
- export declare const deriveBeaconId: (airnodeAddress: string, templateId: string) => string;
71
- /**
72
- * Derives the ID of a set of beacons.
73
- * By convention beacon IDs are sorted alphabetically - the ordering impacts the resulting hash.
74
- *
75
- * @param beaconIds an ordered array of beacon ids
76
- */
77
- export declare const deriveBeaconSetId: (beaconIds: string[]) => string;
17
+ export declare const fromBytes32String: (input: Hex) => string;
18
+ export declare const deriveSponsorWallet: (airnodeMnemonic: Mnemonic, dapiName: string, protocolId: ProtocolId) => ethers.Wallet;
19
+ export declare const deriveBeaconId: (airnodeAddress: Address, templateId: Hex) => string;
20
+ export declare const deriveBeaconSetId: (beaconIds: Hex[]) => string;
78
21
  //# sourceMappingURL=derivation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"derivation.d.ts","sourceRoot":"","sources":["../../src/blockchain-utilities/derivation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIhC,eAAO,MAAM,YAAY;;;;;;CAMxB,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,+CAAgD,QAAQ,WACsB,CAAC;AAE5G;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,aAAc,MAAM,gBAAgB,MAAM,WACsC,CAAC;AAE9G;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,oBAAqB,MAAM,WAC0C,CAAC;AAEpG;;;;;GAKG;AACH,wBAAgB,kCAAkC,CAAC,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,UAU5F;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,UAAW,MAAM,WAA4C,CAAC;AAE1F;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,UAAW,MAAM,WAA2C,CAAC;AAE3F;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,0BAA2B,MAAM,YAAY,MAAM,kBAWlF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,mBAAoB,MAAM,cAAc,MAAM,WACa,CAAC;AAEvF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,cAAe,MAAM,EAAE,WACoC,CAAC"}
1
+ {"version":3,"file":"derivation.d.ts","sourceRoot":"","sources":["../../src/blockchain-utilities/derivation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEvD,eAAO,MAAM,YAAY;;;;;;CAMf,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAE1E,eAAO,MAAM,kBAAkB,YAAa,OAAO,cAAc,GAAG,qBAAqB,GAAG,WACe,CAAC;AAE5G,eAAO,MAAM,kBAAkB,eAAgB,GAAG,qBAAqB,GAAG,WACa,CAAC;AAExF,eAAO,MAAM,gBAAgB,aAAc,MAAM,gBAAgB,MAAM,WACsC,CAAC;AAE9G,eAAO,MAAM,iBAAiB,oBAAqB,QAAQ,WACwC,CAAC;AAEpG,wBAAgB,kCAAkC,CAAC,cAAc,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,UAQjG;AAED,eAAO,MAAM,eAAe,UAAW,MAAM,WAA4C,CAAC;AAE1F,eAAO,MAAM,iBAAiB,UAAW,GAAG,WAA2C,CAAC;AAExF,eAAO,MAAM,mBAAmB,oBAAqB,QAAQ,YAAY,MAAM,cAAc,UAAU,kBAStG,CAAC;AAEF,eAAO,MAAM,cAAc,mBAAoB,OAAO,cAAc,GAAG,WACe,CAAC;AAEvF,eAAO,MAAM,iBAAiB,cAAe,GAAG,EAAE,WAEuC,CAAC"}
@@ -1,8 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.deriveBeaconSetId = exports.deriveBeaconId = exports.deriveSponsorWallet = exports.fromBytes32String = exports.toBytes32String = exports.deriveWalletPathFromSponsorAddress = exports.deriveAirnodeXpub = exports.deriveEndpointId = exports.deriveTemplateId = exports.PROTOCOL_IDS = void 0;
3
+ exports.deriveBeaconSetId = exports.deriveBeaconId = exports.deriveSponsorWallet = exports.fromBytes32String = exports.toBytes32String = exports.deriveWalletPathFromSponsorAddress = exports.deriveAirnodeXpub = exports.deriveEndpointId = exports.deriveTemplateIdV1 = exports.deriveTemplateIdV0 = exports.PROTOCOL_IDS = void 0;
4
4
  const ethers_1 = require("ethers");
5
- const schema_1 = require("./schema");
6
5
  exports.PROTOCOL_IDS = {
7
6
  RRP: '1',
8
7
  PSP: '2',
@@ -10,38 +9,15 @@ exports.PROTOCOL_IDS = {
10
9
  RELAYED_PSP: '4',
11
10
  AIRSEEKER: '5',
12
11
  };
13
- /**
14
- * Derives a template ID from the input parameters
15
- *
16
- * @param airnode an Airnode address
17
- * @param encodedParameters encoded parameters, see the airnode/abi package's encode function
18
- * @param endpointId An endpointID (see deriveEndpointId)
19
- */
20
- const deriveTemplateId = ({ airnode, encodedParameters, endpointId }) => ethers_1.ethers.utils.solidityKeccak256(['address', 'bytes32', 'bytes'], [airnode, endpointId, encodedParameters]);
21
- exports.deriveTemplateId = deriveTemplateId;
22
- /**
23
- * Derives an endpoint ID
24
- *
25
- * @param oisTitle the OIS title
26
- * @param endpointName the endpoint name
27
- */
12
+ const deriveTemplateIdV0 = (airnode, endpointId, encodedParameters) => ethers_1.ethers.utils.solidityKeccak256(['address', 'bytes32', 'bytes'], [airnode, endpointId, encodedParameters]);
13
+ exports.deriveTemplateIdV0 = deriveTemplateIdV0;
14
+ const deriveTemplateIdV1 = (endpointId, encodedParameters) => ethers_1.ethers.utils.solidityKeccak256(['bytes32', 'bytes'], [endpointId, encodedParameters]);
15
+ exports.deriveTemplateIdV1 = deriveTemplateIdV1;
28
16
  const deriveEndpointId = (oisTitle, endpointName) => ethers_1.ethers.utils.keccak256(ethers_1.ethers.utils.defaultAbiCoder.encode(['string', 'string'], [oisTitle, endpointName]));
29
17
  exports.deriveEndpointId = deriveEndpointId;
30
- /**
31
- * Derives an airnode address's xpub, required for allowing signed data consumers to verify authenticity
32
- *
33
- * @param airnodeMnemonic the airnode's mnemonic
34
- */
35
18
  const deriveAirnodeXpub = (airnodeMnemonic) => ethers_1.ethers.utils.HDNode.fromMnemonic(airnodeMnemonic).derivePath("m/44'/60'/0'").neuter().extendedKey;
36
19
  exports.deriveAirnodeXpub = deriveAirnodeXpub;
37
- /**
38
- * Derives a wallet path from a sponsor address, used for calculating a sponsor wallet.
39
- *
40
- * @param sponsorAddress an EVM-compatible address
41
- * @param protocolId an API application protocol ID
42
- */
43
20
  function deriveWalletPathFromSponsorAddress(sponsorAddress, protocolId) {
44
- schema_1.addressSchema.parse(sponsorAddress);
45
21
  const sponsorAddressBN = ethers_1.ethers.BigNumber.from(sponsorAddress);
46
22
  const paths = [];
47
23
  for (let i = 0; i < 6; i++) {
@@ -51,47 +27,21 @@ function deriveWalletPathFromSponsorAddress(sponsorAddress, protocolId) {
51
27
  return `${protocolId}/${paths.join('/')}`;
52
28
  }
53
29
  exports.deriveWalletPathFromSponsorAddress = deriveWalletPathFromSponsorAddress;
54
- /**
55
- * Encodes/formats a string as a hex-encoded bytes32 string.
56
- *
57
- * @param input the input string
58
- */
59
30
  const toBytes32String = (input) => ethers_1.ethers.utils.formatBytes32String(input);
60
31
  exports.toBytes32String = toBytes32String;
61
- /**
62
- * Decodes a hex-encoded bytes32 string to a normal string.
63
- *
64
- * @param input the input hex string
65
- */
66
32
  const fromBytes32String = (input) => ethers_1.ethers.utils.parseBytes32String(input);
67
33
  exports.fromBytes32String = fromBytes32String;
68
- /**
69
- * Derives a sponsor wallet, given a mnemonic and dapiName.
70
- *
71
- * @param sponsorWalletMnemonic the sponsor wallet mnemonic
72
- * @param dapiName the dapi name
73
- */
74
- const deriveSponsorWallet = (sponsorWalletMnemonic, dapiName) => {
34
+ const deriveSponsorWallet = (airnodeMnemonic, dapiName, protocolId) => {
75
35
  // Take first 20 bytes of dapiName as sponsor address together with the "0x" prefix.
76
36
  const sponsorAddress = ethers_1.ethers.utils.getAddress(dapiName.slice(0, 42));
77
- const sponsorWallet = ethers_1.ethers.Wallet.fromMnemonic(sponsorWalletMnemonic, `m/44'/60'/0'/${(deriveWalletPathFromSponsorAddress(sponsorAddress, exports.PROTOCOL_IDS.AIRSEEKER), exports.PROTOCOL_IDS.AIRSEEKER)}`);
37
+ const sponsorWallet = ethers_1.ethers.Wallet.fromMnemonic(airnodeMnemonic, `m/44'/60'/0'/${deriveWalletPathFromSponsorAddress(sponsorAddress, protocolId)}`);
78
38
  return sponsorWallet;
79
39
  };
80
40
  exports.deriveSponsorWallet = deriveSponsorWallet;
81
- /**
82
- * Derives the ID of a single beacon
83
- *
84
- * @param airnodeAddress the airnode address of the provider that supplies the data used to update this beacon
85
- * @param templateId the templateId of the template used to generate the data used to update this beacon
86
- */
87
41
  const deriveBeaconId = (airnodeAddress, templateId) => ethers_1.ethers.utils.solidityKeccak256(['address', 'bytes32'], [airnodeAddress, templateId]);
88
42
  exports.deriveBeaconId = deriveBeaconId;
89
- /**
90
- * Derives the ID of a set of beacons.
91
- * By convention beacon IDs are sorted alphabetically - the ordering impacts the resulting hash.
92
- *
93
- * @param beaconIds an ordered array of beacon ids
94
- */
95
- const deriveBeaconSetId = (beaconIds) => ethers_1.ethers.utils.keccak256(ethers_1.ethers.utils.defaultAbiCoder.encode(['bytes32[]'], [beaconIds]));
43
+ const deriveBeaconSetId = (beaconIds) =>
44
+ // By convention beacon IDs are sorted alphabetically - the ordering impacts the resulting hash.
45
+ ethers_1.ethers.utils.keccak256(ethers_1.ethers.utils.defaultAbiCoder.encode(['bytes32[]'], [beaconIds]));
96
46
  exports.deriveBeaconSetId = deriveBeaconSetId;
97
47
  //# sourceMappingURL=derivation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"derivation.js","sourceRoot":"","sources":["../../src/blockchain-utilities/derivation.ts"],"names":[],"mappings":";;;AAAA,mCAAgC;AAEhC,qCAAyC;AAE5B,QAAA,YAAY,GAAG;IAC1B,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;IACR,WAAW,EAAE,GAAG;IAChB,WAAW,EAAE,GAAG;IAChB,SAAS,EAAE,GAAG;CACf,CAAC;AAWF;;;;;;GAMG;AACI,MAAM,gBAAgB,GAAG,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAY,EAAE,EAAE,CACvF,eAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAC,CAAC;AAD/F,QAAA,gBAAgB,oBAC+E;AAE5G;;;;;GAKG;AACI,MAAM,gBAAgB,GAAG,CAAC,QAAgB,EAAE,YAAoB,EAAE,EAAE,CACzE,eAAM,CAAC,KAAK,CAAC,SAAS,CAAC,eAAM,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;AADjG,QAAA,gBAAgB,oBACiF;AAE9G;;;;GAIG;AACI,MAAM,iBAAiB,GAAG,CAAC,eAAuB,EAAE,EAAE,CAC3D,eAAM,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC;AADvF,QAAA,iBAAiB,qBACsE;AAEpG;;;;;GAKG;AACH,SAAgB,kCAAkC,CAAC,cAAsB,EAAE,UAAkB;IAC3F,sBAAa,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAEpC,MAAM,gBAAgB,GAAG,eAAM,CAAC,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,EAAE,CAAC;IACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;QAC1B,MAAM,uBAAuB,GAAG,gBAAgB,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC7D,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;KACzD;IACD,OAAO,GAAG,UAAU,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AAC5C,CAAC;AAVD,gFAUC;AAED;;;;GAIG;AACI,MAAM,eAAe,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,eAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;AAA7E,QAAA,eAAe,mBAA8D;AAE1F;;;;GAIG;AACI,MAAM,iBAAiB,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,eAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;AAA9E,QAAA,iBAAiB,qBAA6D;AAE3F;;;;;GAKG;AACI,MAAM,mBAAmB,GAAG,CAAC,qBAA6B,EAAE,QAAgB,EAAE,EAAE;IACrF,oFAAoF;IACpF,MAAM,cAAc,GAAG,eAAM,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACtE,MAAM,aAAa,GAAG,eAAM,CAAC,MAAM,CAAC,YAAY,CAC9C,qBAAqB,EACrB,gBACE,CAAC,kCAAkC,CAAC,cAAc,EAAE,oBAAY,CAAC,SAAS,CAAC,EAAE,oBAAY,CAAC,SAAS,CACrG,EAAE,CACH,CAAC;IAEF,OAAO,aAAa,CAAC;AACvB,CAAC,CAAC;AAXW,QAAA,mBAAmB,uBAW9B;AAEF;;;;;GAKG;AACI,MAAM,cAAc,GAAG,CAAC,cAAsB,EAAE,UAAkB,EAAE,EAAE,CAC3E,eAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC,CAAC;AAD1E,QAAA,cAAc,kBAC4D;AAEvF;;;;;GAKG;AACI,MAAM,iBAAiB,GAAG,CAAC,SAAmB,EAAE,EAAE,CACvD,eAAM,CAAC,KAAK,CAAC,SAAS,CAAC,eAAM,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAD7E,QAAA,iBAAiB,qBAC4D"}
1
+ {"version":3,"file":"derivation.js","sourceRoot":"","sources":["../../src/blockchain-utilities/derivation.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,14 @@
1
1
  import { z } from 'zod';
2
- /**
3
- * A Zod validation schema that represents an EVM-compatible address.
4
- */
5
- export declare const addressSchema: z.ZodString;
6
- /**
7
- * A Zod validation schema that represents an EVM-compatible hash, which includes beacon IDs and template IDs.
8
- */
9
- export declare const idSchema: z.ZodString;
2
+ export declare const hexSchema: z.ZodString;
3
+ export type Hex = `0x${string}`;
4
+ export declare const addressSchema: z.ZodEffects<z.ZodString, `0x${string}`, string>;
10
5
  export type Address = z.infer<typeof addressSchema>;
11
- export type Id = z.infer<typeof idSchema>;
6
+ export declare const keccak256HashSchema: z.ZodEffects<z.ZodString, `0x${string}`, string>;
7
+ export type Keccak256Hash = z.infer<typeof keccak256HashSchema>;
8
+ export declare const chainIdSchema: z.ZodEffects<z.ZodString, string, string>;
9
+ export type ChainId = z.infer<typeof chainIdSchema>;
10
+ export declare const ethUnitsSchema: z.ZodUnion<[z.ZodLiteral<"wei">, z.ZodLiteral<"kwei">, z.ZodLiteral<"mwei">, z.ZodLiteral<"gwei">, z.ZodLiteral<"szabo">, z.ZodLiteral<"finney">, z.ZodLiteral<"ether">]>;
11
+ export type EthUnits = z.infer<typeof ethUnitsSchema>;
12
+ export declare const mnemonicSchema: z.ZodEffects<z.ZodString, string, string>;
13
+ export type Mnemonic = z.infer<typeof mnemonicSchema>;
12
14
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/blockchain-utilities/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,aAAa,aAAwE,CAAC;AAEnG;;GAEG;AACH,eAAO,MAAM,QAAQ,aAAqE,CAAC;AAE3F,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AACpD,MAAM,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/blockchain-utilities/schema.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,SAAS,aAAoE,CAAC;AAE3F,MAAM,MAAM,GAAG,GAAG,KAAK,MAAM,EAAE,CAAC;AAEhC,eAAO,MAAM,aAAa,kDAQxB,CAAC;AAEH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,eAAO,MAAM,mBAAmB,kDAGC,CAAC;AAElC,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,aAAa,2CAGoD,CAAC;AAE/E,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,eAAO,MAAM,cAAc,2KAQzB,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,cAAc,2CAEwD,CAAC;AAEpF,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC"}
@@ -1,13 +1,36 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.idSchema = exports.addressSchema = void 0;
3
+ exports.mnemonicSchema = exports.ethUnitsSchema = exports.chainIdSchema = exports.keccak256HashSchema = exports.addressSchema = exports.hexSchema = void 0;
4
+ const promise_utils_1 = require("@api3/promise-utils");
5
+ const ethers_1 = require("ethers");
4
6
  const zod_1 = require("zod");
5
- /**
6
- * A Zod validation schema that represents an EVM-compatible address.
7
- */
8
- exports.addressSchema = zod_1.z.string().regex(/^0x[\dA-Fa-f]{40}$/, 'Must be a valid EVM address');
9
- /**
10
- * A Zod validation schema that represents an EVM-compatible hash, which includes beacon IDs and template IDs.
11
- */
12
- exports.idSchema = zod_1.z.string().regex(/^0x[\dA-Fa-f]{64}$/, 'Must be a valid EVM hash');
7
+ exports.hexSchema = zod_1.z.string().regex(/^0x[\dA-Fa-f]+$/, 'Must be a valid hex string');
8
+ exports.addressSchema = zod_1.z.string().transform((value, ctx) => {
9
+ const goParseAddress = (0, promise_utils_1.goSync)(() => ethers_1.ethers.utils.getAddress(value));
10
+ if (!goParseAddress.success) {
11
+ ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, message: 'Invalid EVM address' });
12
+ return zod_1.z.NEVER;
13
+ }
14
+ return goParseAddress.data;
15
+ });
16
+ exports.keccak256HashSchema = zod_1.z
17
+ .string()
18
+ .regex(/^0x[\dA-Fa-f]{64}$/, 'Must be a valid EVM keccak256 hash')
19
+ .transform((val) => val);
20
+ exports.chainIdSchema = zod_1.z
21
+ .string()
22
+ .regex(/^\d+$/, 'Must be a valid chain ID')
23
+ .refine((chainId) => Number(chainId) > 0, 'Chain ID must be greater than 0');
24
+ exports.ethUnitsSchema = zod_1.z.union([
25
+ zod_1.z.literal('wei'),
26
+ zod_1.z.literal('kwei'),
27
+ zod_1.z.literal('mwei'),
28
+ zod_1.z.literal('gwei'),
29
+ zod_1.z.literal('szabo'),
30
+ zod_1.z.literal('finney'),
31
+ zod_1.z.literal('ether'),
32
+ ]);
33
+ exports.mnemonicSchema = zod_1.z
34
+ .string()
35
+ .refine((mnemonic) => ethers_1.ethers.utils.isValidMnemonic(mnemonic), 'Invalid mnemonic');
13
36
  //# sourceMappingURL=schema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/blockchain-utilities/schema.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAExB;;GAEG;AACU,QAAA,aAAa,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,oBAAoB,EAAE,6BAA6B,CAAC,CAAC;AAEnG;;GAEG;AACU,QAAA,QAAQ,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,oBAAoB,EAAE,0BAA0B,CAAC,CAAC"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/blockchain-utilities/schema.ts"],"names":[],"mappings":";;;AAAA,uDAA6C;AAC7C,mCAAgC;AAChC,6BAAwB;AAEX,QAAA,SAAS,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,iBAAiB,EAAE,4BAA4B,CAAC,CAAC;AAI9E,QAAA,aAAa,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAC/D,MAAM,cAAc,GAAG,IAAA,sBAAM,EAAC,GAAG,EAAE,CAAC,eAAM,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IACpE,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;QAC3B,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC,CAAC;QAC9E,OAAO,OAAC,CAAC,KAAK,CAAC;KAChB;IAED,OAAO,cAAc,CAAC,IAAW,CAAC;AACpC,CAAC,CAAC,CAAC;AAIU,QAAA,mBAAmB,GAAG,OAAC;KACjC,MAAM,EAAE;KACR,KAAK,CAAC,oBAAoB,EAAE,oCAAoC,CAAC;KACjE,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAU,CAAC,CAAC;AAIrB,QAAA,aAAa,GAAG,OAAC;KAC3B,MAAM,EAAE;KACR,KAAK,CAAC,OAAO,EAAE,0BAA0B,CAAC;KAC1C,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,iCAAiC,CAAC,CAAC;AAIlE,QAAA,cAAc,GAAG,OAAC,CAAC,KAAK,CAAC;IACpC,OAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IAChB,OAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACjB,OAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACjB,OAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACjB,OAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IAClB,OAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IACnB,OAAC,CAAC,OAAO,CAAC,OAAO,CAAC;CACnB,CAAC,CAAC;AAIU,QAAA,cAAc,GAAG,OAAC;KAC5B,MAAM,EAAE;KACR,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,eAAM,CAAC,KAAK,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAC,CAAC"}
@@ -1,12 +1,12 @@
1
1
  import dotenv from 'dotenv';
2
2
  import { z } from 'zod';
3
- export declare const secretNamePattern: RegExp;
4
- export declare const secretNameSchema: z.ZodString;
5
- export declare const secretsSchema: z.ZodRecord<z.ZodString, z.ZodString>;
6
- export declare const nonBlankSecretsSchema: z.ZodRecord<z.ZodString, z.ZodString>;
3
+ export declare const strictSecretNamePattern: RegExp;
4
+ export declare const strictSecretNameSchema: z.ZodString;
5
+ export declare const nonBlankSecretValueSchema: z.ZodString;
7
6
  export type Secrets = Record<string, string>;
8
7
  export interface InterpolationOptions {
9
- allowBlankSecretValue: boolean;
8
+ allowBlankSecretValue?: boolean;
9
+ validateSecretName?: boolean;
10
10
  }
11
11
  export type AnyObject = Record<string, unknown>;
12
12
  export declare function interpolateSecretsIntoConfig<T = AnyObject>(config: T, secrets: unknown, options?: InterpolationOptions): T;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config-parsing/index.ts"],"names":[],"mappings":"AAEA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,iBAAiB,QAAqB,CAAC;AAEpD,eAAO,MAAM,gBAAgB,aAEoF,CAAC;AAElH,eAAO,MAAM,aAAa,uCAAyC,CAAC;AAEpE,eAAO,MAAM,qBAAqB,uCAGjC,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAe7C,MAAM,WAAW,oBAAoB;IACnC,qBAAqB,EAAE,OAAO,CAAC;CAChC;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,wBAAgB,4BAA4B,CAAC,CAAC,GAAG,SAAS,EACxD,MAAM,EAAE,CAAC,EACT,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,oBAAsD,KA0BhE;AAED,eAAO,MAAM,WAAW,SAAU,MAAM,6BAA6C,CAAC;AAEtF,eAAO,MAAM,UAAU,SAAU,MAAM,QAA2C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config-parsing/index.ts"],"names":[],"mappings":"AAEA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,uBAAuB,QAAqB,CAAC;AAE1D,eAAO,MAAM,sBAAsB,aAKhC,CAAC;AAEJ,eAAO,MAAM,yBAAyB,aAA2D,CAAC;AAElG,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAe7C,MAAM,WAAW,oBAAoB;IACnC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,wBAAgB,4BAA4B,CAAC,CAAC,GAAG,SAAS,EACxD,MAAM,EAAE,CAAC,EACT,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,oBAAoB,KA4B/B;AAED,eAAO,MAAM,WAAW,SAAU,MAAM,6BAA6C,CAAC;AAEtF,eAAO,MAAM,UAAU,SAAU,MAAM,QAA2C,CAAC"}
@@ -3,18 +3,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.loadConfig = exports.loadSecrets = exports.interpolateSecretsIntoConfig = exports.nonBlankSecretsSchema = exports.secretsSchema = exports.secretNameSchema = exports.secretNamePattern = void 0;
6
+ exports.loadConfig = exports.loadSecrets = exports.interpolateSecretsIntoConfig = exports.nonBlankSecretValueSchema = exports.strictSecretNameSchema = exports.strictSecretNamePattern = void 0;
7
7
  const node_fs_1 = require("node:fs");
8
8
  const dotenv_1 = __importDefault(require("dotenv"));
9
9
  const reduce_1 = __importDefault(require("lodash/reduce"));
10
10
  const template_1 = __importDefault(require("lodash/template"));
11
11
  const zod_1 = require("zod");
12
- exports.secretNamePattern = /^[A-Z][\dA-Z_]*$/;
13
- exports.secretNameSchema = zod_1.z
12
+ exports.strictSecretNamePattern = /^[A-Z][\dA-Z_]*$/;
13
+ exports.strictSecretNameSchema = zod_1.z
14
14
  .string()
15
- .regex(exports.secretNamePattern, `Secret name is not a valid. Secret name must match ${exports.secretNamePattern.toString()}`);
16
- exports.secretsSchema = zod_1.z.record(exports.secretNameSchema, zod_1.z.string());
17
- exports.nonBlankSecretsSchema = zod_1.z.record(exports.secretNameSchema, zod_1.z.string().min(1, { message: 'Secret cannot be blank' }));
15
+ .regex(exports.strictSecretNamePattern, `Secret name is not a valid. Secret name must match ${exports.strictSecretNamePattern.toString()}`);
16
+ exports.nonBlankSecretValueSchema = zod_1.z.string().min(1, { message: 'Secret cannot be blank' });
18
17
  // Regular expression that does not match anything, ensuring no escaping or interpolation happens
19
18
  // https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L199
20
19
  // eslint-disable-next-line prefer-named-capture-group
@@ -27,9 +26,11 @@ const ES_MATCH_REGEXP = /(?<!\\)\${([^\\}]*(?:\\.[^\\}]*)*)}/g;
27
26
  // because "\\" becomes "\\\\" when converted to string
28
27
  // eslint-disable-next-line prefer-named-capture-group
29
28
  const ESCAPED_ES_MATCH_REGEXP = /\\\\(\${([^\\}]*(?:\\.[^\\}]*)*)})/g;
30
- function interpolateSecretsIntoConfig(config, secrets, options = { allowBlankSecretValue: true }) {
31
- const { allowBlankSecretValue } = options;
32
- const validatedSecrets = (allowBlankSecretValue ? exports.secretsSchema : exports.nonBlankSecretsSchema).parse(secrets);
29
+ function interpolateSecretsIntoConfig(config, secrets, options) {
30
+ const { allowBlankSecretValue = true, validateSecretName = true } = options ?? {};
31
+ const secretNameSchema = validateSecretName ? exports.strictSecretNameSchema : zod_1.z.string();
32
+ const secretValueSchema = allowBlankSecretValue ? zod_1.z.string() : exports.nonBlankSecretValueSchema;
33
+ const validatedSecrets = zod_1.z.record(secretNameSchema, secretValueSchema).parse(secrets);
33
34
  const stringifiedSecrets = (0, reduce_1.default)(validatedSecrets, (acc, value, key) => {
34
35
  return {
35
36
  ...acc,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config-parsing/index.ts"],"names":[],"mappings":";;;;;;AAAA,qCAAuC;AAEvC,oDAA4B;AAC5B,2DAAmC;AACnC,+DAAuC;AACvC,6BAAwB;AAEX,QAAA,iBAAiB,GAAG,kBAAkB,CAAC;AAEvC,QAAA,gBAAgB,GAAG,OAAC;KAC9B,MAAM,EAAE;KACR,KAAK,CAAC,yBAAiB,EAAE,sDAAsD,yBAAiB,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAErG,QAAA,aAAa,GAAG,OAAC,CAAC,MAAM,CAAC,wBAAgB,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC;AAEvD,QAAA,qBAAqB,GAAG,OAAC,CAAC,MAAM,CAC3C,wBAAgB,EAChB,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,wBAAwB,EAAE,CAAC,CACzD,CAAC;AAIF,iGAAiG;AACjG,+DAA+D;AAC/D,sDAAsD;AACtD,MAAM,eAAe,GAAG,MAAM,CAAC;AAC/B,gFAAgF;AAChF,+DAA+D;AAC/D,sDAAsD;AACtD,MAAM,eAAe,GAAG,sCAAsC,CAAC;AAC/D,wHAAwH;AACxH,uDAAuD;AACvD,sDAAsD;AACtD,MAAM,uBAAuB,GAAG,qCAAqC,CAAC;AAQtE,SAAgB,4BAA4B,CAC1C,MAAS,EACT,OAAgB,EAChB,UAAgC,EAAE,qBAAqB,EAAE,IAAI,EAAE;IAE/D,MAAM,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAC;IAC1C,MAAM,gBAAgB,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC,qBAAa,CAAC,CAAC,CAAC,6BAAqB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAExG,MAAM,kBAAkB,GAAG,IAAA,gBAAM,EAC/B,gBAAgB,EAChB,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QAClB,OAAO;YACL,GAAG,GAAG;YACN,8GAA8G;YAC9G,wBAAwB;YACxB,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;SAC1C,CAAC;IACJ,CAAC,EACD,EAAa,CACd,CAAC;IAEF,MAAM,kBAAkB,GAAG,IAAA,kBAAQ,EAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE;QAC1D,MAAM,EAAE,eAAe;QACvB,QAAQ,EAAE,eAAe;QACzB,WAAW,EAAE,eAAe;KAC7B,CAAC,CAAC,kBAAkB,CAAC,CAAC;IACvB,oHAAoH;IACpH,2CAA2C;IAC3C,OAAO,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,UAAU,CAAC,uBAAuB,EAAE,IAAI,CAAC,CAAM,CAAC;AACvF,CAAC;AA7BD,oEA6BC;AAEM,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,gBAAM,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;AAAzE,QAAA,WAAW,eAA8D;AAE/E,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;AAAtE,QAAA,UAAU,cAA4D"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config-parsing/index.ts"],"names":[],"mappings":";;;;;;AAAA,qCAAuC;AAEvC,oDAA4B;AAC5B,2DAAmC;AACnC,+DAAuC;AACvC,6BAAwB;AAEX,QAAA,uBAAuB,GAAG,kBAAkB,CAAC;AAE7C,QAAA,sBAAsB,GAAG,OAAC;KACpC,MAAM,EAAE;KACR,KAAK,CACJ,+BAAuB,EACvB,sDAAsD,+BAAuB,CAAC,QAAQ,EAAE,EAAE,CAC3F,CAAC;AAES,QAAA,yBAAyB,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,wBAAwB,EAAE,CAAC,CAAC;AAIlG,iGAAiG;AACjG,+DAA+D;AAC/D,sDAAsD;AACtD,MAAM,eAAe,GAAG,MAAM,CAAC;AAC/B,gFAAgF;AAChF,+DAA+D;AAC/D,sDAAsD;AACtD,MAAM,eAAe,GAAG,sCAAsC,CAAC;AAC/D,wHAAwH;AACxH,uDAAuD;AACvD,sDAAsD;AACtD,MAAM,uBAAuB,GAAG,qCAAqC,CAAC;AAStE,SAAgB,4BAA4B,CAC1C,MAAS,EACT,OAAgB,EAChB,OAA8B;IAE9B,MAAM,EAAE,qBAAqB,GAAG,IAAI,EAAE,kBAAkB,GAAG,IAAI,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;IAClF,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,CAAC,CAAC,8BAAsB,CAAC,CAAC,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;IAClF,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,CAAC,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,iCAAyB,CAAC;IACzF,MAAM,gBAAgB,GAAG,OAAC,CAAC,MAAM,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEtF,MAAM,kBAAkB,GAAG,IAAA,gBAAM,EAC/B,gBAAgB,EAChB,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QAClB,OAAO;YACL,GAAG,GAAG;YACN,8GAA8G;YAC9G,wBAAwB;YACxB,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;SAC1C,CAAC;IACJ,CAAC,EACD,EAAa,CACd,CAAC;IAEF,MAAM,kBAAkB,GAAG,IAAA,kBAAQ,EAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE;QAC1D,MAAM,EAAE,eAAe;QACvB,QAAQ,EAAE,eAAe;QACzB,WAAW,EAAE,eAAe;KAC7B,CAAC,CAAC,kBAAkB,CAAC,CAAC;IACvB,oHAAoH;IACpH,2CAA2C;IAC3C,OAAO,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,UAAU,CAAC,uBAAuB,EAAE,IAAI,CAAC,CAAM,CAAC;AACvF,CAAC;AA/BD,oEA+BC;AAEM,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,gBAAM,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;AAAzE,QAAA,WAAW,eAA8D;AAE/E,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;AAAtE,QAAA,UAAU,cAA4D"}
@@ -1,2 +1,3 @@
1
1
  export * from './blockchain-utilities';
2
+ export * from './http';
2
3
  //# sourceMappingURL=universal-index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"universal-index.d.ts","sourceRoot":"","sources":["../src/universal-index.ts"],"names":[],"mappings":"AACA,cAAc,wBAAwB,CAAC"}
1
+ {"version":3,"file":"universal-index.d.ts","sourceRoot":"","sources":["../src/universal-index.ts"],"names":[],"mappings":"AACA,cAAc,wBAAwB,CAAC;AACvC,cAAc,QAAQ,CAAC"}
@@ -16,4 +16,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  // NOTE: Only export modules which work in both Node.js and browser environments.
18
18
  __exportStar(require("./blockchain-utilities"), exports);
19
+ __exportStar(require("./http"), exports);
19
20
  //# sourceMappingURL=universal-index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"universal-index.js","sourceRoot":"","sources":["../src/universal-index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iFAAiF;AACjF,yDAAuC"}
1
+ {"version":3,"file":"universal-index.js","sourceRoot":"","sources":["../src/universal-index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iFAAiF;AACjF,yDAAuC;AACvC,yCAAuB"}
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "@api3/commons",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "keywords": [],
5
5
  "license": "MIT",
6
6
  "engines": {
7
- "node": "^18.14.0 || ^20.10.0",
8
- "pnpm": "^8.8.0"
7
+ "node": ">=18.14.0"
9
8
  },
10
9
  "files": [
11
10
  "dist",
@@ -6,12 +6,14 @@ import {
6
6
  deriveBeaconSetId,
7
7
  deriveEndpointId,
8
8
  deriveSponsorWallet,
9
- deriveTemplateId,
9
+ deriveTemplateIdV0,
10
+ deriveTemplateIdV1,
10
11
  deriveWalletPathFromSponsorAddress,
11
12
  fromBytes32String,
12
13
  PROTOCOL_IDS,
13
14
  toBytes32String,
14
15
  } from './derivation';
16
+ import type { Address } from './schema';
15
17
 
16
18
  describe('deriveWalletPathFromSponsorAddress', () => {
17
19
  it('converts address to derivation path', () => {
@@ -19,7 +21,7 @@ describe('deriveWalletPathFromSponsorAddress', () => {
19
21
  const res = deriveWalletPathFromSponsorAddress(sponsorAddress, PROTOCOL_IDS.AIRSEEKER);
20
22
  expect(res).toBe('5/973563544/2109481170/2137349576/871269377/610184194/17');
21
23
 
22
- const randomAddress = ethers.utils.getAddress(ethers.utils.hexlify(ethers.utils.randomBytes(20)));
24
+ const randomAddress = ethers.utils.getAddress(ethers.utils.hexlify(ethers.utils.randomBytes(20))) as Address;
23
25
  const randomPath = deriveWalletPathFromSponsorAddress(randomAddress, PROTOCOL_IDS.AIRSEEKER);
24
26
  expect(res).not.toStrictEqual(randomPath);
25
27
  });
@@ -45,24 +47,7 @@ describe('deriveWalletPathFromSponsorAddress', () => {
45
47
  });
46
48
 
47
49
  it('throws if address is an empty string', () => {
48
- const sponsorAddress = '';
49
- expect(() => deriveWalletPathFromSponsorAddress(sponsorAddress, PROTOCOL_IDS.AIRSEEKER)).toThrow(
50
- expect.objectContaining({ name: expect.stringContaining('Error') })
51
- );
52
- });
53
-
54
- it('throws if address is invalid', () => {
55
- let sponsorAddress = '7dD0803Fd957723EdE10693A076698';
56
- expect(() => deriveWalletPathFromSponsorAddress(sponsorAddress, PROTOCOL_IDS.AIRSEEKER)).toThrow(
57
- expect.objectContaining({ name: expect.stringContaining('Error') })
58
- );
59
-
60
- sponsorAddress = ethers.utils.hexlify(ethers.utils.randomBytes(4));
61
- expect(() => deriveWalletPathFromSponsorAddress(sponsorAddress, PROTOCOL_IDS.AIRSEEKER)).toThrow(
62
- expect.objectContaining({ name: expect.stringContaining('Error') })
63
- );
64
-
65
- sponsorAddress = ethers.utils.hexlify(ethers.utils.randomBytes(32));
50
+ const sponsorAddress = '' as Address;
66
51
  expect(() => deriveWalletPathFromSponsorAddress(sponsorAddress, PROTOCOL_IDS.AIRSEEKER)).toThrow(
67
52
  expect.objectContaining({ name: expect.stringContaining('Error') })
68
53
  );
@@ -73,20 +58,39 @@ describe('deriveWalletPathFromSponsorAddress', () => {
73
58
  const dapiName = ethers.utils.formatBytes32String('BTC/ETH');
74
59
  const sponsorWallet = deriveSponsorWallet(
75
60
  'test test test test test test test test test test test junk',
76
- dapiName
61
+ dapiName,
62
+ '1'
77
63
  );
78
64
 
79
- expect(sponsorWallet.address).toBe('0x1e6f0dfb1775f5032f12f56a01526351eD3F07aF');
65
+ expect(sponsorWallet.address).toBe('0x4f86228e0Bc58829Cd77547224291bb8d212174D');
80
66
  });
81
67
 
82
68
  it('throws deriving a sponsor wallet due to an invalid DApi name', () => {
83
69
  const dapiName = 'invalid dapi name';
84
70
  const throwingFn = () =>
85
- deriveSponsorWallet('test test test test test test test test test test test junk', dapiName);
71
+ deriveSponsorWallet('test test test test test test test test test test test junk', dapiName, '5');
86
72
 
87
73
  expect(throwingFn).toThrow(expect.objectContaining({ name: expect.stringContaining('Error') }));
88
74
  });
89
75
 
76
+ it('derives the same sponsor wallet as Airnode', () => {
77
+ function deriveSponsorWalletAirnode(masterHDNode: ethers.utils.HDNode, sponsorAddress: Address): ethers.Wallet {
78
+ const sponsorWalletHdNode = masterHDNode.derivePath(
79
+ `m/44'/60'/0'/${deriveWalletPathFromSponsorAddress(sponsorAddress, '1')}`
80
+ );
81
+ return new ethers.Wallet(sponsorWalletHdNode.privateKey);
82
+ }
83
+ const mnemonic = 'achieve climb couple wait accident symbol spy blouse reduce foil echo label';
84
+ const hdNode = ethers.utils.HDNode.fromMnemonic(mnemonic);
85
+
86
+ // https://github.com/api3dao/airnode/blob/a4c17c28c8b31c9fb13d2828764b89f1063b702f/packages/airnode-node/src/evm/wallet.test.ts#L25
87
+ const expectedSponsorWallet = deriveSponsorWalletAirnode(hdNode, '0x06f509f73eefba36352bc8228f9112c3786100da');
88
+ const actualSponsorWallet = deriveSponsorWallet(mnemonic, '0x06f509f73eefba36352bc8228f9112c3786100da', '1');
89
+
90
+ expect(actualSponsorWallet.address).toBe(expectedSponsorWallet.address);
91
+ expect(actualSponsorWallet.address).toBe('0x228A54F33E46fbb32a62ca650Fcc9eD3C730511d');
92
+ });
93
+
90
94
  it(`derives an airnode's xpub from a mnemonic`, () => {
91
95
  const xpub = deriveAirnodeXpub('test test test test test test test test test test test junk');
92
96
 
@@ -101,14 +105,23 @@ describe('deriveWalletPathFromSponsorAddress', () => {
101
105
  expect(endpointId).toBe('0x5a82d40e44ecd3ef0906e9e82c1a20f2f4ffe4f613ac70f999047496a9cd4635');
102
106
  });
103
107
 
104
- it(`it derives a template ID`, () => {
105
- const templateId = deriveTemplateId({
106
- airnode: '0x4E95C31894a89CdC4288669A6F294836948c862b',
107
- endpointId: '0x5a82d40e44ecd3ef0906e9e82c1a20f2f4ffe4f613ac70f999047496a9cd4635',
108
- encodedParameters: '0x1234',
109
- });
108
+ it(`it derives a template ID V0`, () => {
109
+ const templateId = deriveTemplateIdV0(
110
+ '0x4E95C31894a89CdC4288669A6F294836948c862b',
111
+ '0x5a82d40e44ecd3ef0906e9e82c1a20f2f4ffe4f613ac70f999047496a9cd4635',
112
+ '0x6466726f6d63455448'
113
+ );
114
+
115
+ expect(templateId).toBe('0x25ea8b12135e4b8d49960ef9e0f967b7c0ccad136b955fbb7fbeb76da27d60b0');
116
+ });
117
+
118
+ it('derives templateId for V1', () => {
119
+ const expectedTemplateIdV1 = deriveTemplateIdV1(
120
+ '0x2f3a3adf6daf5a3bb00ab83aa82262a6a84b59b0a89222386135330a1819ab48',
121
+ '0x6466726f6d63455448'
122
+ );
110
123
 
111
- expect(templateId).toBe('0x7655363f294273f84bcc7c47d79858cf46f21951deee92746d9f17a69ac0b0c0');
124
+ expect(expectedTemplateIdV1).toBe('0xe5d99287b5a870c3453bc0b42769c6f37cf4a3143890e9c34753181171fac842');
112
125
  });
113
126
 
114
127
  it('derives a beacon ID', () => {
@@ -1,6 +1,6 @@
1
1
  import { ethers } from 'ethers';
2
2
 
3
- import { addressSchema } from './schema';
3
+ import type { Address, Hex, Mnemonic } from './schema';
4
4
 
5
5
  export const PROTOCOL_IDS = {
6
6
  RRP: '1',
@@ -8,53 +8,23 @@ export const PROTOCOL_IDS = {
8
8
  RELAYED_RRP: '3',
9
9
  RELAYED_PSP: '4',
10
10
  AIRSEEKER: '5',
11
- };
11
+ } as const;
12
12
 
13
- /**
14
- * An interface that reflects the structure of a Template
15
- */
16
- export interface Template {
17
- airnode: string;
18
- encodedParameters: string;
19
- endpointId: string;
20
- }
13
+ export type ProtocolId = (typeof PROTOCOL_IDS)[keyof typeof PROTOCOL_IDS];
21
14
 
22
- /**
23
- * Derives a template ID from the input parameters
24
- *
25
- * @param airnode an Airnode address
26
- * @param encodedParameters encoded parameters, see the airnode/abi package's encode function
27
- * @param endpointId An endpointID (see deriveEndpointId)
28
- */
29
- export const deriveTemplateId = ({ airnode, encodedParameters, endpointId }: Template) =>
15
+ export const deriveTemplateIdV0 = (airnode: Address, endpointId: Hex, encodedParameters: Hex) =>
30
16
  ethers.utils.solidityKeccak256(['address', 'bytes32', 'bytes'], [airnode, endpointId, encodedParameters]);
31
17
 
32
- /**
33
- * Derives an endpoint ID
34
- *
35
- * @param oisTitle the OIS title
36
- * @param endpointName the endpoint name
37
- */
18
+ export const deriveTemplateIdV1 = (endpointId: Hex, encodedParameters: Hex) =>
19
+ ethers.utils.solidityKeccak256(['bytes32', 'bytes'], [endpointId, encodedParameters]);
20
+
38
21
  export const deriveEndpointId = (oisTitle: string, endpointName: string) =>
39
22
  ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(['string', 'string'], [oisTitle, endpointName]));
40
23
 
41
- /**
42
- * Derives an airnode address's xpub, required for allowing signed data consumers to verify authenticity
43
- *
44
- * @param airnodeMnemonic the airnode's mnemonic
45
- */
46
- export const deriveAirnodeXpub = (airnodeMnemonic: string) =>
24
+ export const deriveAirnodeXpub = (airnodeMnemonic: Mnemonic) =>
47
25
  ethers.utils.HDNode.fromMnemonic(airnodeMnemonic).derivePath("m/44'/60'/0'").neuter().extendedKey;
48
26
 
49
- /**
50
- * Derives a wallet path from a sponsor address, used for calculating a sponsor wallet.
51
- *
52
- * @param sponsorAddress an EVM-compatible address
53
- * @param protocolId an API application protocol ID
54
- */
55
- export function deriveWalletPathFromSponsorAddress(sponsorAddress: string, protocolId: string) {
56
- addressSchema.parse(sponsorAddress);
57
-
27
+ export function deriveWalletPathFromSponsorAddress(sponsorAddress: Address, protocolId: ProtocolId) {
58
28
  const sponsorAddressBN = ethers.BigNumber.from(sponsorAddress);
59
29
  const paths = [];
60
30
  for (let i = 0; i < 6; i++) {
@@ -64,53 +34,24 @@ export function deriveWalletPathFromSponsorAddress(sponsorAddress: string, proto
64
34
  return `${protocolId}/${paths.join('/')}`;
65
35
  }
66
36
 
67
- /**
68
- * Encodes/formats a string as a hex-encoded bytes32 string.
69
- *
70
- * @param input the input string
71
- */
72
37
  export const toBytes32String = (input: string) => ethers.utils.formatBytes32String(input);
73
38
 
74
- /**
75
- * Decodes a hex-encoded bytes32 string to a normal string.
76
- *
77
- * @param input the input hex string
78
- */
79
- export const fromBytes32String = (input: string) => ethers.utils.parseBytes32String(input);
39
+ export const fromBytes32String = (input: Hex) => ethers.utils.parseBytes32String(input);
80
40
 
81
- /**
82
- * Derives a sponsor wallet, given a mnemonic and dapiName.
83
- *
84
- * @param sponsorWalletMnemonic the sponsor wallet mnemonic
85
- * @param dapiName the dapi name
86
- */
87
- export const deriveSponsorWallet = (sponsorWalletMnemonic: string, dapiName: string) => {
41
+ export const deriveSponsorWallet = (airnodeMnemonic: Mnemonic, dapiName: string, protocolId: ProtocolId) => {
88
42
  // Take first 20 bytes of dapiName as sponsor address together with the "0x" prefix.
89
- const sponsorAddress = ethers.utils.getAddress(dapiName.slice(0, 42));
43
+ const sponsorAddress = ethers.utils.getAddress(dapiName.slice(0, 42)) as Address;
90
44
  const sponsorWallet = ethers.Wallet.fromMnemonic(
91
- sponsorWalletMnemonic,
92
- `m/44'/60'/0'/${
93
- (deriveWalletPathFromSponsorAddress(sponsorAddress, PROTOCOL_IDS.AIRSEEKER), PROTOCOL_IDS.AIRSEEKER)
94
- }`
45
+ airnodeMnemonic,
46
+ `m/44'/60'/0'/${deriveWalletPathFromSponsorAddress(sponsorAddress, protocolId)}`
95
47
  );
96
48
 
97
49
  return sponsorWallet;
98
50
  };
99
51
 
100
- /**
101
- * Derives the ID of a single beacon
102
- *
103
- * @param airnodeAddress the airnode address of the provider that supplies the data used to update this beacon
104
- * @param templateId the templateId of the template used to generate the data used to update this beacon
105
- */
106
- export const deriveBeaconId = (airnodeAddress: string, templateId: string) =>
52
+ export const deriveBeaconId = (airnodeAddress: Address, templateId: Hex) =>
107
53
  ethers.utils.solidityKeccak256(['address', 'bytes32'], [airnodeAddress, templateId]);
108
54
 
109
- /**
110
- * Derives the ID of a set of beacons.
111
- * By convention beacon IDs are sorted alphabetically - the ordering impacts the resulting hash.
112
- *
113
- * @param beaconIds an ordered array of beacon ids
114
- */
115
- export const deriveBeaconSetId = (beaconIds: string[]) =>
55
+ export const deriveBeaconSetId = (beaconIds: Hex[]) =>
56
+ // By convention beacon IDs are sorted alphabetically - the ordering impacts the resulting hash.
116
57
  ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(['bytes32[]'], [beaconIds]));
@@ -1,8 +1,10 @@
1
- import { addressSchema, idSchema } from './schema';
1
+ import { addressSchema, hexSchema, keccak256HashSchema, chainIdSchema, ethUnitsSchema, mnemonicSchema } from './schema';
2
2
 
3
- describe('schema', () => {
4
- it('validates a valid address', () => {
5
- expect(() => addressSchema.parse('0x8A45eac0267dD0803Fd957723EdE10693A076698')).not.toThrow();
3
+ describe('addressSchema', () => {
4
+ it('validates a valid address and returns its checksum', () => {
5
+ expect(addressSchema.parse('0x8a45eac0267dd0803fd957723ede10693a076698')).toBe(
6
+ '0x8A45eac0267dD0803Fd957723EdE10693A076698'
7
+ );
6
8
  });
7
9
 
8
10
  it('throws for an invalid address', () => {
@@ -10,14 +12,70 @@ describe('schema', () => {
10
12
  expect.objectContaining({ name: 'ZodError' })
11
13
  );
12
14
  });
15
+ });
13
16
 
17
+ describe('keccak256HashSchema', () => {
14
18
  it('validates a valid ID', () => {
15
- expect(() => idSchema.parse('0x3528e42b017a5fbf9d2993a2df04efc3ed474357575065a111b054ddf9de2acc')).not.toThrow();
19
+ expect(() =>
20
+ keccak256HashSchema.parse('0x3528e42b017a5fbf9d2993a2df04efc3ed474357575065a111b054ddf9de2acc')
21
+ ).not.toThrow();
16
22
  });
17
23
 
18
24
  it('throws for an invalid ID', () => {
19
- expect(() => idSchema.parse('0xA3528e42b017a5fbf9d2993a2df04efc3ed474357575065a111b054ddf9de2acc')).toThrow(
25
+ expect(() =>
26
+ keccak256HashSchema.parse('0xA3528e42b017a5fbf9d2993a2df04efc3ed474357575065a111b054ddf9de2acc')
27
+ ).toThrow(expect.objectContaining({ name: 'ZodError' }));
28
+ });
29
+ });
30
+
31
+ describe('hexSchema', () => {
32
+ it('validates a valid hex string', () => {
33
+ expect(() => hexSchema.parse('0x3528e42b017a5fbf9d2993a2df04efc3ed474357575065a111b054ddf9de2acc')).not.toThrow();
34
+ });
35
+
36
+ it('throws for an invalid hex string', () => {
37
+ expect(() => hexSchema.parse('3528e42b017a5fbf9d2993a2df04efc3ed474357575065a111b054ddf9de2acc')).toThrow(
20
38
  expect.objectContaining({ name: 'ZodError' })
21
39
  );
22
40
  });
23
41
  });
42
+
43
+ describe('chainIdSchema', () => {
44
+ it('validates a valid chain ID', () => {
45
+ expect(() => chainIdSchema.parse('1')).not.toThrow();
46
+ });
47
+
48
+ it('throws for an invalid chain ID', () => {
49
+ expect(() => chainIdSchema.parse('0')).toThrow(expect.objectContaining({ name: 'ZodError' }));
50
+ });
51
+ });
52
+
53
+ describe('ethUnitsSchema', () => {
54
+ it('validates a valid unit', () => {
55
+ expect(() => ethUnitsSchema.parse('wei')).not.toThrow();
56
+ expect(() => ethUnitsSchema.parse('kwei')).not.toThrow();
57
+ expect(() => ethUnitsSchema.parse('mwei')).not.toThrow();
58
+ expect(() => ethUnitsSchema.parse('gwei')).not.toThrow();
59
+ expect(() => ethUnitsSchema.parse('szabo')).not.toThrow();
60
+ expect(() => ethUnitsSchema.parse('finney')).not.toThrow();
61
+ expect(() => ethUnitsSchema.parse('ether')).not.toThrow();
62
+ });
63
+
64
+ it('throws for an invalid unit', () => {
65
+ expect(() => ethUnitsSchema.parse('wei2')).toThrow(expect.objectContaining({ name: 'ZodError' }));
66
+ });
67
+ });
68
+
69
+ describe('mnemonicSchema', () => {
70
+ it('validates a valid mnemonic', () => {
71
+ expect(() =>
72
+ mnemonicSchema.parse('destroy manual orange pole pioneer enemy detail lady cake bus shed visa')
73
+ ).not.toThrow();
74
+ });
75
+
76
+ it('throws for an invalid mnemonic', () => {
77
+ expect(() =>
78
+ mnemonicSchema.parse('destroy manual orange pole pioneer enemy detail lady cake bus shed WTF')
79
+ ).toThrow(expect.objectContaining({ name: 'ZodError' }));
80
+ });
81
+ });
@@ -1,14 +1,51 @@
1
+ import { goSync } from '@api3/promise-utils';
2
+ import { ethers } from 'ethers';
1
3
  import { z } from 'zod';
2
4
 
3
- /**
4
- * A Zod validation schema that represents an EVM-compatible address.
5
- */
6
- export const addressSchema = z.string().regex(/^0x[\dA-Fa-f]{40}$/, 'Must be a valid EVM address');
5
+ export const hexSchema = z.string().regex(/^0x[\dA-Fa-f]+$/, 'Must be a valid hex string');
7
6
 
8
- /**
9
- * A Zod validation schema that represents an EVM-compatible hash, which includes beacon IDs and template IDs.
10
- */
11
- export const idSchema = z.string().regex(/^0x[\dA-Fa-f]{64}$/, 'Must be a valid EVM hash');
7
+ export type Hex = `0x${string}`; // Not using z.infer<typeof hexSchema> because the inferred type is just `string`.
8
+
9
+ export const addressSchema = z.string().transform((value, ctx) => {
10
+ const goParseAddress = goSync(() => ethers.utils.getAddress(value));
11
+ if (!goParseAddress.success) {
12
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Invalid EVM address' });
13
+ return z.NEVER;
14
+ }
15
+
16
+ return goParseAddress.data as Hex;
17
+ });
12
18
 
13
19
  export type Address = z.infer<typeof addressSchema>;
14
- export type Id = z.infer<typeof idSchema>;
20
+
21
+ export const keccak256HashSchema = z
22
+ .string()
23
+ .regex(/^0x[\dA-Fa-f]{64}$/, 'Must be a valid EVM keccak256 hash')
24
+ .transform((val) => val as Hex);
25
+
26
+ export type Keccak256Hash = z.infer<typeof keccak256HashSchema>;
27
+
28
+ export const chainIdSchema = z
29
+ .string()
30
+ .regex(/^\d+$/, 'Must be a valid chain ID')
31
+ .refine((chainId) => Number(chainId) > 0, 'Chain ID must be greater than 0');
32
+
33
+ export type ChainId = z.infer<typeof chainIdSchema>;
34
+
35
+ export const ethUnitsSchema = z.union([
36
+ z.literal('wei'),
37
+ z.literal('kwei'),
38
+ z.literal('mwei'),
39
+ z.literal('gwei'),
40
+ z.literal('szabo'),
41
+ z.literal('finney'),
42
+ z.literal('ether'),
43
+ ]);
44
+
45
+ export type EthUnits = z.infer<typeof ethUnitsSchema>;
46
+
47
+ export const mnemonicSchema = z
48
+ .string()
49
+ .refine((mnemonic) => ethers.utils.isValidMnemonic(mnemonic), 'Invalid mnemonic');
50
+
51
+ export type Mnemonic = z.infer<typeof mnemonicSchema>;
@@ -127,6 +127,38 @@ describe(interpolateSecretsIntoConfig.name, () => {
127
127
  );
128
128
  });
129
129
 
130
+ it('allows parsing secrets without validating secret names', () => {
131
+ const rawSecrets = {
132
+ SECRET_A: 'secretValueA',
133
+ SECRET_B: 'secretValueB',
134
+ 'CANNOT-CONTAIN-HYPHEN': 'invalid',
135
+ lowercasedSecret: 'valid',
136
+ };
137
+
138
+ expect(() => interpolateSecretsIntoConfig(rawConfig, rawSecrets)).toThrow(
139
+ new ZodError([
140
+ {
141
+ validation: 'regex',
142
+ code: 'invalid_string',
143
+ message: 'Secret name is not a valid. Secret name must match /^[A-Z][\\dA-Z_]*$/',
144
+ path: ['CANNOT-CONTAIN-HYPHEN'],
145
+ },
146
+ {
147
+ validation: 'regex',
148
+ code: 'invalid_string',
149
+ message: 'Secret name is not a valid. Secret name must match /^[A-Z][\\dA-Z_]*$/',
150
+ path: ['lowercasedSecret'],
151
+ },
152
+ ])
153
+ );
154
+
155
+ expect(interpolateSecretsIntoConfig(rawConfig, rawSecrets, { validateSecretName: false })).toStrictEqual({
156
+ property: 'value',
157
+ secretA: 'secretValueA',
158
+ secretB: 'secretValueB',
159
+ });
160
+ });
161
+
130
162
  it('provides up to date README examples', () => {
131
163
  // Basic interpolation
132
164
  const basicInterpolationConfig = {
@@ -5,18 +5,16 @@ import reduce from 'lodash/reduce';
5
5
  import template from 'lodash/template';
6
6
  import { z } from 'zod';
7
7
 
8
- export const secretNamePattern = /^[A-Z][\dA-Z_]*$/;
8
+ export const strictSecretNamePattern = /^[A-Z][\dA-Z_]*$/;
9
9
 
10
- export const secretNameSchema = z
10
+ export const strictSecretNameSchema = z
11
11
  .string()
12
- .regex(secretNamePattern, `Secret name is not a valid. Secret name must match ${secretNamePattern.toString()}`);
13
-
14
- export const secretsSchema = z.record(secretNameSchema, z.string());
12
+ .regex(
13
+ strictSecretNamePattern,
14
+ `Secret name is not a valid. Secret name must match ${strictSecretNamePattern.toString()}`
15
+ );
15
16
 
16
- export const nonBlankSecretsSchema = z.record(
17
- secretNameSchema,
18
- z.string().min(1, { message: 'Secret cannot be blank' })
19
- );
17
+ export const nonBlankSecretValueSchema = z.string().min(1, { message: 'Secret cannot be blank' });
20
18
 
21
19
  export type Secrets = Record<string, string>;
22
20
 
@@ -34,7 +32,8 @@ const ES_MATCH_REGEXP = /(?<!\\)\${([^\\}]*(?:\\.[^\\}]*)*)}/g;
34
32
  const ESCAPED_ES_MATCH_REGEXP = /\\\\(\${([^\\}]*(?:\\.[^\\}]*)*)})/g;
35
33
 
36
34
  export interface InterpolationOptions {
37
- allowBlankSecretValue: boolean;
35
+ allowBlankSecretValue?: boolean;
36
+ validateSecretName?: boolean;
38
37
  }
39
38
 
40
39
  export type AnyObject = Record<string, unknown>;
@@ -42,10 +41,12 @@ export type AnyObject = Record<string, unknown>;
42
41
  export function interpolateSecretsIntoConfig<T = AnyObject>(
43
42
  config: T,
44
43
  secrets: unknown,
45
- options: InterpolationOptions = { allowBlankSecretValue: true }
44
+ options?: InterpolationOptions
46
45
  ) {
47
- const { allowBlankSecretValue } = options;
48
- const validatedSecrets = (allowBlankSecretValue ? secretsSchema : nonBlankSecretsSchema).parse(secrets);
46
+ const { allowBlankSecretValue = true, validateSecretName = true } = options ?? {};
47
+ const secretNameSchema = validateSecretName ? strictSecretNameSchema : z.string();
48
+ const secretValueSchema = allowBlankSecretValue ? z.string() : nonBlankSecretValueSchema;
49
+ const validatedSecrets = z.record(secretNameSchema, secretValueSchema).parse(secrets);
49
50
 
50
51
  const stringifiedSecrets = reduce(
51
52
  validatedSecrets,
@@ -1,2 +1,3 @@
1
1
  // NOTE: Only export modules which work in both Node.js and browser environments.
2
2
  export * from './blockchain-utilities';
3
+ export * from './http';