@xo-cash/utils 0.0.1-development.13987669945

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/dist/index.mjs ADDED
@@ -0,0 +1,840 @@
1
+ import { binToHex, hexToBin, sha256, utf8ToBin } from "@bitauth/libauth";
2
+ import { z } from "zod";
3
+
4
+ //#region source/extended-json.ts
5
+ /**
6
+ * Matches a bigint encoded in Extended JSON format: `<bigint: 123n>`.
7
+ */
8
+ const EXTENDED_JSON_BIGINT_PATTERN = /^<bigint: (?<bigint>[+-]?[0-9]+)n>$/u;
9
+ /**
10
+ * Matches a Uint8Array encoded in Extended JSON format: `<uint8array: abcd>`.
11
+ */
12
+ const EXTENDED_JSON_UINT8ARRAY_PATTERN = /^<uint8array: (?<hex>[0-9a-f]*)>$/u;
13
+ /**
14
+ * The JSON replacer that encodes `bigint` and `Uint8Array` values in Extended JSON format,
15
+ * compatible with the format expected by `extendedJsonReviver`.
16
+ *
17
+ * - BigInts are encoded as `<bigint: 123n>`.
18
+ * - Uint8Arrays are encoded as `<uint8array: abcd>`.
19
+ * All other values pass through unchanged and if any incompatible type is encountered, an error is thrown.
20
+ *
21
+ * Note: To use this function, pass it as the second argument to `JSON.stringify` when serializing data.
22
+ *
23
+ * Note to developers: Libauth's `stringify` is the replacer. It also serializes functions and symbols,
24
+ * which we do not support. Passing it would let templates include those values, but revival would then fail.
25
+ * This module provides a dedicated replacer and reviver so serialization and deserialization stay aligned.
26
+ *
27
+ * @param _propertyKey The property key being serialized, required by the `JSON.stringify` replacer but not used here.
28
+ * @param value The value to encode or pass through unchanged.
29
+ * @returns The encoded string
30
+ */
31
+ const extendedJsonReplacer = (_propertyKey, value) => {
32
+ if (value instanceof Uint8Array) return `<uint8array: ${binToHex(value)}>`;
33
+ if (typeof value === "bigint") return `<bigint: ${value.toString()}n>`;
34
+ return value;
35
+ };
36
+ /**
37
+ * The JSON reviver that reconstructs `bigint` and `Uint8Array` values encoded by `extendedJsonReplacer`.
38
+ *
39
+ * Note: To use this function, pass it as the second argument to `JSON.parse` when deserializing data.
40
+ *
41
+ * @param _propertyKey The property key being deserialized, required by the `JSON.parse` reviver but not used here.
42
+ * @param value The value to reconstruct or pass through unchanged.
43
+ * @returns The reconstructed value
44
+ */
45
+ const extendedJsonReviver = (_propertyKey, value) => {
46
+ if (typeof value !== "string") return value;
47
+ const bigintPatternMatch = value.match(EXTENDED_JSON_BIGINT_PATTERN);
48
+ if (bigintPatternMatch) return BigInt(bigintPatternMatch.groups.bigint);
49
+ const uint8arrayPatternMatch = value.match(EXTENDED_JSON_UINT8ARRAY_PATTERN);
50
+ if (uint8arrayPatternMatch) return hexToBin(uint8arrayPatternMatch.groups.hex);
51
+ return value;
52
+ };
53
+
54
+ //#endregion
55
+ //#region source/script.ts
56
+ /**
57
+ * Converts a script to a scriptHash.
58
+ * @param {Uint8Array} script - The script to convert.
59
+ * @returns {string} The scriptHash as a reversed hex string.
60
+ */
61
+ const scriptToScriptHash = (script) => {
62
+ return binToHex(sha256.hash(script).reverse());
63
+ };
64
+
65
+ //#endregion
66
+ //#region source/template/errors.ts
67
+ /**
68
+ * Formats the Zod validation failures into a single string with one line each: "- <field>: <message>" and top level failures
69
+ * with no field path show as "(root)" for better readability.
70
+ *
71
+ * @param issues The Zod validation failures to format.
72
+ * @returns A human readable error string for better debugging.
73
+ */
74
+ const buildErrorDescription = (issues) => {
75
+ const lines = [];
76
+ for (const issue of issues) {
77
+ const issuePath = issue.path.length > 0 ? issue.path.join(".") : "(root)";
78
+ const issueMessage = issue.message.startsWith("Invalid input: ") ? issue.message.slice(15) : issue.message;
79
+ lines.push(`- ${issuePath}: ${issueMessage}`);
80
+ }
81
+ return `\n${lines.join("\n")}`;
82
+ };
83
+ /**
84
+ * Thrown when the provided template does not satisfy the XOTemplate schema.
85
+ */
86
+ var TemplateInvalidError = class extends Error {
87
+ constructor(details) {
88
+ const message = `Template invalid: ${details}`;
89
+ super(message);
90
+ this.name = "TemplateInvalidError";
91
+ }
92
+ };
93
+ /**
94
+ * Thrown when a string passed to `deserializeTemplate` cannot be parsed as JSON.
95
+ */
96
+ var TemplateJsonMalformedError = class extends Error {
97
+ constructor(reason) {
98
+ super(`Template JSON malformed, expected a valid JSON string: ${reason}`);
99
+ this.name = "TemplateJsonMalformedError";
100
+ }
101
+ };
102
+ /**
103
+ * Thrown when `serializeTemplate` fails to produce a JSON string from the template.
104
+ */
105
+ var TemplateSerializationFailedError = class extends Error {
106
+ constructor(reason) {
107
+ super(`Template serialization failed: ${reason}`);
108
+ this.name = "TemplateSerializationFailedError";
109
+ }
110
+ };
111
+
112
+ //#endregion
113
+ //#region source/template/serialization.ts
114
+ /**
115
+ * Serializes an XOTemplate to a JSON string. Encodes `bigint` and `Uint8Array` fields in
116
+ * Extended JSON format so they can be reconstructed by `deserializeTemplate`.
117
+ *
118
+ * @param template The template to serialize.
119
+ * @returns A JSON string representation of the template.
120
+ * @throws {TemplateSerializationFailedError} If the template cannot be serialized to JSON.
121
+ */
122
+ const serializeTemplate = (template) => {
123
+ try {
124
+ return JSON.stringify(template, extendedJsonReplacer);
125
+ } catch (serializationError) {
126
+ throw new TemplateSerializationFailedError(serializationError instanceof Error ? serializationError.message : "unknown error while serializing template");
127
+ }
128
+ };
129
+ /**
130
+ * Deserializes a JSON string back into an XOTemplate object. Restores `bigint` and
131
+ * `Uint8Array` fields encoded in Extended JSON format by `serializeTemplate`.
132
+ *
133
+ * @param serializedTemplate - A JSON string of an XOTemplate object.
134
+ * @returns The reconstructed XOTemplate object.
135
+ * @throws {TemplateJsonMalformedError} If the serialized template is not valid JSON.
136
+ */
137
+ const deserializeTemplate = (serializedTemplate) => {
138
+ try {
139
+ return JSON.parse(serializedTemplate, extendedJsonReviver);
140
+ } catch (parsingError) {
141
+ throw new TemplateJsonMalformedError(parsingError instanceof Error ? parsingError.message : "unknown error while deserializing template");
142
+ }
143
+ };
144
+
145
+ //#endregion
146
+ //#region source/template/identifier.ts
147
+ /**
148
+ * Generates a deterministic template identifier by hashing the template.
149
+ *
150
+ * Note: This expects a template that has been validated by `parseTemplate`.
151
+ *
152
+ * @param template - The template to generate an identifier for.
153
+ * @returns The sha256 hex identifier for the template.
154
+ */
155
+ const generateTemplateIdentifier = (template) => {
156
+ const serializedTemplate = serializeTemplate(template);
157
+ return binToHex(sha256.hash(utf8ToBin(serializedTemplate)));
158
+ };
159
+
160
+ //#endregion
161
+ //#region source/template/schemas.ts
162
+ /**
163
+ * Validation schema for a BCH VM version identifier. Defines the set of known BCH VM versions
164
+ * that XO templates declare support for.
165
+ *
166
+ * Zod's `z.enum` requires the exact values to be defined inline because it needs to know each
167
+ * specific value at compile time to validate against them. Defining the versions here directly
168
+ * satisfies that requirement and allows `z.array(bchVmVersionSchema)` to be used elsewhere
169
+ *
170
+ * ```
171
+ * {
172
+ * "supported": [ "BCH_2025_05" ] ← each value
173
+ * }
174
+ * ```
175
+ */
176
+ const bchVmVersionSchema = z.enum([
177
+ "BCH_2020_05",
178
+ "BCH_2021_05",
179
+ "BCH_2022_05",
180
+ "BCH_2023_05",
181
+ "BCH_2024_05",
182
+ "BCH_2025_05",
183
+ "BCH_2026_05"
184
+ ]);
185
+ /**
186
+ * Validation schema for the capability of a non-fungible token. Defines the three capability
187
+ * types supported on BCH: minting tokens can create new NFTs, mutable tokens can update their
188
+ * commitment, and none tokens cannot be changed after creation.
189
+ *
190
+ * ```
191
+ * {
192
+ * "inputs|outputs": {
193
+ * "[id]": {
194
+ * "token": {
195
+ * "nft": {
196
+ * "capability": "minting" ← this schema
197
+ * }
198
+ * }
199
+ * }
200
+ * }
201
+ * }
202
+ * ```
203
+ */
204
+ const xoTemplateNftCapabilitySchema = z.enum([
205
+ "minting",
206
+ "mutable",
207
+ "none"
208
+ ]);
209
+ /**
210
+ * Validation schema for a BCH locking script type. Defines the standard locking script types
211
+ * supported on BCH.
212
+ *
213
+ * ```
214
+ * {
215
+ * "lockingScripts": {
216
+ * "[id]": {
217
+ * "lockingType": "p2pkh" ← this schema
218
+ * }
219
+ * }
220
+ * }
221
+ * ```
222
+ */
223
+ const xoTemplateLockingTypeSchema = z.enum([
224
+ "p2s",
225
+ "p2pkh",
226
+ "p2sh"
227
+ ]);
228
+ /**
229
+ * Validation schema for a primitive type identifier. Defines the set of primitive types
230
+ * that can be declared in an XO template. Used by constants, variables, and data fields.
231
+ */
232
+ const xoTemplatePrimitiveTypeSchema = z.enum([
233
+ "boolean",
234
+ "bytes",
235
+ "integer",
236
+ "bigint",
237
+ "string",
238
+ "private_key",
239
+ "public_key"
240
+ ]);
241
+ /**
242
+ * Validation schema for byte array fields i.e. Uint8Array instance.
243
+ */
244
+ const uint8ArraySchema = z.instanceof(Uint8Array).describe("A sequence of unsigned 8-bit integers expressed as a Uint8Array.");
245
+ /**
246
+ * Validation schema for the Satoshis type i.e. bigint.
247
+ */
248
+ const satoshisSchema = z.bigint().describe("A satoshi amount expressed as a bigint.");
249
+ /** Maximum character length for name fields on view properties. */
250
+ const VIEW_PROPERTIES_NAME_MAX_LENGTH = 200;
251
+ /** Maximum character length for description fields on view properties. */
252
+ const VIEW_PROPERTIES_DESCRIPTION_MAX_LENGTH = 5e3;
253
+ /** Maximum character length for icon fields on view properties. */
254
+ const VIEW_PROPERTIES_ICON_MAX_LENGTH = 50;
255
+ /**
256
+ * Validation schema for view properties shared across many template elements i.e. name, description, icon.
257
+ * Extended by most other schemas in this file.
258
+ */
259
+ const xoTemplateViewPropertiesSchema = z.object({
260
+ name: z.string().max(VIEW_PROPERTIES_NAME_MAX_LENGTH).describe("A short human-readable label for this element."),
261
+ description: z.string().max(VIEW_PROPERTIES_DESCRIPTION_MAX_LENGTH).describe("A human-readable explanation of what this element does and when it is relevant."),
262
+ icon: z.string().max(VIEW_PROPERTIES_ICON_MAX_LENGTH).optional().describe("An optional icon identifier or URL for this element.")
263
+ }).strict();
264
+ /**
265
+ * Validation schema for the base intent structure. Describes the common data parameters shared
266
+ * by all intent types regardless of what they target.
267
+ *
268
+ * An optional templateIdentifier allows the intent to reference a target defined in a different
269
+ * template, enabling cross-template interaction.
270
+ *
271
+ * Extended by: xoTemplateActionIntentSchema, xoTemplateOutputIntentSchema,
272
+ * xoTemplateLockingScriptIntentSchema.
273
+ */
274
+ const xoTemplateIntentSchema = z.object({
275
+ templateIdentifier: z.string().optional().describe("Optional identifier for the template used in this intent. If not provided, uses the current template."),
276
+ role: z.string().optional().describe("Optional identifier for the role used in this intent."),
277
+ generate: z.array(z.string()).optional().describe("Identifiers for items to generate when this intent is resolved, e.g. keys or secrets."),
278
+ variables: z.array(z.record(z.string(), z.unknown())).optional().describe("Variable values to apply when this intent is resolved."),
279
+ constants: z.array(z.record(z.string(), z.unknown())).optional().describe("Constant values to apply when this intent is resolved."),
280
+ secrets: z.array(z.record(z.string(), z.unknown())).optional().describe("Secret values to apply when this intent is resolved.")
281
+ }).strict();
282
+ /**
283
+ * Validation schema for an action intent. Extends the base intent structure with an action
284
+ * identifier. Used in locking script action lists and in the template's start array.
285
+ *
286
+ * ```
287
+ * {
288
+ * "start": [
289
+ * { "action": "..." } ← this schema
290
+ * ],
291
+ * "lockingScripts": {
292
+ * "[id]": {
293
+ * "actions": [
294
+ * { "action": "..." } ← this schema
295
+ * ],
296
+ * "roles": {
297
+ * "[roleId]": {
298
+ * "actions": [
299
+ * { "action": "..." } ← this schema
300
+ * ]
301
+ * }
302
+ * }
303
+ * }
304
+ * }
305
+ * }
306
+ * ```
307
+ */
308
+ const xoTemplateActionIntentSchema = xoTemplateIntentSchema.extend({ action: z.string().describe("The identifier for the intended action.") }).strict();
309
+ /**
310
+ * Validation schema for an output intent. Extends the base intent structure with an output
311
+ * identifier. Used in the template's defaults block.
312
+ *
313
+ * ```
314
+ * {
315
+ * "defaults": {
316
+ * "change": { "output": "..." } ← this schema
317
+ * }
318
+ * }
319
+ * ```
320
+ */
321
+ const xoTemplateOutputIntentSchema = xoTemplateIntentSchema.extend({ output: z.string().describe("The identifier for the intended output.") }).strict();
322
+ /**
323
+ * Validation schema for a locking script intent. Extends the base intent structure with
324
+ * a locking script identifier.
325
+ *
326
+ * @todo The location of this schema in the template JSON is not yet determined.
327
+ */
328
+ const xoTemplateLockingScriptIntentSchema = xoTemplateIntentSchema.extend({ lockingScript: z.string().describe("The identifier for the intended locking script.") }).strict();
329
+ /**
330
+ * Validation schema for the slot count configuration on a role requirement. Declares how many
331
+ * participants of a given role are needed. min sets the lower bound and max sets the upper bound.
332
+ * When max is absent, there is no upper limit.
333
+ *
334
+ * ```
335
+ * {
336
+ * "actions": {
337
+ * "[id]": {
338
+ * "requirements": {
339
+ * "participants": [
340
+ * { "slots": { "min": 1, "max": 1 } } ← this schema
341
+ * ]
342
+ * }
343
+ * }
344
+ * }
345
+ * }
346
+ * ```
347
+ */
348
+ const xoTemplateRoleSlotsRequirementsSchema = z.object({
349
+ min: z.number().describe("Minimum number of participants required for this role."),
350
+ max: z.number().optional().describe("Maximum number of participants allowed for this role. Undefined means unlimited.")
351
+ }).strict();
352
+ /**
353
+ * Validation schema for the capability requirements declared on a role within an action.
354
+ * Describes what data, secrets, or state the role is responsible for providing when participating in an action.
355
+ *
356
+ * ```
357
+ * {
358
+ * "actions": {
359
+ * "[id]": {
360
+ * "roles": {
361
+ * "[roleId]": {
362
+ * "requirements": { "variables": [], "secrets": [] } ← this schema
363
+ * }
364
+ * }
365
+ * }
366
+ * }
367
+ * }
368
+ * ```
369
+ */
370
+ const xoTemplateActionRoleRequirementsSchema = z.object({
371
+ variables: z.array(z.string()).optional().describe("List of variable identifiers required for this role."),
372
+ secrets: z.array(z.string()).optional().describe("List of secret identifiers required for this role.")
373
+ }).strict();
374
+ /**
375
+ * Validation schema for a role-specific definition within an action.
376
+ * All view properties are optional.
377
+ *
378
+ * ```
379
+ * {
380
+ * "actions": {
381
+ * "[id]": {
382
+ * "roles": {
383
+ * "[roleId]": { } ← this schema
384
+ * }
385
+ * }
386
+ * }
387
+ * }
388
+ * ```
389
+ */
390
+ const xoTemplateActionRoleSchema = xoTemplateViewPropertiesSchema.partial().extend({
391
+ generate: z.array(z.string()).optional().describe("Identifiers for data items that should be generated for this role when participating in the action."),
392
+ requirements: xoTemplateActionRoleRequirementsSchema.optional().describe("The requirements for this role within this action.")
393
+ }).strict();
394
+ /**
395
+ * Validation schema for a role participation requirement in an action's requirements block.
396
+ *
397
+ * ```
398
+ * {
399
+ * "actions": {
400
+ * "[id]": {
401
+ * "requirements": {
402
+ * "participants": [
403
+ * { "role": "...", "slots": { } } ← this schema
404
+ * ]
405
+ * }
406
+ * }
407
+ * }
408
+ * }
409
+ * ```
410
+ */
411
+ const xoTemplateRoleSlotSchema = z.object({
412
+ role: z.string().describe("The role identifier that this requirement applies to."),
413
+ slots: xoTemplateRoleSlotsRequirementsSchema.describe("Slot configuration specifying how many participants of this role are required.")
414
+ }).strict();
415
+ /**
416
+ * Validation schema for the requirements of an action.
417
+ *
418
+ * ```
419
+ * {
420
+ * "actions": {
421
+ * "[id]": {
422
+ * "requirements": { "participants": [], "secrets": [] } ← this schema
423
+ * }
424
+ * }
425
+ * }
426
+ * ```
427
+ */
428
+ const xoTemplateActionRequirementsSchema = z.object({
429
+ participants: z.array(xoTemplateRoleSlotSchema).optional().describe("The participants required for this action."),
430
+ secrets: z.array(z.string()).optional().describe("The secrets required for this action.")
431
+ }).strict();
432
+ /**
433
+ * Validation schema for an action definition.
434
+ *
435
+ * ```
436
+ * {
437
+ * "actions": {
438
+ * "[id]": { } ← this schema
439
+ * }
440
+ * }
441
+ * ```
442
+ */
443
+ const xoTemplateActionSchema = xoTemplateViewPropertiesSchema.extend({
444
+ roles: z.record(z.string(), xoTemplateActionRoleSchema).optional().describe("Specific context for each role participating in this action."),
445
+ requirements: xoTemplateActionRequirementsSchema.optional().describe("The requirements for this action."),
446
+ conditions: z.array(z.string()).optional().describe("Conditions that must be met for this action to be available."),
447
+ transaction: z.string().optional().describe("The identifier of the transaction this action produces, referencing an entry in the template's transactions."),
448
+ data: z.string().optional().describe("The identifier of the data field this action produces, referencing an entry in the template's data.")
449
+ }).strict();
450
+ /**
451
+ * Validation schema for the non-fungible token configuration within a token field.
452
+ *
453
+ * ```
454
+ * {
455
+ * "inputs|outputs": {
456
+ * "[id]": {
457
+ * "token": {
458
+ * "nft": { } ← this schema
459
+ * }
460
+ * }
461
+ * }
462
+ * }
463
+ * ```
464
+ */
465
+ const xoTemplateNonFungibleTokenDetailsSchema = z.object({
466
+ capability: z.union([xoTemplateNftCapabilitySchema, z.string()]).optional().describe("The capability of the NFT. May be a known capability value or a CashASM expression resolving to a capability."),
467
+ commitment: z.string().optional().describe("The commitment data for the NFT, as a string or CashASM expression resolving to a commitment.")
468
+ }).strict();
469
+ /**
470
+ * Validation schema for the token configuration on inputs and outputs.
471
+ *
472
+ * ```
473
+ * {
474
+ * "inputs|outputs": {
475
+ * "[id]": {
476
+ * "token": { } ← this schema
477
+ * }
478
+ * }
479
+ * }
480
+ * ```
481
+ */
482
+ const xoTemplateTokenSchema = z.object({
483
+ category: z.string().optional().describe("The category of the token, as a string or CashASM expression resolving to a category."),
484
+ amount: z.union([
485
+ z.bigint(),
486
+ z.string(),
487
+ z.null()
488
+ ]).optional().describe("The amount of fungible tokens as a bigint, a CashASM expression resolving to a bigint, or null indicating no FT is present."),
489
+ nft: xoTemplateNonFungibleTokenDetailsSchema.nullable().optional().describe("Non-fungible token configuration. Null indicates no NFT is present.")
490
+ }).strict();
491
+ /**
492
+ * Validation schema for the asset amounts configuration. Used by omitChangeAmounts on inputs
493
+ * and by balance on locking scripts, outputs, and their roles.
494
+ */
495
+ const xoTemplateAssetAmountsSchema = z.object({
496
+ satoshis: z.union([
497
+ satoshisSchema,
498
+ z.string(),
499
+ z.literal(true)
500
+ ]).optional().describe("The satoshi amount. Accepts a bigint for a specific value, a CashASM expression, or true for the entire amount."),
501
+ fungibleTokens: z.union([
502
+ z.bigint(),
503
+ z.string(),
504
+ z.literal(true)
505
+ ]).optional().describe("The fungible token amount. Accepts a bigint for a specific value, a CashASM expression, or true for the entire amount."),
506
+ nonfungibleTokens: z.union([
507
+ z.literal(0),
508
+ z.literal(1),
509
+ z.string(),
510
+ z.literal(true)
511
+ ]).optional().describe("Whether an NFT is present: 0 for absent, 1 for present, a CashASM expression evaluating to 0 or 1, or true to estimate the NFT as part of the balance if present, or absent from it if not.")
512
+ }).strict();
513
+ /**
514
+ * Validation schema for the state configuration shared by a locking script and its individual roles.
515
+ * Declares which variables and secrets are tracked in the on-chain state for a given participant.
516
+ *
517
+ * ```
518
+ * {
519
+ * "lockingScripts": {
520
+ * "[id]": {
521
+ * "state": { "variables": [], "secrets": [] } ← this schema
522
+ * "roles": {
523
+ * "[roleId]": {
524
+ * "state": { "variables": [], "secrets": [] } ← this schema
525
+ * }
526
+ * }
527
+ * }
528
+ * }
529
+ * }
530
+ * ```
531
+ */
532
+ const xoTemplateStateSchema = z.object({
533
+ variables: z.array(z.string()).optional().describe("List of variable identifiers to track in state."),
534
+ secrets: z.array(z.string()).optional().describe("List of secret identifiers to track in state.")
535
+ }).strict();
536
+ /**
537
+ * Validation schema for a role definition for a locking script.
538
+ *
539
+ * ```
540
+ * {
541
+ * "lockingScripts": {
542
+ * "[id]": {
543
+ * "roles": {
544
+ * "[roleId]": { } ← this schema
545
+ * }
546
+ * }
547
+ * }
548
+ * }
549
+ * ```
550
+ */
551
+ const xoTemplateLockingScriptRoleSchema = xoTemplateViewPropertiesSchema.partial().extend({
552
+ state: xoTemplateStateSchema.optional().describe("List of items to track as state for this role."),
553
+ actions: z.array(xoTemplateActionIntentSchema).optional().describe("List of action references available to this role."),
554
+ balance: xoTemplateAssetAmountsSchema.partial().optional().describe("Estimated ownership in the optional set of asset amounts specified."),
555
+ selectable: z.boolean().optional().describe("Whether outputs locked to this script should be available for coin selection."),
556
+ privacy: z.union([z.number(), z.string()]).optional().describe("Privacy level for outputs locked to this script. A numeric level or a CashASM expression that evaluates to a privacy level.")
557
+ }).strict();
558
+ /**
559
+ * Validation schema for a locking script definition.
560
+ *
561
+ * ```
562
+ * {
563
+ * "lockingScripts": {
564
+ * "[id]": { } ← this schema
565
+ * }
566
+ * }
567
+ * ```
568
+ */
569
+ const xoTemplateLockingScriptSchema = xoTemplateViewPropertiesSchema.extend({
570
+ lockingType: xoTemplateLockingTypeSchema.optional().describe("The type of locking mechanism. Defaults to p2s if not specified."),
571
+ lockingBytecode: z.string().describe("The locking script bytecode."),
572
+ unlockingBytecode: z.string().optional().describe("Optional default unlocking bytecode when used in automatic coin selection."),
573
+ actions: z.array(xoTemplateActionIntentSchema).optional().describe("The actions available for this locking script."),
574
+ state: xoTemplateStateSchema.optional().describe("List of items to track as state for all participants."),
575
+ balance: xoTemplateAssetAmountsSchema.partial().optional().describe("Estimated ownership in the optional set of asset amounts specified."),
576
+ selectable: z.boolean().optional().describe("Whether outputs locked to this script should be available for coin selection."),
577
+ privacy: z.union([z.number(), z.string()]).optional().describe("Privacy level for outputs locked to this script. A numeric level or a CashASM expression that evaluates to a privacy level."),
578
+ roles: z.record(z.string(), xoTemplateLockingScriptRoleSchema).optional().describe("Specific context for each role participating in this locking script.")
579
+ }).strict();
580
+ /**
581
+ * Validation schema for an input definition in the template. Extends view properties with optional
582
+ * satoshi value, token configuration, and other transaction level fields.
583
+ *
584
+ * ```
585
+ * {
586
+ * "inputs": {
587
+ * "[id]": { } ← this schema
588
+ * }
589
+ * }
590
+ * ```
591
+ */
592
+ const xoTemplateInputSchema = xoTemplateViewPropertiesSchema.extend({
593
+ valueSatoshis: z.union([satoshisSchema, z.string()]).optional().describe("The amount of satoshis for this input as a bigint or a CashASM expression resolving to the amount."),
594
+ token: xoTemplateTokenSchema.nullable().optional().describe("Token configuration for this input."),
595
+ sequenceNumber: z.union([z.number(), z.string()]).optional().describe("The sequence number of this input as a specific number or a CashASM expression."),
596
+ unlockingScript: z.string().optional().describe("Identifier of the unlocking script to use for the UTXO provided for this input."),
597
+ omitChangeAmounts: xoTemplateAssetAmountsSchema.optional().describe("Amount of change that should be omitted from the automatic change handling. WARNING: Setting this can result in loss of funds!")
598
+ }).strict();
599
+ /**
600
+ * Validation schema for an output definition. Extends the locking script schema so that
601
+ * every output inherits the same locking script fields and adds output-specific fields.
602
+ *
603
+ * ```
604
+ * {
605
+ * "outputs": {
606
+ * "[id]": { } ← this schema
607
+ * }
608
+ * }
609
+ * ```
610
+ */
611
+ const xoTemplateOutputSchema = xoTemplateLockingScriptSchema.omit({
612
+ lockingType: true,
613
+ lockingBytecode: true,
614
+ unlockingBytecode: true
615
+ }).extend({
616
+ lockingScript: z.string().describe("Identifier of the locking script to use for this output."),
617
+ valueSatoshis: z.union([satoshisSchema, z.string()]).optional().describe("The amount of satoshis for this output as a bigint or a CashASM expression resolving to the amount."),
618
+ token: xoTemplateTokenSchema.nullable().optional().describe("Token configuration for this output.")
619
+ }).strict();
620
+ /**
621
+ * Validation schema for a transaction input reference for a transaction definition.
622
+ *
623
+ * ```
624
+ * {
625
+ * "transactions": {
626
+ * "[id]": {
627
+ * "inputs": [
628
+ * { "input": "..." } ← this schema
629
+ * ]
630
+ * }
631
+ * }
632
+ * }
633
+ * ```
634
+ */
635
+ const xoTemplateTransactionInputSchema = z.object({
636
+ input: z.string().describe("The input definition identifier."),
637
+ inputIndex: z.number().optional().describe("Optional index of this input in the transaction.")
638
+ }).strict();
639
+ /**
640
+ * Validation schema for a transaction output reference for a transaction definition.
641
+ *
642
+ * ```
643
+ * {
644
+ * "transactions": {
645
+ * "[id]": {
646
+ * "outputs": [
647
+ * { "output": "..." } ← this schema
648
+ * ]
649
+ * }
650
+ * }
651
+ * }
652
+ * ```
653
+ */
654
+ const xoTemplateTransactionOutputSchema = z.object({
655
+ output: z.string().describe("The output definition identifier."),
656
+ outputIndex: z.number().optional().describe("Optional index of this output in the transaction.")
657
+ }).strict();
658
+ /**
659
+ * Validation schema for role-specific data for a transaction definition.
660
+ *
661
+ * ```
662
+ * {
663
+ * "transactions": {
664
+ * "[id]": {
665
+ * "roles": {
666
+ * "[roleId]": { } ← this schema
667
+ * }
668
+ * }
669
+ * }
670
+ * }
671
+ * ```
672
+ */
673
+ const xoTemplateTransactionRoleDataSchema = xoTemplateViewPropertiesSchema.partial().extend({
674
+ inputs: z.array(xoTemplateTransactionInputSchema).optional().describe("The inputs required for this role."),
675
+ outputs: z.array(xoTemplateTransactionOutputSchema).optional().describe("The outputs required for this role.")
676
+ }).strict();
677
+ /**
678
+ * Validation schema for a transaction template definition.
679
+ *
680
+ * ```
681
+ * {
682
+ * "transactions": {
683
+ * "[id]": { } ← this schema
684
+ * }
685
+ * }
686
+ * ```
687
+ */
688
+ const xoTemplateTransactionSchema = xoTemplateViewPropertiesSchema.extend({
689
+ version: z.number().optional().describe("The version of the transaction."),
690
+ locktime: z.number().optional().describe("The locktime for this transaction."),
691
+ inputs: z.array(xoTemplateTransactionInputSchema).describe("The inputs for this transaction."),
692
+ outputs: z.array(xoTemplateTransactionOutputSchema).describe("The outputs for this transaction."),
693
+ roles: z.record(z.string(), xoTemplateTransactionRoleDataSchema).optional().describe("Specific context for each role participating in this transaction."),
694
+ composable: z.boolean().optional().describe("Whether this transaction can be composed with other transactions.")
695
+ }).strict();
696
+ /**
697
+ * Validation schema for a constant value definition.
698
+ *
699
+ * ```
700
+ * {
701
+ * "constants": {
702
+ * "[id]": { } ← this schema
703
+ * }
704
+ * }
705
+ * ```
706
+ */
707
+ const xoTemplateConstantSchema = xoTemplateViewPropertiesSchema.extend({
708
+ type: xoTemplatePrimitiveTypeSchema.describe("The data type of this constant."),
709
+ value: z.unknown().describe("The value of this constant."),
710
+ hint: z.string().optional().describe("An optional hint to help apps and users understand what this constant represents.")
711
+ }).strict();
712
+ /**
713
+ * Validation schema for a data field definition.
714
+ *
715
+ * ```
716
+ * {
717
+ * "data": {
718
+ * "[id]": { } ← this schema
719
+ * }
720
+ * }
721
+ * ```
722
+ */
723
+ const xoTemplateDataSchema = z.object({
724
+ type: xoTemplatePrimitiveTypeSchema.describe("The data type of this data field."),
725
+ value: z.unknown().describe("The value for this data field."),
726
+ hint: z.string().optional().describe("An optional hint to help apps and users understand this data field.")
727
+ }).strict();
728
+ /**
729
+ * Validation schema for an import default value intent. Extends the base intent with optional
730
+ * view properties that the engine evaluates at runtime to produce human-readable output.
731
+ *
732
+ * ```
733
+ * {
734
+ * "variables": {
735
+ * "[id]": {
736
+ * "importDefaultValue": { } ← this schema
737
+ * }
738
+ * }
739
+ * }
740
+ * ```
741
+ */
742
+ const xoTemplateImportDefaultValueSchema = xoTemplateIntentSchema.extend(xoTemplateViewPropertiesSchema.partial().shape).strict();
743
+ /**
744
+ * Validation schema for a variable definition.
745
+ *
746
+ * ```
747
+ * {
748
+ * "variables": {
749
+ * "[id]": { } ← this schema
750
+ * }
751
+ * }
752
+ * ```
753
+ */
754
+ const xoTemplateVariableSchema = xoTemplateViewPropertiesSchema.extend({
755
+ type: xoTemplatePrimitiveTypeSchema.optional().describe("The data type of this variable."),
756
+ hint: z.string().optional().describe("A hint to help users understand what value to provide."),
757
+ importDefaultValue: xoTemplateImportDefaultValueSchema.optional().describe("A neutral intent that the engine uses to populate the default value for this variable.")
758
+ }).strict();
759
+ /**
760
+ * Validation schema for a resource reference attached to a template element. Extends view
761
+ * properties with a URL pointing to external documentation or tooling.
762
+ *
763
+ * ```
764
+ * {
765
+ * "resources": [
766
+ * { "name": "...", "description": "...", "url": "..." } ← this schema
767
+ * ]
768
+ * }
769
+ * ```
770
+ */
771
+ const xoTemplateResourceSchema = xoTemplateViewPropertiesSchema.extend({ url: z.string().describe("The URL for this resource.") }).strict();
772
+ /**
773
+ * Validation schema for an icon reference.
774
+ *
775
+ * ```
776
+ * {
777
+ * "icons": [
778
+ * { "name": "...", "hash": "..." } ← this schema
779
+ * ]
780
+ * }
781
+ * ```
782
+ */
783
+ const xoTemplateIconSchema = xoTemplateViewPropertiesSchema.pick({ name: true }).extend({ hash: z.string().describe("The identifier of the icon.") }).strict();
784
+ /**
785
+ * Validation schema for the defaults block of a template.
786
+ *
787
+ * ```
788
+ * {
789
+ * "defaults": { } ← this schema
790
+ * }
791
+ * ```
792
+ */
793
+ const xoTemplateDefaultsSchema = z.object({ change: xoTemplateOutputIntentSchema.optional().describe("Instructions for how to construct automated change output.") }).strict();
794
+ /**
795
+ * Validation schema for the full XOTemplate type.
796
+ */
797
+ const xoTemplateSchema = xoTemplateViewPropertiesSchema.extend({
798
+ $schema: z.string().describe("The URI that identifies the JSON Schema used by this template. This enables documentation, autocompletion, and validation in JSON documents."),
799
+ version: z.string().optional().describe("A string identifying the version of this template."),
800
+ supported: z.array(bchVmVersionSchema).min(1).describe("The BCH VM versions that this template supports. At least one version is required."),
801
+ defaults: xoTemplateDefaultsSchema.optional().describe("Optional default settings used in this template."),
802
+ roles: z.record(z.string(), xoTemplateViewPropertiesSchema).describe("The roles defined in this template."),
803
+ start: z.array(xoTemplateActionIntentSchema).describe("A list of entry points defining which actions are available at the start."),
804
+ actions: z.record(z.string(), xoTemplateActionSchema).describe("The actions defined in this template."),
805
+ data: z.record(z.string(), xoTemplateDataSchema).optional().describe("The data fields defined in this template."),
806
+ transactions: z.record(z.string(), xoTemplateTransactionSchema).optional().describe("The transaction templates defined in this template."),
807
+ inputs: z.record(z.string(), xoTemplateInputSchema).describe("The inputs defined in this template."),
808
+ outputs: z.record(z.string(), xoTemplateOutputSchema).describe("The outputs defined in this template."),
809
+ lockingScripts: z.record(z.string(), xoTemplateLockingScriptSchema).describe("The locking script templates defined in this template."),
810
+ scripts: z.record(z.string(), z.string()).describe("Scripts used in this template. Keys are script identifiers, values are bytecode or CashASM expressions."),
811
+ constants: z.record(z.string(), xoTemplateConstantSchema).optional().describe("The constants defined in this template."),
812
+ variables: z.record(z.string(), xoTemplateVariableSchema).optional().describe("The variables that must be provided for use in the template's scripts."),
813
+ resources: z.array(xoTemplateResourceSchema).optional().describe("Resource references providing external documentation or tooling links."),
814
+ icons: z.array(xoTemplateIconSchema).optional().describe("The icons available for use throughout the template."),
815
+ scenarios: z.unknown().optional().describe("The scenarios defined in this template.")
816
+ }).strict();
817
+
818
+ //#endregion
819
+ //#region source/template/parser.ts
820
+ /**
821
+ * Accepts a template value and returns a validated XOTemplate object. The input may be
822
+ * either an Extended JSON string or a pre-parsed object. Both are validated
823
+ * against the XOTemplate schema.
824
+ *
825
+ * @param inputTemplate - The value to validate. May be an Extended JSON string or a pre-parsed object.
826
+ * @returns The validated template object
827
+ * @throws {TemplateSerializationFailedError} If a pre-parsed object input cannot be serialized to JSON for normalization.
828
+ * @throws {TemplateJsonMalformedError} If the string input is not valid JSON.
829
+ * @throws {TemplateInvalidError} If the value does not conform to the XOTemplate schema.
830
+ */
831
+ const parseTemplate = (inputTemplate) => {
832
+ const templateObject = deserializeTemplate(typeof inputTemplate === "string" ? inputTemplate : serializeTemplate(inputTemplate));
833
+ const parseResult = xoTemplateSchema.safeParse(templateObject);
834
+ if (parseResult.success) return parseResult.data;
835
+ throw new TemplateInvalidError(buildErrorDescription(parseResult.error.issues));
836
+ };
837
+
838
+ //#endregion
839
+ export { TemplateInvalidError, TemplateJsonMalformedError, TemplateSerializationFailedError, VIEW_PROPERTIES_DESCRIPTION_MAX_LENGTH, VIEW_PROPERTIES_ICON_MAX_LENGTH, VIEW_PROPERTIES_NAME_MAX_LENGTH, bchVmVersionSchema, buildErrorDescription, extendedJsonReplacer, extendedJsonReviver, generateTemplateIdentifier, parseTemplate, satoshisSchema, scriptToScriptHash, serializeTemplate, uint8ArraySchema, xoTemplateActionIntentSchema, xoTemplateActionRequirementsSchema, xoTemplateActionRoleRequirementsSchema, xoTemplateActionRoleSchema, xoTemplateActionSchema, xoTemplateAssetAmountsSchema, xoTemplateConstantSchema, xoTemplateDataSchema, xoTemplateDefaultsSchema, xoTemplateIconSchema, xoTemplateImportDefaultValueSchema, xoTemplateInputSchema, xoTemplateIntentSchema, xoTemplateLockingScriptIntentSchema, xoTemplateLockingScriptRoleSchema, xoTemplateLockingScriptSchema, xoTemplateLockingTypeSchema, xoTemplateNftCapabilitySchema, xoTemplateNonFungibleTokenDetailsSchema, xoTemplateOutputIntentSchema, xoTemplateOutputSchema, xoTemplatePrimitiveTypeSchema, xoTemplateResourceSchema, xoTemplateRoleSlotSchema, xoTemplateRoleSlotsRequirementsSchema, xoTemplateSchema, xoTemplateStateSchema, xoTemplateTokenSchema, xoTemplateTransactionInputSchema, xoTemplateTransactionOutputSchema, xoTemplateTransactionRoleDataSchema, xoTemplateTransactionSchema, xoTemplateVariableSchema, xoTemplateViewPropertiesSchema };
840
+ //# sourceMappingURL=index.mjs.map