zcashname-sdk 0.8.1 → 0.8.3

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/zns.cjs CHANGED
@@ -35,7 +35,8 @@ __export(zns_exports, {
35
35
  LIST_COMMISSION: () => LIST_COMMISSION,
36
36
  MAINNET_UIVK: () => MAINNET_UIVK,
37
37
  TESTNET_UIVK: () => TESTNET_UIVK,
38
- ZNS: () => ZNS
38
+ ZNS: () => ZNS,
39
+ ZNS_ACTIONS: () => ZNS_ACTIONS
39
40
  });
40
41
  module.exports = __toCommonJS(zns_exports);
41
42
  var ed25519 = __toESM(require("@noble/ed25519"), 1);
@@ -54,7 +55,14 @@ var REGISTRY_ADDRESSES = {
54
55
  testnet: "utest1f32kn6c4zvn54xr8wfsnxmj9hzpu2mwgtxzpzwcw34906tdccdvzs0z2dx38lly7tpan77x6udt8pjczqm22ymsdhlz9j0tk5yq664nl",
55
56
  mainnet: "u1k0evt0ahj5qdt6y9ftsxndl8lrkm4ff6rp00u04cjpmqj6hxl9t8hfsxftmn3ht34e03lljh89czn2h8qn67rwrs8x0hm3lsxsucp9q9"
56
57
  };
58
+ var ZNS_ACTIONS = ["CLAIM", "BUY", "UPDATE", "LIST", "DELIST", "RELEASE"];
57
59
  var NAME_RE = /^[a-z0-9]{1,62}$/;
60
+ function isWholeNumber(value) {
61
+ return /^\d+$/.test(value) && !value.startsWith("0") || value === "0";
62
+ }
63
+ function mk(level, action, canonical, message) {
64
+ return { valid: level === "valid", action, canonicalAction: canonical, message, level };
65
+ }
58
66
  var ZNS = class {
59
67
  /**
60
68
  * Creates a new ZNS client.
@@ -182,6 +190,120 @@ var ZNS = class {
182
190
  isValidName(name) {
183
191
  return NAME_RE.test(name);
184
192
  }
193
+ /**
194
+ * Validate a signing payload string against the ZNS memo format spec.
195
+ *
196
+ * This is the single source of truth for payload format validation —
197
+ * it mirrors the Rust indexer's `parse_memo` and `signing_payload` logic.
198
+ *
199
+ * Does NOT validate the signature (see {@link verifyEd25519} for that).
200
+ * Does NOT validate the name against the blockchain (see {@link isAvailable} for that).
201
+ *
202
+ * @param payload - Raw payload string, e.g. `CLAIM:foo:u1abc`
203
+ * @returns Validation result with level and human-readable message
204
+ *
205
+ * @example
206
+ * ```ts
207
+ * const result = zns.validatePayload("CLAIM:alice:u1qvs2...");
208
+ * if (!result.valid) {
209
+ * console.error(result.message);
210
+ * }
211
+ * ```
212
+ */
213
+ validatePayload(payload) {
214
+ const raw = String(payload ?? "").trim();
215
+ if (!raw) {
216
+ return {
217
+ valid: false,
218
+ action: "",
219
+ canonicalAction: null,
220
+ message: "Empty payload.",
221
+ level: "invalid"
222
+ };
223
+ }
224
+ const colonIdx = raw.indexOf(":");
225
+ if (colonIdx === -1) {
226
+ return {
227
+ valid: false,
228
+ action: raw.toUpperCase(),
229
+ canonicalAction: null,
230
+ message: "Missing colon separator. Expected format: ACTION:field1:field2:...",
231
+ level: "invalid"
232
+ };
233
+ }
234
+ const actionUpper = raw.slice(0, colonIdx).toUpperCase();
235
+ const actionLower = raw.slice(0, colonIdx).toLowerCase();
236
+ const rest = raw.slice(colonIdx + 1);
237
+ const parts = rest.split(":");
238
+ switch (actionLower) {
239
+ case "claim": {
240
+ if (parts.length !== 2)
241
+ return mk("invalid", actionUpper, "claim", `Expected CLAIM:<name>:<ua>.`);
242
+ if (!NAME_RE.test(parts[0]))
243
+ return mk("invalid", actionUpper, "claim", `Invalid name. Use lowercase a-z and 0-9, 1 to 62 chars.`);
244
+ if (!this.isValidUnifiedAddress(parts[1]))
245
+ return mk("invalid", actionUpper, "claim", `Invalid unified address: "${parts[1]}".`);
246
+ return mk("valid", actionUpper, "claim", "Valid CLAIM payload.");
247
+ }
248
+ case "buy": {
249
+ if (parts.length !== 2)
250
+ return mk("invalid", actionUpper, "buy", `Expected BUY:<name>:<buyer_ua>.`);
251
+ if (!NAME_RE.test(parts[0]))
252
+ return mk("invalid", actionUpper, "buy", `Invalid name. Use lowercase a-z and 0-9, 1 to 62 chars.`);
253
+ if (!this.isValidUnifiedAddress(parts[1]))
254
+ return mk("invalid", actionUpper, "buy", `Invalid unified address: "${parts[1]}".`);
255
+ return mk("valid", actionUpper, "buy", "Valid BUY payload.");
256
+ }
257
+ case "update": {
258
+ if (parts.length !== 3)
259
+ return mk("invalid", actionUpper, "update", `Expected UPDATE:<name>:<ua>:<nonce>.`);
260
+ if (!NAME_RE.test(parts[0]))
261
+ return mk("invalid", actionUpper, "update", `Invalid name. Use lowercase a-z and 0-9, 1 to 62 chars.`);
262
+ if (!this.isValidUnifiedAddress(parts[1]))
263
+ return mk("invalid", actionUpper, "update", `Invalid unified address: "${parts[1]}".`);
264
+ if (!isWholeNumber(parts[2]))
265
+ return mk("invalid", actionUpper, "update", `Nonce must be a whole number.`);
266
+ return mk("valid", actionUpper, "update", "Valid UPDATE payload.");
267
+ }
268
+ case "list": {
269
+ if (parts.length !== 4)
270
+ return mk("invalid", actionUpper, "list", `Expected LIST:<name>:<price_zats>:<pay_taddr>:<nonce>.`);
271
+ if (!NAME_RE.test(parts[0]))
272
+ return mk("invalid", actionUpper, "list", `Invalid name. Use lowercase a-z and 0-9, 1 to 62 chars.`);
273
+ if (!isWholeNumber(parts[1]) || Number(parts[1]) <= 0)
274
+ return mk("invalid", actionUpper, "list", `Price must be a positive whole number in zats.`);
275
+ if (!isWholeNumber(parts[3]))
276
+ return mk("invalid", actionUpper, "list", `Nonce must be a whole number.`);
277
+ return mk("valid", actionUpper, "list", "Valid LIST payload.");
278
+ }
279
+ case "delist": {
280
+ if (parts.length !== 2)
281
+ return mk("invalid", actionUpper, "delist", `Expected DELIST:<name>:<nonce>.`);
282
+ if (!NAME_RE.test(parts[0]))
283
+ return mk("invalid", actionUpper, "delist", `Invalid name. Use lowercase a-z and 0-9, 1 to 62 chars.`);
284
+ if (!isWholeNumber(parts[1]))
285
+ return mk("invalid", actionUpper, "delist", `Nonce must be a whole number.`);
286
+ return mk("valid", actionUpper, "delist", "Valid DELIST payload.");
287
+ }
288
+ case "release": {
289
+ if (parts.length !== 2)
290
+ return mk("invalid", actionUpper, "release", `Expected RELEASE:<name>:<nonce>.`);
291
+ if (!NAME_RE.test(parts[0]))
292
+ return mk("invalid", actionUpper, "release", `Invalid name. Use lowercase a-z and 0-9, 1 to 62 chars.`);
293
+ if (!isWholeNumber(parts[1]))
294
+ return mk("invalid", actionUpper, "release", `Nonce must be a whole number.`);
295
+ return mk("valid", actionUpper, "release", "Valid RELEASE payload.");
296
+ }
297
+ default:
298
+ return {
299
+ valid: false,
300
+ action: actionUpper,
301
+ canonicalAction: null,
302
+ message: `Unrecognized action "${actionUpper}". Valid actions: ${ZNS_ACTIONS.join(", ")}.`,
303
+ level: "unrecognized"
304
+ };
305
+ }
306
+ }
185
307
  /**
186
308
  * Get the claim cost in zatoshis for a name of given length.
187
309
  * @param nameLength The length of the name (1-62)
@@ -416,5 +538,6 @@ var ZNS = class {
416
538
  LIST_COMMISSION,
417
539
  MAINNET_UIVK,
418
540
  TESTNET_UIVK,
419
- ZNS
541
+ ZNS,
542
+ ZNS_ACTIONS
420
543
  });
package/dist/zns.d.cts CHANGED
@@ -133,10 +133,29 @@ interface PreparedSetPrice extends PreparedAction {
133
133
  readonly prices: readonly Zats[];
134
134
  readonly nonce: number;
135
135
  }
136
+ /** Validation result for a signing payload.
137
+ * Mirrors the Rust indexer's parse_memo format validation.
138
+ * @see https://github.com/zcashme/ZNS/blob/main/src/memo.rs */
139
+ type PayloadValidationLevel = "valid" | "invalid" | "unrecognized";
140
+ interface PayloadValidationResult {
141
+ /** Whether the payload is valid for signing. */
142
+ readonly valid: boolean;
143
+ /** Parsed action name (uppercase), e.g. "CLAIM", "LIST" */
144
+ readonly action: string;
145
+ /** Canonical action used internally (lowercase), e.g. "claim", "list" */
146
+ readonly canonicalAction: string | null;
147
+ /** Human-readable validation message */
148
+ readonly message: string;
149
+ /** Validation level: valid | invalid | unrecognized */
150
+ readonly level: PayloadValidationLevel;
151
+ }
136
152
 
137
153
  declare const DEFAULT_URL = "https://light.zcash.me/zns-testnet";
138
154
  declare const TESTNET_UIVK = "uivktest1hzw7wyadutvzfgpna80yftsk5l7jeyu2p5me5quvp28tytxueta00cx4068wnlzcv7tx9n3t3gfhsy83pe4y6jrhxtzaq0hj6xtg5zrk2dn7zen3vns2a5pgs4fxdjlletmqrhfa42";
139
155
  declare const MAINNET_UIVK = "uivk1gl26qy0xjja7lqhyg3pf0x4j4j66kqwewrjkdcg28eqq4wgtzjmujpee7x9cs2ec9xhnlgrm8ptlw8z80j2aryw8nqtssser2ys778a0s00uvgkdjnfr58sndhfvc3f4zqjs6ywva6";
156
+ /** Actions accepted by {@link validatePayload}. Exposed for consumers who need
157
+ * to build action selectors or dynamic validation. */
158
+ declare const ZNS_ACTIONS: readonly ["CLAIM", "BUY", "UPDATE", "LIST", "DELIST", "RELEASE"];
140
159
  type Network = "testnet" | "mainnet";
141
160
  declare class ZNS {
142
161
  private url;
@@ -201,6 +220,27 @@ declare class ZNS {
201
220
  verifyRegistration(reg: Registration, adminPubkey: string): Promise<boolean>;
202
221
  /** Check if a name is valid format (lowercase alphanumeric, 1-62 chars). */
203
222
  isValidName(name: string): boolean;
223
+ /**
224
+ * Validate a signing payload string against the ZNS memo format spec.
225
+ *
226
+ * This is the single source of truth for payload format validation —
227
+ * it mirrors the Rust indexer's `parse_memo` and `signing_payload` logic.
228
+ *
229
+ * Does NOT validate the signature (see {@link verifyEd25519} for that).
230
+ * Does NOT validate the name against the blockchain (see {@link isAvailable} for that).
231
+ *
232
+ * @param payload - Raw payload string, e.g. `CLAIM:foo:u1abc`
233
+ * @returns Validation result with level and human-readable message
234
+ *
235
+ * @example
236
+ * ```ts
237
+ * const result = zns.validatePayload("CLAIM:alice:u1qvs2...");
238
+ * if (!result.valid) {
239
+ * console.error(result.message);
240
+ * }
241
+ * ```
242
+ */
243
+ validatePayload(payload: string): PayloadValidationResult;
204
244
  /**
205
245
  * Get the claim cost in zatoshis for a name of given length.
206
246
  * @param nameLength The length of the name (1-62)
@@ -246,4 +286,4 @@ declare class ZNS {
246
286
  private rpc;
247
287
  }
248
288
 
249
- export { BUY_COMMISSION, type CompletedAction, DEFAULT_URL, type Event, type EventAction, type EventsFilter, type EventsResult, LIST_COMMISSION, type LastAction, type Listing, MAINNET_UIVK, type Network, type PendingBuy, type PreparedBuy, type PreparedClaim, type PreparedDelist, type PreparedList, type PreparedRelease, type PreparedSetPrice, type PreparedUpdate, type Pricing, type Registration, type Status, TESTNET_UIVK, ZNS, type Zats };
289
+ export { BUY_COMMISSION, type CompletedAction, DEFAULT_URL, type Event, type EventAction, type EventsFilter, type EventsResult, LIST_COMMISSION, type LastAction, type Listing, MAINNET_UIVK, type Network, type PayloadValidationLevel, type PayloadValidationResult, type PendingBuy, type PreparedBuy, type PreparedClaim, type PreparedDelist, type PreparedList, type PreparedRelease, type PreparedSetPrice, type PreparedUpdate, type Pricing, type Registration, type Status, TESTNET_UIVK, ZNS, ZNS_ACTIONS, type Zats };
package/dist/zns.d.ts CHANGED
@@ -133,10 +133,29 @@ interface PreparedSetPrice extends PreparedAction {
133
133
  readonly prices: readonly Zats[];
134
134
  readonly nonce: number;
135
135
  }
136
+ /** Validation result for a signing payload.
137
+ * Mirrors the Rust indexer's parse_memo format validation.
138
+ * @see https://github.com/zcashme/ZNS/blob/main/src/memo.rs */
139
+ type PayloadValidationLevel = "valid" | "invalid" | "unrecognized";
140
+ interface PayloadValidationResult {
141
+ /** Whether the payload is valid for signing. */
142
+ readonly valid: boolean;
143
+ /** Parsed action name (uppercase), e.g. "CLAIM", "LIST" */
144
+ readonly action: string;
145
+ /** Canonical action used internally (lowercase), e.g. "claim", "list" */
146
+ readonly canonicalAction: string | null;
147
+ /** Human-readable validation message */
148
+ readonly message: string;
149
+ /** Validation level: valid | invalid | unrecognized */
150
+ readonly level: PayloadValidationLevel;
151
+ }
136
152
 
137
153
  declare const DEFAULT_URL = "https://light.zcash.me/zns-testnet";
138
154
  declare const TESTNET_UIVK = "uivktest1hzw7wyadutvzfgpna80yftsk5l7jeyu2p5me5quvp28tytxueta00cx4068wnlzcv7tx9n3t3gfhsy83pe4y6jrhxtzaq0hj6xtg5zrk2dn7zen3vns2a5pgs4fxdjlletmqrhfa42";
139
155
  declare const MAINNET_UIVK = "uivk1gl26qy0xjja7lqhyg3pf0x4j4j66kqwewrjkdcg28eqq4wgtzjmujpee7x9cs2ec9xhnlgrm8ptlw8z80j2aryw8nqtssser2ys778a0s00uvgkdjnfr58sndhfvc3f4zqjs6ywva6";
156
+ /** Actions accepted by {@link validatePayload}. Exposed for consumers who need
157
+ * to build action selectors or dynamic validation. */
158
+ declare const ZNS_ACTIONS: readonly ["CLAIM", "BUY", "UPDATE", "LIST", "DELIST", "RELEASE"];
140
159
  type Network = "testnet" | "mainnet";
141
160
  declare class ZNS {
142
161
  private url;
@@ -201,6 +220,27 @@ declare class ZNS {
201
220
  verifyRegistration(reg: Registration, adminPubkey: string): Promise<boolean>;
202
221
  /** Check if a name is valid format (lowercase alphanumeric, 1-62 chars). */
203
222
  isValidName(name: string): boolean;
223
+ /**
224
+ * Validate a signing payload string against the ZNS memo format spec.
225
+ *
226
+ * This is the single source of truth for payload format validation —
227
+ * it mirrors the Rust indexer's `parse_memo` and `signing_payload` logic.
228
+ *
229
+ * Does NOT validate the signature (see {@link verifyEd25519} for that).
230
+ * Does NOT validate the name against the blockchain (see {@link isAvailable} for that).
231
+ *
232
+ * @param payload - Raw payload string, e.g. `CLAIM:foo:u1abc`
233
+ * @returns Validation result with level and human-readable message
234
+ *
235
+ * @example
236
+ * ```ts
237
+ * const result = zns.validatePayload("CLAIM:alice:u1qvs2...");
238
+ * if (!result.valid) {
239
+ * console.error(result.message);
240
+ * }
241
+ * ```
242
+ */
243
+ validatePayload(payload: string): PayloadValidationResult;
204
244
  /**
205
245
  * Get the claim cost in zatoshis for a name of given length.
206
246
  * @param nameLength The length of the name (1-62)
@@ -246,4 +286,4 @@ declare class ZNS {
246
286
  private rpc;
247
287
  }
248
288
 
249
- export { BUY_COMMISSION, type CompletedAction, DEFAULT_URL, type Event, type EventAction, type EventsFilter, type EventsResult, LIST_COMMISSION, type LastAction, type Listing, MAINNET_UIVK, type Network, type PendingBuy, type PreparedBuy, type PreparedClaim, type PreparedDelist, type PreparedList, type PreparedRelease, type PreparedSetPrice, type PreparedUpdate, type Pricing, type Registration, type Status, TESTNET_UIVK, ZNS, type Zats };
289
+ export { BUY_COMMISSION, type CompletedAction, DEFAULT_URL, type Event, type EventAction, type EventsFilter, type EventsResult, LIST_COMMISSION, type LastAction, type Listing, MAINNET_UIVK, type Network, type PayloadValidationLevel, type PayloadValidationResult, type PendingBuy, type PreparedBuy, type PreparedClaim, type PreparedDelist, type PreparedList, type PreparedRelease, type PreparedSetPrice, type PreparedUpdate, type Pricing, type Registration, type Status, TESTNET_UIVK, ZNS, ZNS_ACTIONS, type Zats };
package/dist/zns.js CHANGED
@@ -15,7 +15,14 @@ var REGISTRY_ADDRESSES = {
15
15
  testnet: "utest1f32kn6c4zvn54xr8wfsnxmj9hzpu2mwgtxzpzwcw34906tdccdvzs0z2dx38lly7tpan77x6udt8pjczqm22ymsdhlz9j0tk5yq664nl",
16
16
  mainnet: "u1k0evt0ahj5qdt6y9ftsxndl8lrkm4ff6rp00u04cjpmqj6hxl9t8hfsxftmn3ht34e03lljh89czn2h8qn67rwrs8x0hm3lsxsucp9q9"
17
17
  };
18
+ var ZNS_ACTIONS = ["CLAIM", "BUY", "UPDATE", "LIST", "DELIST", "RELEASE"];
18
19
  var NAME_RE = /^[a-z0-9]{1,62}$/;
20
+ function isWholeNumber(value) {
21
+ return /^\d+$/.test(value) && !value.startsWith("0") || value === "0";
22
+ }
23
+ function mk(level, action, canonical, message) {
24
+ return { valid: level === "valid", action, canonicalAction: canonical, message, level };
25
+ }
19
26
  var ZNS = class {
20
27
  /**
21
28
  * Creates a new ZNS client.
@@ -143,6 +150,120 @@ var ZNS = class {
143
150
  isValidName(name) {
144
151
  return NAME_RE.test(name);
145
152
  }
153
+ /**
154
+ * Validate a signing payload string against the ZNS memo format spec.
155
+ *
156
+ * This is the single source of truth for payload format validation —
157
+ * it mirrors the Rust indexer's `parse_memo` and `signing_payload` logic.
158
+ *
159
+ * Does NOT validate the signature (see {@link verifyEd25519} for that).
160
+ * Does NOT validate the name against the blockchain (see {@link isAvailable} for that).
161
+ *
162
+ * @param payload - Raw payload string, e.g. `CLAIM:foo:u1abc`
163
+ * @returns Validation result with level and human-readable message
164
+ *
165
+ * @example
166
+ * ```ts
167
+ * const result = zns.validatePayload("CLAIM:alice:u1qvs2...");
168
+ * if (!result.valid) {
169
+ * console.error(result.message);
170
+ * }
171
+ * ```
172
+ */
173
+ validatePayload(payload) {
174
+ const raw = String(payload ?? "").trim();
175
+ if (!raw) {
176
+ return {
177
+ valid: false,
178
+ action: "",
179
+ canonicalAction: null,
180
+ message: "Empty payload.",
181
+ level: "invalid"
182
+ };
183
+ }
184
+ const colonIdx = raw.indexOf(":");
185
+ if (colonIdx === -1) {
186
+ return {
187
+ valid: false,
188
+ action: raw.toUpperCase(),
189
+ canonicalAction: null,
190
+ message: "Missing colon separator. Expected format: ACTION:field1:field2:...",
191
+ level: "invalid"
192
+ };
193
+ }
194
+ const actionUpper = raw.slice(0, colonIdx).toUpperCase();
195
+ const actionLower = raw.slice(0, colonIdx).toLowerCase();
196
+ const rest = raw.slice(colonIdx + 1);
197
+ const parts = rest.split(":");
198
+ switch (actionLower) {
199
+ case "claim": {
200
+ if (parts.length !== 2)
201
+ return mk("invalid", actionUpper, "claim", `Expected CLAIM:<name>:<ua>.`);
202
+ if (!NAME_RE.test(parts[0]))
203
+ return mk("invalid", actionUpper, "claim", `Invalid name. Use lowercase a-z and 0-9, 1 to 62 chars.`);
204
+ if (!this.isValidUnifiedAddress(parts[1]))
205
+ return mk("invalid", actionUpper, "claim", `Invalid unified address: "${parts[1]}".`);
206
+ return mk("valid", actionUpper, "claim", "Valid CLAIM payload.");
207
+ }
208
+ case "buy": {
209
+ if (parts.length !== 2)
210
+ return mk("invalid", actionUpper, "buy", `Expected BUY:<name>:<buyer_ua>.`);
211
+ if (!NAME_RE.test(parts[0]))
212
+ return mk("invalid", actionUpper, "buy", `Invalid name. Use lowercase a-z and 0-9, 1 to 62 chars.`);
213
+ if (!this.isValidUnifiedAddress(parts[1]))
214
+ return mk("invalid", actionUpper, "buy", `Invalid unified address: "${parts[1]}".`);
215
+ return mk("valid", actionUpper, "buy", "Valid BUY payload.");
216
+ }
217
+ case "update": {
218
+ if (parts.length !== 3)
219
+ return mk("invalid", actionUpper, "update", `Expected UPDATE:<name>:<ua>:<nonce>.`);
220
+ if (!NAME_RE.test(parts[0]))
221
+ return mk("invalid", actionUpper, "update", `Invalid name. Use lowercase a-z and 0-9, 1 to 62 chars.`);
222
+ if (!this.isValidUnifiedAddress(parts[1]))
223
+ return mk("invalid", actionUpper, "update", `Invalid unified address: "${parts[1]}".`);
224
+ if (!isWholeNumber(parts[2]))
225
+ return mk("invalid", actionUpper, "update", `Nonce must be a whole number.`);
226
+ return mk("valid", actionUpper, "update", "Valid UPDATE payload.");
227
+ }
228
+ case "list": {
229
+ if (parts.length !== 4)
230
+ return mk("invalid", actionUpper, "list", `Expected LIST:<name>:<price_zats>:<pay_taddr>:<nonce>.`);
231
+ if (!NAME_RE.test(parts[0]))
232
+ return mk("invalid", actionUpper, "list", `Invalid name. Use lowercase a-z and 0-9, 1 to 62 chars.`);
233
+ if (!isWholeNumber(parts[1]) || Number(parts[1]) <= 0)
234
+ return mk("invalid", actionUpper, "list", `Price must be a positive whole number in zats.`);
235
+ if (!isWholeNumber(parts[3]))
236
+ return mk("invalid", actionUpper, "list", `Nonce must be a whole number.`);
237
+ return mk("valid", actionUpper, "list", "Valid LIST payload.");
238
+ }
239
+ case "delist": {
240
+ if (parts.length !== 2)
241
+ return mk("invalid", actionUpper, "delist", `Expected DELIST:<name>:<nonce>.`);
242
+ if (!NAME_RE.test(parts[0]))
243
+ return mk("invalid", actionUpper, "delist", `Invalid name. Use lowercase a-z and 0-9, 1 to 62 chars.`);
244
+ if (!isWholeNumber(parts[1]))
245
+ return mk("invalid", actionUpper, "delist", `Nonce must be a whole number.`);
246
+ return mk("valid", actionUpper, "delist", "Valid DELIST payload.");
247
+ }
248
+ case "release": {
249
+ if (parts.length !== 2)
250
+ return mk("invalid", actionUpper, "release", `Expected RELEASE:<name>:<nonce>.`);
251
+ if (!NAME_RE.test(parts[0]))
252
+ return mk("invalid", actionUpper, "release", `Invalid name. Use lowercase a-z and 0-9, 1 to 62 chars.`);
253
+ if (!isWholeNumber(parts[1]))
254
+ return mk("invalid", actionUpper, "release", `Nonce must be a whole number.`);
255
+ return mk("valid", actionUpper, "release", "Valid RELEASE payload.");
256
+ }
257
+ default:
258
+ return {
259
+ valid: false,
260
+ action: actionUpper,
261
+ canonicalAction: null,
262
+ message: `Unrecognized action "${actionUpper}". Valid actions: ${ZNS_ACTIONS.join(", ")}.`,
263
+ level: "unrecognized"
264
+ };
265
+ }
266
+ }
146
267
  /**
147
268
  * Get the claim cost in zatoshis for a name of given length.
148
269
  * @param nameLength The length of the name (1-62)
@@ -376,5 +497,6 @@ export {
376
497
  LIST_COMMISSION,
377
498
  MAINNET_UIVK,
378
499
  TESTNET_UIVK,
379
- ZNS
500
+ ZNS,
501
+ ZNS_ACTIONS
380
502
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zcashname-sdk",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
4
4
  "type": "module",
5
5
  "description": "TypeScript SDK for the Zcash Name System (ZNS)",
6
6
  "main": "dist/zns.cjs",