@codama/dynamic-instructions 0.2.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.
Files changed (39) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +97 -0
  3. package/dist/index.browser.cjs +752 -0
  4. package/dist/index.browser.cjs.map +1 -0
  5. package/dist/index.browser.mjs +741 -0
  6. package/dist/index.browser.mjs.map +1 -0
  7. package/dist/index.node.cjs +752 -0
  8. package/dist/index.node.cjs.map +1 -0
  9. package/dist/index.node.mjs +741 -0
  10. package/dist/index.node.mjs.map +1 -0
  11. package/dist/index.react-native.mjs +741 -0
  12. package/dist/index.react-native.mjs.map +1 -0
  13. package/dist/types/accounts/create-account-meta.d.ts +11 -0
  14. package/dist/types/accounts/create-account-meta.d.ts.map +1 -0
  15. package/dist/types/accounts/index.d.ts +3 -0
  16. package/dist/types/accounts/index.d.ts.map +1 -0
  17. package/dist/types/accounts/validate-accounts-input.d.ts +9 -0
  18. package/dist/types/accounts/validate-accounts-input.d.ts.map +1 -0
  19. package/dist/types/arguments/encode-instruction-arguments.d.ts +13 -0
  20. package/dist/types/arguments/encode-instruction-arguments.d.ts.map +1 -0
  21. package/dist/types/arguments/index.d.ts +4 -0
  22. package/dist/types/arguments/index.d.ts.map +1 -0
  23. package/dist/types/arguments/resolve-argument-from-custom-resolvers.d.ts +9 -0
  24. package/dist/types/arguments/resolve-argument-from-custom-resolvers.d.ts.map +1 -0
  25. package/dist/types/arguments/shared.d.ts +4 -0
  26. package/dist/types/arguments/shared.d.ts.map +1 -0
  27. package/dist/types/arguments/validate-arguments-input.d.ts +11 -0
  28. package/dist/types/arguments/validate-arguments-input.d.ts.map +1 -0
  29. package/dist/types/index.d.ts +6 -0
  30. package/dist/types/index.d.ts.map +1 -0
  31. package/dist/types/instructions-builder.d.ts +18 -0
  32. package/dist/types/instructions-builder.d.ts.map +1 -0
  33. package/dist/types/shared/types.d.ts +15 -0
  34. package/dist/types/shared/types.d.ts.map +1 -0
  35. package/dist/types/shared/util.d.ts +14 -0
  36. package/dist/types/shared/util.d.ts.map +1 -0
  37. package/dist/types/validators.d.ts +16 -0
  38. package/dist/types/validators.d.ts.map +1 -0
  39. package/package.json +76 -0
@@ -0,0 +1,741 @@
1
+ import { toAddress, resolveInstructionAccountAddress, isAddressConvertible, createDefaultValueEncoderVisitor, DEFAULT_VALUE_ENCODER_SUPPORTED_NODE_KINDS, createCodecInputTransformer, OPTIONAL_NODE_KINDS, isPublicKeyLike } from '@codama/dynamic-address-resolution';
2
+ export { isPublicKeyLike, toAddress } from '@codama/dynamic-address-resolution';
3
+ import { CodamaError, CODAMA_ERROR__UNEXPECTED_NODE_KIND, CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ARGUMENT_INPUT, CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE, CODAMA_ERROR__DYNAMIC_CLIENT__DEFAULT_VALUE_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_ENCODE_ARGUMENT, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT, CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ACCOUNT_ADDRESS, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER } from '@codama/errors';
4
+ import { AccountRole } from '@solana/instructions';
5
+ import { isNode, visitOrElse, camelCase } from 'codama';
6
+ import { assert, StructError, object, define, tuple, intersection, string, number, boolean, array, size } from 'superstruct';
7
+ import { address, isAddress } from '@solana/addresses';
8
+ import { mergeBytes, getUtf8Encoder } from '@solana/codecs';
9
+ import { getNodeCodec } from '@codama/dynamic-codecs';
10
+
11
+ // src/accounts/create-account-meta.ts
12
+
13
+ // src/shared/util.ts
14
+ function isObjectRecord(value) {
15
+ return typeof value === "object" && value !== null && Object.getPrototypeOf(value) === Object.prototype;
16
+ }
17
+ function getMaybeNodeKind(node) {
18
+ if (!isObjectRecord(node)) return null;
19
+ return node.kind ?? null;
20
+ }
21
+ function formatValueType(value) {
22
+ if (value === null) return "null";
23
+ if (Array.isArray(value)) return `array (length ${value.length})`;
24
+ if (value instanceof Uint8Array) return `Uint8Array (length ${value.length})`;
25
+ if (typeof value === "object") return "object";
26
+ return typeof value;
27
+ }
28
+ function safeStringify(value) {
29
+ try {
30
+ return JSON.stringify(value, (_key, v) => typeof v === "bigint" ? String(v) : v);
31
+ } catch {
32
+ return `non-serializable ${formatValueType(value)}`;
33
+ }
34
+ }
35
+
36
+ // src/accounts/create-account-meta.ts
37
+ async function createAccountMeta(root, ixNode, argumentsInput, accountsInput, signers = [], resolversInput) {
38
+ const programAddress = toAddress(root.program.publicKey);
39
+ const resolvedAccounts = await Promise.all(
40
+ ixNode.accounts.map(async (ixAccountNode) => {
41
+ const finalAddress = await resolveInstructionAccountAddress({
42
+ accountsInput,
43
+ argumentsInput,
44
+ ixAccountNode,
45
+ ixNode,
46
+ resolversInput,
47
+ root
48
+ });
49
+ const accountAddressInput = accountsInput?.[ixAccountNode.name];
50
+ const isAccountProvided = accountAddressInput !== void 0 && accountAddressInput !== null;
51
+ const role = ixAccountNode.isOptional && !isAccountProvided && ixNode.optionalAccountStrategy === "programId" && finalAddress === programAddress ? getReadonlyAccountRole(ixAccountNode, signers) : getAccountRole(ixAccountNode, signers);
52
+ return {
53
+ address: finalAddress,
54
+ optional: Boolean(ixAccountNode.isOptional),
55
+ role
56
+ };
57
+ })
58
+ );
59
+ const accountMetas = resolvedAccounts.filter((acc) => acc.address !== null).map((acc) => ({
60
+ address: acc.address,
61
+ role: acc.role
62
+ }));
63
+ for (const remainingNode of ixNode.remainingAccounts ?? []) {
64
+ if (!isNode(remainingNode.value, "argumentValueNode")) {
65
+ throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, {
66
+ expectedKinds: ["argumentValueNode"],
67
+ kind: remainingNode.value.kind,
68
+ node: remainingNode.value
69
+ });
70
+ }
71
+ const addresses = argumentsInput?.[remainingNode.value.name];
72
+ if (addresses === void 0) {
73
+ if (!remainingNode.isOptional) {
74
+ throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING, {
75
+ argumentName: remainingNode.value.name,
76
+ instructionName: ixNode.name
77
+ });
78
+ }
79
+ continue;
80
+ }
81
+ if (!Array.isArray(addresses)) {
82
+ throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ARGUMENT_INPUT, {
83
+ argumentName: remainingNode.value.name,
84
+ expectedType: "Address[]",
85
+ value: safeStringify(addresses)
86
+ });
87
+ }
88
+ const role = getRemainingAccountRole(remainingNode.isSigner, remainingNode.isWritable);
89
+ for (let i = 0; i < addresses.length; i++) {
90
+ const addr = addresses[i];
91
+ if (!isAddressConvertible(addr)) {
92
+ throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE, {
93
+ accountName: `${remainingNode.value.name}[${i}]`,
94
+ actualType: formatValueType(addr),
95
+ expectedType: "Address | PublicKey"
96
+ });
97
+ }
98
+ accountMetas.push({ address: toAddress(addr), role });
99
+ }
100
+ }
101
+ return accountMetas;
102
+ }
103
+ function getRemainingAccountRole(isSigner, isWritable) {
104
+ const signer = isSigner === true || isSigner === "either";
105
+ const writable = isWritable === true;
106
+ if (writable && signer) return AccountRole.WRITABLE_SIGNER;
107
+ if (writable) return AccountRole.WRITABLE;
108
+ if (signer) return AccountRole.READONLY_SIGNER;
109
+ return AccountRole.READONLY;
110
+ }
111
+ function getAccountRole(acc, signers) {
112
+ const isSigner = isSignerAccount(acc, signers ?? []);
113
+ if (acc.isWritable && isSigner) {
114
+ return AccountRole.WRITABLE_SIGNER;
115
+ }
116
+ if (acc.isWritable) {
117
+ return AccountRole.WRITABLE;
118
+ }
119
+ if (isSigner) {
120
+ return AccountRole.READONLY_SIGNER;
121
+ }
122
+ return AccountRole.READONLY;
123
+ }
124
+ function getReadonlyAccountRole(acc, signers) {
125
+ const isSigner = isSignerAccount(acc, signers ?? []);
126
+ return isSigner ? AccountRole.READONLY_SIGNER : AccountRole.READONLY;
127
+ }
128
+ function isSignerAccount(acc, signers) {
129
+ if (acc.isSigner === "either") {
130
+ return signers.includes(acc.name);
131
+ }
132
+ return acc.isSigner === true;
133
+ }
134
+ function createIxAccountsValidator(ixAccountNodes) {
135
+ const shape = ixAccountNodes.reduce((acc, node) => {
136
+ acc[node.name] = node.isOptional || node.defaultValue ? OptionalSolanaAddressValidator : SolanaAddressValidator;
137
+ return acc;
138
+ }, {});
139
+ return object(shape);
140
+ }
141
+ function createIxArgumentsValidator(ixNodeName, ixArgumentNodes, definedTypes) {
142
+ const shape = ixArgumentNodes.reduce((acc, argumentNode, index) => {
143
+ if (!argumentNode.type) {
144
+ throw new Error(`Argument ${argumentNode.name} of instruction ${ixNodeName} does not have a type`);
145
+ }
146
+ acc[argumentNode.name] = createValidatorForTypeNode(
147
+ `${ixNodeName}_${argumentNode.name}_${index}`,
148
+ argumentNode.type,
149
+ definedTypes
150
+ );
151
+ return acc;
152
+ }, {});
153
+ return object(shape);
154
+ }
155
+ function createValidatorForTypeNode(nodeName, node, definedTypes) {
156
+ if (!node) {
157
+ throw new Error(
158
+ `Node ${nodeName} is not defined. ${definedTypes.length} defined types were provided: ${definedTypes.map((t) => t.name).join(", ")}`
159
+ );
160
+ }
161
+ switch (node.kind) {
162
+ case "arrayTypeNode": {
163
+ return ArrayValidator(`${nodeName}_array`, node, definedTypes);
164
+ }
165
+ case "booleanTypeNode": {
166
+ return boolean();
167
+ }
168
+ case "numberTypeNode": {
169
+ const format = node.format;
170
+ if (format === "u64" || format === "u128" || format === "i64" || format === "i128") {
171
+ return NumberOrBigintValidator;
172
+ }
173
+ return number();
174
+ }
175
+ case "publicKeyTypeNode": {
176
+ return SolanaAddressValidator;
177
+ }
178
+ case "setTypeNode": {
179
+ return intersection([
180
+ UniqueItemsValidator,
181
+ ArrayValidator(`${nodeName}_set`, node, definedTypes)
182
+ ]);
183
+ }
184
+ case "stringTypeNode": {
185
+ return string();
186
+ }
187
+ case "fixedSizeTypeNode": {
188
+ if (node.type.kind === "stringTypeNode") {
189
+ return StringValidatorForFixedSize(node.size);
190
+ }
191
+ if (node.type.kind === "bytesTypeNode") {
192
+ return BytesWithSizeValidator(node.size);
193
+ }
194
+ return createValidatorForTypeNode(`${nodeName}_fixed_size`, node.type, definedTypes);
195
+ }
196
+ case "bytesTypeNode": {
197
+ return BytesLikeValidator;
198
+ }
199
+ case "dateTimeTypeNode": {
200
+ return createValidatorForTypeNode(`${nodeName}_date_time`, node.number, definedTypes);
201
+ }
202
+ case "definedTypeLinkNode": {
203
+ const definedType = definedTypes.find((d) => d.name === node.name);
204
+ if (!definedType) {
205
+ throw new Error(`Undefined type: ${node.name} ${node.kind}`);
206
+ }
207
+ return createValidatorForTypeNode(`${nodeName}_defined_type`, definedType.type, definedTypes);
208
+ }
209
+ case "mapTypeNode": {
210
+ const keyValidator = createValidatorForTypeNode(
211
+ `${nodeName}_map_key_${node.key.kind}`,
212
+ node.key,
213
+ definedTypes
214
+ );
215
+ const valueValidator = createValidatorForTypeNode(
216
+ `${nodeName}_map_value_${node.value.kind}`,
217
+ node.value,
218
+ definedTypes
219
+ );
220
+ const sizeValidator = MapCountValidator(node.count);
221
+ const keyValueValidator = KeyValueValidator(nodeName, keyValidator, valueValidator);
222
+ if (sizeValidator) {
223
+ return intersection([keyValueValidator, sizeValidator]);
224
+ }
225
+ return keyValueValidator;
226
+ }
227
+ case "structTypeNode": {
228
+ const structShape = node.fields.reduce((acc, field) => {
229
+ acc[field.name] = createValidatorForTypeNode(
230
+ `${nodeName}_struct_${field.name}`,
231
+ field.type,
232
+ definedTypes
233
+ );
234
+ return acc;
235
+ }, {});
236
+ return object(structShape);
237
+ }
238
+ case "tupleTypeNode": {
239
+ const validators = node.items.map(
240
+ (typeNode, index) => createValidatorForTypeNode(`${nodeName}_tuple${typeNode.kind}_${index}`, typeNode, definedTypes)
241
+ );
242
+ return tuple(validators);
243
+ }
244
+ case "zeroableOptionTypeNode": {
245
+ const innerValidator = createValidatorForTypeNode(
246
+ `${nodeName}_zeroable_option_item`,
247
+ node.item,
248
+ definedTypes
249
+ );
250
+ return ZeroableOptionValidator(`${nodeName}_zeroable_option`, innerValidator);
251
+ }
252
+ case "optionTypeNode": {
253
+ const SomeValueValidator = createValidatorForTypeNode(`${nodeName}_option_item`, node.item, definedTypes);
254
+ return OptionValueValidator(`${nodeName}_option`, SomeValueValidator);
255
+ }
256
+ case "remainderOptionTypeNode": {
257
+ const innerValidator = RemainderOptionTypeItemValidator(
258
+ `${nodeName}_remainder_option_item`,
259
+ node.item,
260
+ definedTypes
261
+ );
262
+ return OptionValueValidator(`${nodeName}_remainder_option`, innerValidator);
263
+ }
264
+ case "hiddenPrefixTypeNode":
265
+ case "hiddenSuffixTypeNode":
266
+ case "sentinelTypeNode":
267
+ case "postOffsetTypeNode":
268
+ case "preOffsetTypeNode":
269
+ case "sizePrefixTypeNode": {
270
+ return createValidatorForTypeNode(`${nodeName}_size_prefix`, node.type, definedTypes);
271
+ }
272
+ case "enumTypeNode": {
273
+ return EnumVariantValidator(nodeName, node.variants, definedTypes);
274
+ }
275
+ case "amountTypeNode": {
276
+ return AmountTypeValidator(nodeName);
277
+ }
278
+ case "solAmountTypeNode": {
279
+ return AmountTypeValidator(nodeName);
280
+ }
281
+ default: {
282
+ node["kind"];
283
+ throw new Error(`Validator for TypeNode "${nodeName}" kind: ${getMaybeNodeKind(node)} is not implemented!`);
284
+ }
285
+ }
286
+ }
287
+ function RemainderOptionTypeItemValidator(nodeName, itemNode, definedTypes) {
288
+ if (itemNode.kind === "fixedSizeTypeNode" && itemNode.type.kind === "stringTypeNode") {
289
+ return StringValidatorForFixedSize(itemNode.size);
290
+ }
291
+ if (itemNode.kind === "definedTypeLinkNode") {
292
+ const definedType = definedTypes.find((d) => d.name === itemNode.name);
293
+ if (definedType?.type.kind === "fixedSizeTypeNode" && definedType.type.type.kind === "stringTypeNode") {
294
+ return StringValidatorForFixedSize(definedType.type.size);
295
+ }
296
+ }
297
+ return createValidatorForTypeNode(nodeName, itemNode, definedTypes);
298
+ }
299
+ function StringValidatorForFixedSize(maxSize) {
300
+ return define(`StringForFixedSize_max_${maxSize}`, (value) => {
301
+ if (typeof value !== "string") {
302
+ return `Expected a string, received: ${formatValueType(value)}`;
303
+ }
304
+ const encoder = getUtf8Encoder();
305
+ const bytes = encoder.encode(value);
306
+ return bytes.length <= maxSize || `String exceeds max size: ${bytes.length} bytes (UTF-8), limit is ${maxSize} bytes`;
307
+ });
308
+ }
309
+ function EnumVariantValidator(nodeName, variants, definedTypes) {
310
+ const variantMap = new Map(variants.map((v) => [v.name, v]));
311
+ const variantNames = Array.from(variantMap.keys());
312
+ const variantValidators = /* @__PURE__ */ new Map();
313
+ for (const variant of variants) {
314
+ if (variant.kind === "enumStructVariantTypeNode") {
315
+ variantValidators.set(
316
+ variant.name,
317
+ createValidatorForTypeNode(`${nodeName}_${variant.name}`, variant.struct, definedTypes)
318
+ );
319
+ } else if (variant.kind === "enumTupleVariantTypeNode") {
320
+ variantValidators.set(
321
+ variant.name,
322
+ createValidatorForTypeNode(`${nodeName}_${variant.name}`, variant.tuple, definedTypes)
323
+ );
324
+ }
325
+ }
326
+ return define(`${nodeName}_EnumVariant`, (value) => {
327
+ if (typeof value === "string")
328
+ return variantMap.has(value) || `Invalid enum value "${value}". Expected one of: ${variantNames.join(", ")}`;
329
+ if (typeof value === "object" && value !== null && "__kind" in value) {
330
+ const kind = value["__kind"];
331
+ if (typeof kind !== "string") {
332
+ return `Expected __kind to be a string, received: ${formatValueType(kind)}`;
333
+ }
334
+ const variant = variantMap.get(kind);
335
+ if (!variant) {
336
+ return `Invalid enum variant "${kind}". Expected one of: ${variantNames.join(", ")}`;
337
+ }
338
+ if (variant.kind === "enumEmptyVariantTypeNode") {
339
+ return true;
340
+ }
341
+ const { __kind: _, ...rest } = value;
342
+ const payloadValidator = variantValidators.get(kind);
343
+ if (!payloadValidator) {
344
+ return true;
345
+ }
346
+ if (variant.kind === "enumStructVariantTypeNode") {
347
+ const [structError] = payloadValidator.validate(rest);
348
+ return structError ? formatErrorForEnumTypeNode(kind, structError) : true;
349
+ }
350
+ if (variant.kind === "enumTupleVariantTypeNode") {
351
+ const fields = rest.fields;
352
+ const [structError] = payloadValidator.validate(fields);
353
+ return structError ? formatErrorForEnumTypeNode(kind, structError) : true;
354
+ }
355
+ }
356
+ return `Expected an enum variant (string or object with __kind), received: ${formatValueType(value)}`;
357
+ });
358
+ }
359
+ function formatErrorForEnumTypeNode(enumVariantKind, error) {
360
+ const failures = error.failures();
361
+ const first = failures?.[0];
362
+ if (first) {
363
+ return `Enum variant "${enumVariantKind}" has invalid "${String(first.key)}"`;
364
+ }
365
+ return `Enum variant "${enumVariantKind}" has invalid payload`;
366
+ }
367
+ var SolanaAddressValidator = /* @__PURE__ */ define("SolanaAddress", (value) => {
368
+ if (typeof value === "string") {
369
+ return isAddress(value) || `Expected a valid Solana address (base58), received string: "${value}"`;
370
+ }
371
+ if (isPublicKeyLike(value)) {
372
+ return isAddress(value.toBase58()) || "Expected a valid Solana address, received an invalid PublicKey";
373
+ }
374
+ return `Expected a Solana address (base58 string or PublicKey), received: ${formatValueType(value)}`;
375
+ });
376
+ var OptionalSolanaAddressValidator = /* @__PURE__ */ define(
377
+ "OptionalSolanaAddress",
378
+ (value) => {
379
+ if (value === void 0 || value === null) return true;
380
+ const [error] = SolanaAddressValidator.validate(value);
381
+ if (!error) return true;
382
+ return error.failures()[0]?.message ?? "Expected a valid Solana address or null/undefined";
383
+ }
384
+ );
385
+ var NumberOrBigintValidator = /* @__PURE__ */ define("NumberOrBigint", (value) => {
386
+ if (typeof value === "number") {
387
+ return Number.isSafeInteger(value) || `Expected a safe integer, received unsafe number: ${value}`;
388
+ }
389
+ if (typeof value === "bigint") return true;
390
+ return `Expected a number or bigint, received: ${formatValueType(value)}`;
391
+ });
392
+ var BytesLikeValidator = /* @__PURE__ */ define("BytesLike", (value) => {
393
+ if (value instanceof Uint8Array) return true;
394
+ if (!Array.isArray(value)) {
395
+ return `Expected a Uint8Array or number[] (bytes 0-255), received: ${formatValueType(value)}`;
396
+ }
397
+ const invalidIndex = value.findIndex((n) => typeof n !== "number" || !Number.isInteger(n) || n < 0 || n > 255);
398
+ if (invalidIndex !== -1) {
399
+ return `Expected byte values (integers 0-255), invalid element at index ${invalidIndex}: ${String(value[invalidIndex])}`;
400
+ }
401
+ return true;
402
+ });
403
+ function BytesWithSizeValidator(exactSize) {
404
+ return define(`BytesWithSize_${exactSize}`, (value) => {
405
+ if (value instanceof Uint8Array) {
406
+ return value.length === exactSize || `Expected exactly ${exactSize} bytes, received ${value.length} bytes`;
407
+ }
408
+ if (!Array.isArray(value)) {
409
+ return `Expected a Uint8Array or number[] of exactly ${exactSize} bytes, received: ${formatValueType(value)}`;
410
+ }
411
+ if (value.length !== exactSize) {
412
+ return `Expected exactly ${exactSize} bytes, received ${value.length} elements`;
413
+ }
414
+ const invalidIndex = value.findIndex((n) => typeof n !== "number" || !Number.isInteger(n) || n < 0 || n > 255);
415
+ if (invalidIndex !== -1) {
416
+ return `Expected byte values (integers 0-255), invalid element at index ${invalidIndex}: ${String(value[invalidIndex])}`;
417
+ }
418
+ return true;
419
+ });
420
+ }
421
+ function OptionValueValidator(name, SomeValueValidator) {
422
+ return define(`${name}_OptionValueValidator`, (value) => {
423
+ if (value === null || value === void 0) return true;
424
+ const [error] = SomeValueValidator.validate(value);
425
+ if (!error) return true;
426
+ return error.failures()[0]?.message ?? "Invalid value for optional field";
427
+ });
428
+ }
429
+ function ZeroableOptionValidator(name, innerValidator) {
430
+ return define(name, (value) => {
431
+ if (value == null) return true;
432
+ const [error] = innerValidator.validate(value);
433
+ if (!error) return true;
434
+ return error.failures()[0]?.message ?? "Expected a valid value or null for zeroable option";
435
+ });
436
+ }
437
+ var UniqueItemsValidator = /* @__PURE__ */ define("UniqueItems", (value) => {
438
+ if (!Array.isArray(value)) {
439
+ return `Expected an array with unique items, received: ${formatValueType(value)}`;
440
+ }
441
+ const unique = /* @__PURE__ */ new Map();
442
+ for (let i = 0; i < value.length; i++) {
443
+ const key = safeStringify(value[i]);
444
+ const index = unique.get(key);
445
+ if (index !== void 0) {
446
+ return `Expected all items to be unique, found duplicate at indices ${index} and ${i}`;
447
+ }
448
+ unique.set(key, i);
449
+ }
450
+ return true;
451
+ });
452
+ function KeyValueValidator(name, KeyValidator, ValueValidator) {
453
+ return define(`${name}_KeyValueValidator`, (value) => {
454
+ if (typeof value !== "object" || value === null) {
455
+ return `Expected a map (object), received: ${formatValueType(value)}`;
456
+ }
457
+ const record = value;
458
+ const invalidKeys = [];
459
+ const invalidValues = [];
460
+ for (const key of Object.keys(record)) {
461
+ if (KeyValidator.validate(key)[0]) invalidKeys.push(key);
462
+ if (ValueValidator.validate(record[key])[0]) invalidValues.push(key);
463
+ }
464
+ if (!invalidKeys.length && !invalidValues.length) return true;
465
+ const parts = [];
466
+ if (invalidKeys.length) parts.push(`invalid keys: ${invalidKeys.join(", ")}`);
467
+ if (invalidValues.length) parts.push(`invalid values: ${invalidValues.join(", ")}`);
468
+ return `Map validation failed: ${parts.join("; ")}`;
469
+ });
470
+ }
471
+ function MapCountValidator(node) {
472
+ switch (node.kind) {
473
+ case "fixedCountNode":
474
+ return KeysLengthValidator(node.value);
475
+ case "remainderCountNode":
476
+ case "prefixedCountNode":
477
+ return null;
478
+ // the number of items is unknown or arbitrary, like vec![]
479
+ default:
480
+ throw new Error(`Unsupported map count type: ${getMaybeNodeKind(node)}`);
481
+ }
482
+ }
483
+ function KeysLengthValidator(count) {
484
+ return define(`KeysLengthValidator_len_${count}`, (value) => {
485
+ if (typeof value !== "object" || value === null) {
486
+ return `Expected a map with exactly ${count} entries, received: ${formatValueType(value)}`;
487
+ }
488
+ const actual = Object.keys(value).length;
489
+ return actual === count || `Expected exactly ${count} map entries, received ${actual}`;
490
+ });
491
+ }
492
+ function ArrayValidator(nodeName, node, definedTypes) {
493
+ const itemValidator = createValidatorForTypeNode(nodeName, node.item, definedTypes);
494
+ switch (node.count.kind) {
495
+ case "fixedCountNode": {
496
+ return size(array(itemValidator), node.count.value);
497
+ }
498
+ case "remainderCountNode":
499
+ case "prefixedCountNode": {
500
+ return array(itemValidator);
501
+ }
502
+ default: {
503
+ throw new Error(`Node: ${nodeName}. Unsupported array count type`);
504
+ }
505
+ }
506
+ }
507
+ function AmountTypeValidator(nodeName) {
508
+ return define(`AmountType_${nodeName}`, (value) => {
509
+ if (typeof value === "number") {
510
+ return Number.isSafeInteger(value) || `Expected a safe integer, received unsafe number: ${value}`;
511
+ }
512
+ if (typeof value === "bigint") {
513
+ return true;
514
+ }
515
+ return `Expected a number or bigint, received: ${formatValueType(value)}`;
516
+ });
517
+ }
518
+
519
+ // src/accounts/validate-accounts-input.ts
520
+ function createAccountsInputValidator(ixNode) {
521
+ const validator = ixNode.accounts.length ? createIxAccountsValidator(ixNode.accounts) : null;
522
+ return (accountsInput = {}) => {
523
+ if (!validator) return;
524
+ try {
525
+ assert(accountsInput, validator);
526
+ } catch (error) {
527
+ if (error instanceof StructError) {
528
+ const key = error.key;
529
+ const value = error.value;
530
+ if (value == null) {
531
+ throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING, {
532
+ accountName: camelCase(key),
533
+ instructionName: ixNode.name
534
+ });
535
+ } else {
536
+ throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ACCOUNT_ADDRESS, {
537
+ accountName: camelCase(key),
538
+ value: safeStringify(value)
539
+ });
540
+ }
541
+ }
542
+ throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT, {
543
+ cause: error,
544
+ message: "Unexpected validation error"
545
+ });
546
+ }
547
+ };
548
+ }
549
+ function isOmittedArgument(node) {
550
+ return node.defaultValueStrategy === "omitted";
551
+ }
552
+ function isOptionalArgument(ixArgumentNode, input) {
553
+ return OPTIONAL_NODE_KINDS.includes(ixArgumentNode.type.kind) && (input === null || input === void 0);
554
+ }
555
+
556
+ // src/arguments/encode-instruction-arguments.ts
557
+ function encodeInstructionArguments(root, ix, argumentsInput) {
558
+ const chunks = ix.arguments.map((ixArgumentNode) => {
559
+ const input = argumentsInput?.[ixArgumentNode.name];
560
+ const nodeCodec = getNodeCodec([root, root.program, ix, ixArgumentNode]);
561
+ if (isOmittedArgument(ixArgumentNode)) {
562
+ return encodeOmittedArgument(ix, ixArgumentNode, nodeCodec);
563
+ } else if (isOptionalArgument(ixArgumentNode, input)) {
564
+ return encodeOptionalArgument(ix, ixArgumentNode, nodeCodec);
565
+ } else {
566
+ return encodeRequiredArgument(root, ix, ixArgumentNode, input, nodeCodec);
567
+ }
568
+ });
569
+ return mergeBytes(chunks.map((chunk) => Uint8Array.from(chunk)));
570
+ }
571
+ function encodeOmittedArgument(ix, ixArgumentNode, nodeCodec) {
572
+ const defaultValue = ixArgumentNode.defaultValue;
573
+ if (defaultValue === void 0) {
574
+ throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__DEFAULT_VALUE_MISSING, {
575
+ argumentName: ixArgumentNode.name,
576
+ instructionName: ix.name
577
+ });
578
+ }
579
+ const visitor = createDefaultValueEncoderVisitor(nodeCodec);
580
+ return visitOrElse(defaultValue, visitor, (node) => {
581
+ throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, {
582
+ expectedKinds: [...DEFAULT_VALUE_ENCODER_SUPPORTED_NODE_KINDS],
583
+ kind: node.kind,
584
+ node
585
+ });
586
+ });
587
+ }
588
+ function encodeOptionalArgument(ix, ixArgumentNode, nodeCodec) {
589
+ try {
590
+ return nodeCodec.encode(null);
591
+ } catch (error) {
592
+ throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_ENCODE_ARGUMENT, {
593
+ argumentName: ixArgumentNode.name,
594
+ cause: error,
595
+ instructionName: ix.name
596
+ });
597
+ }
598
+ }
599
+ function encodeRequiredArgument(root, ix, ixArgumentNode, input, nodeCodec) {
600
+ if (input === void 0) {
601
+ throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING, {
602
+ argumentName: ixArgumentNode.name,
603
+ instructionName: ix.name
604
+ });
605
+ }
606
+ const transformer = createCodecInputTransformer(ixArgumentNode.type, root, {
607
+ bytesEncoding: "base16"
608
+ });
609
+ const transformedInput = transformer(input);
610
+ try {
611
+ return nodeCodec.encode(transformedInput);
612
+ } catch (error) {
613
+ throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_ENCODE_ARGUMENT, {
614
+ argumentName: ixArgumentNode.name,
615
+ cause: error,
616
+ instructionName: ix.name
617
+ });
618
+ }
619
+ }
620
+ function createArgumentsInputValidator(root, ixNode) {
621
+ const requiredArguments = ixNode.arguments.filter((arg) => arg?.defaultValueStrategy !== "omitted");
622
+ const validator = requiredArguments.length ? createIxArgumentsValidator(ixNode.name, requiredArguments, root.program.definedTypes) : null;
623
+ return (argumentsInput = {}) => {
624
+ validateOmittedArguments(ixNode, argumentsInput);
625
+ if (!validator) return;
626
+ const filteredInput = filterRemainingAccountArguments(ixNode, argumentsInput);
627
+ try {
628
+ assert(filteredInput, validator);
629
+ } catch (error) {
630
+ if (!(error instanceof StructError)) {
631
+ throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT, {
632
+ cause: error,
633
+ message: "Unexpected validation error"
634
+ });
635
+ }
636
+ const formattedMessage = error.failures().map((failure) => {
637
+ const fieldPath = formatFailurePath(failure);
638
+ const value = formatFailureValue(failure.value);
639
+ return `Invalid argument "${fieldPath}", value: ${value}. ${failure.message}
640
+ `;
641
+ });
642
+ throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT, {
643
+ cause: error,
644
+ message: formattedMessage.join("")
645
+ });
646
+ }
647
+ };
648
+ }
649
+ function formatFailurePath(failure) {
650
+ const path = failure.path;
651
+ if (!path || path.length === 0) return String(failure.key ?? "");
652
+ return path.map((segment, i) => {
653
+ if (typeof segment === "number") {
654
+ return `[${segment}]`;
655
+ }
656
+ return `${i === 0 ? "" : "."}${String(segment)}`;
657
+ }).join("");
658
+ }
659
+ var MAX_VALUE_LENGTH = 120;
660
+ function formatFailureValue(value) {
661
+ const raw = typeof value === "object" ? safeStringify(value) : String(value);
662
+ return raw.length > MAX_VALUE_LENGTH ? `${raw.slice(0, MAX_VALUE_LENGTH)}...` : raw;
663
+ }
664
+ function validateOmittedArguments(ixNode, argumentsInput = {}) {
665
+ ixNode.arguments.filter(isOmittedArgument).forEach((ixArgumentNode) => {
666
+ if (Object.hasOwn(argumentsInput, ixArgumentNode.name)) {
667
+ throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT, {
668
+ message: "Omitted argument must not be provided"
669
+ });
670
+ }
671
+ });
672
+ }
673
+ function getRemainingAccountArgNames(ixNode) {
674
+ return (ixNode.remainingAccounts ?? []).filter((node) => node.value.kind === "argumentValueNode").map((node) => node.value.name);
675
+ }
676
+ function filterRemainingAccountArguments(ixNode, argumentsInput) {
677
+ const remainingAccountArgNames = getRemainingAccountArgNames(ixNode);
678
+ if (!remainingAccountArgNames.length) {
679
+ return argumentsInput;
680
+ }
681
+ const remainingAccountArgNamesSet = new Set(remainingAccountArgNames);
682
+ return Object.fromEntries(Object.entries(argumentsInput).filter(([key]) => !remainingAccountArgNamesSet.has(key)));
683
+ }
684
+ async function resolveArgumentDefaultsFromCustomResolvers(ixNode, argumentsInput, accountsInput, resolversInput) {
685
+ const resolvedArgumentsInput = { ...argumentsInput };
686
+ const allArguments = [...ixNode.arguments, ...ixNode.extraArguments ?? []];
687
+ for (const argumentNode of allArguments) {
688
+ if (resolvedArgumentsInput[argumentNode.name] !== void 0) continue;
689
+ if (isOmittedArgument(argumentNode)) continue;
690
+ if (!isNode(argumentNode.defaultValue, "resolverValueNode")) continue;
691
+ const resolverFn = resolversInput?.[argumentNode.defaultValue.name];
692
+ if (!resolverFn) continue;
693
+ try {
694
+ resolvedArgumentsInput[argumentNode.name] = await resolverFn(
695
+ resolvedArgumentsInput,
696
+ accountsInput ?? {}
697
+ );
698
+ } catch (error) {
699
+ throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER, {
700
+ cause: error,
701
+ resolverName: argumentNode.defaultValue.name,
702
+ targetKind: "instructionArgumentNode",
703
+ targetName: argumentNode.name
704
+ });
705
+ }
706
+ }
707
+ return resolvedArgumentsInput;
708
+ }
709
+ function createInstructionsBuilder(root, ixNode) {
710
+ const programAddress = address(root.program.publicKey);
711
+ const validateArguments = createArgumentsInputValidator(root, ixNode);
712
+ const validateAccounts = createAccountsInputValidator(ixNode);
713
+ return async (argumentsInput, accountsInput, signers, resolversInput) => {
714
+ validateArguments(argumentsInput);
715
+ validateAccounts(accountsInput);
716
+ const enrichedArgumentsInput = await resolveArgumentDefaultsFromCustomResolvers(
717
+ ixNode,
718
+ argumentsInput,
719
+ accountsInput,
720
+ resolversInput
721
+ );
722
+ const argumentsData = encodeInstructionArguments(root, ixNode, enrichedArgumentsInput);
723
+ const accountsData = await createAccountMeta(
724
+ root,
725
+ ixNode,
726
+ enrichedArgumentsInput,
727
+ accountsInput,
728
+ signers,
729
+ resolversInput
730
+ );
731
+ return {
732
+ accounts: accountsData,
733
+ data: argumentsData,
734
+ programAddress
735
+ };
736
+ };
737
+ }
738
+
739
+ export { createAccountMeta, createInstructionsBuilder, encodeInstructionArguments };
740
+ //# sourceMappingURL=index.browser.mjs.map
741
+ //# sourceMappingURL=index.browser.mjs.map