bulletin-deploy 0.18.1-rc.1 → 0.18.2

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 (40) hide show
  1. package/dist/auth-config.js +3 -3
  2. package/dist/bug-report.js +4 -4
  3. package/dist/chain-health.js +3 -3
  4. package/dist/{chunk-FJTZNSNU.js → chunk-2GKEZI5B.js} +104 -20
  5. package/dist/{chunk-2WGCBESY.js → chunk-6BNYZN7R.js} +2 -2
  6. package/dist/{chunk-5JVTBR5H.js → chunk-BQKBZMLB.js} +3 -3
  7. package/dist/{chunk-Q7CHACT6.js → chunk-CWLLC46X.js} +1 -1
  8. package/dist/{chunk-RULOELNF.js → chunk-D6ONN6VJ.js} +1 -1
  9. package/dist/{chunk-HIODF4QF.js → chunk-DOLHX2AM.js} +1 -1
  10. package/dist/{chunk-Q6NVSUCX.js → chunk-FWMFCXIB.js} +35 -15
  11. package/dist/{chunk-UPQ2JGIO.js → chunk-H3ZDWTNY.js} +1 -1
  12. package/dist/chunk-HNJWIY55.js +8 -0
  13. package/dist/{chunk-6HPDXI7E.js → chunk-IAPBFRWN.js} +1 -1
  14. package/dist/{chunk-SSV2KD3B.js → chunk-QCZKXFCY.js} +2 -2
  15. package/dist/{chunk-3BDYD4BG.js → chunk-W76SHNTO.js} +3 -3
  16. package/dist/{chunk-64UKPUK4.js → chunk-ZHSULISU.js} +1 -1
  17. package/dist/chunk-probe.js +3 -3
  18. package/dist/commands/login.js +12 -11
  19. package/dist/commands/logout.js +4 -4
  20. package/dist/commands/transfer.js +4 -4
  21. package/dist/commands/whoami.js +3 -3
  22. package/dist/deploy-actors.js +6 -6
  23. package/dist/deploy.js +12 -11
  24. package/dist/dotns.d.ts +42 -4
  25. package/dist/dotns.js +4 -4
  26. package/dist/index.js +13 -12
  27. package/dist/manifest/publish.js +13 -12
  28. package/dist/manifest/schema.d.ts +4 -0
  29. package/dist/memory-report.js +2 -2
  30. package/dist/merkle.js +12 -11
  31. package/dist/personhood/bootstrap.js +13 -13
  32. package/dist/personhood/people-client.js +4 -4
  33. package/dist/run-state.js +1 -1
  34. package/dist/sss-allowance-cache.js +4 -4
  35. package/dist/storage-signer.js +12 -11
  36. package/dist/subname-depth.d.ts +22 -0
  37. package/dist/subname-depth.js +6 -0
  38. package/dist/telemetry.js +2 -2
  39. package/dist/version-check.js +3 -3
  40. package/package.json +2 -2
@@ -9,12 +9,12 @@ import {
9
9
  getPeopleChainEndpoints,
10
10
  hasPersistedSession,
11
11
  resolveBulletinEndpoints
12
- } from "./chunk-Q7CHACT6.js";
12
+ } from "./chunk-CWLLC46X.js";
13
13
  import "./chunk-TSPERKUS.js";
14
14
  import "./chunk-HDGD5FYX.js";
15
15
  import "./chunk-ZOC4GITL.js";
16
- import "./chunk-HIODF4QF.js";
17
- import "./chunk-SSV2KD3B.js";
16
+ import "./chunk-DOLHX2AM.js";
17
+ import "./chunk-QCZKXFCY.js";
18
18
  export {
19
19
  DOT_DAPP_ID,
20
20
  DOT_DERIVATION_INDEX,
@@ -10,10 +10,10 @@ import {
10
10
  offerBugReport,
11
11
  scrubSecrets,
12
12
  setDeployContext
13
- } from "./chunk-3BDYD4BG.js";
14
- import "./chunk-UPQ2JGIO.js";
15
- import "./chunk-HIODF4QF.js";
16
- import "./chunk-SSV2KD3B.js";
13
+ } from "./chunk-W76SHNTO.js";
14
+ import "./chunk-H3ZDWTNY.js";
15
+ import "./chunk-DOLHX2AM.js";
16
+ import "./chunk-QCZKXFCY.js";
17
17
  export {
18
18
  buildCliFlagsSummary,
19
19
  buildLabels,
@@ -3,9 +3,9 @@ import {
3
3
  DEFAULT_WINDOW_BLOCKS,
4
4
  MAX_SPANS_PER_SAMPLER,
5
5
  endpointHost
6
- } from "./chunk-6HPDXI7E.js";
7
- import "./chunk-HIODF4QF.js";
8
- import "./chunk-SSV2KD3B.js";
6
+ } from "./chunk-IAPBFRWN.js";
7
+ import "./chunk-DOLHX2AM.js";
8
+ import "./chunk-QCZKXFCY.js";
9
9
  export {
10
10
  ChainHealthSampler,
11
11
  DEFAULT_WINDOW_BLOCKS,
@@ -13,7 +13,7 @@ import {
13
13
  } from "./chunk-ZOC4GITL.js";
14
14
  import {
15
15
  ChainHealthSampler
16
- } from "./chunk-6HPDXI7E.js";
16
+ } from "./chunk-IAPBFRWN.js";
17
17
  import {
18
18
  captureWarning,
19
19
  markCodePath,
@@ -21,7 +21,7 @@ import {
21
21
  setDeploySentryTag,
22
22
  truncateAddress,
23
23
  withSpan
24
- } from "./chunk-HIODF4QF.js";
24
+ } from "./chunk-DOLHX2AM.js";
25
25
  import {
26
26
  POP_CONTROLLER_PROBE_ABI,
27
27
  PROTOCOL_PROBE_LABEL,
@@ -411,7 +411,18 @@ var DOTNS_REGISTRY_ABI = [
411
411
  { inputs: [{ name: "record", type: "tuple", components: [{ name: "parentNode", type: "bytes32" }, { name: "subLabel", type: "string" }, { name: "parentLabel", type: "string" }, { name: "owner", type: "address" }] }], name: "setSubnodeOwner", outputs: [{ name: "subnode", type: "bytes32" }], stateMutability: "nonpayable", type: "function" },
412
412
  { inputs: [{ name: "node", type: "bytes32" }, { name: "newResolver", type: "address" }], name: "setResolver", outputs: [], stateMutability: "nonpayable", type: "function" },
413
413
  { inputs: [{ name: "node", type: "bytes32" }], name: "owner", outputs: [{ name: "", type: "address" }], stateMutability: "view", type: "function" },
414
- { inputs: [{ name: "node", type: "bytes32" }], name: "resolver", outputs: [{ name: "", type: "address" }], stateMutability: "view", type: "function" }
414
+ { inputs: [{ name: "node", type: "bytes32" }], name: "resolver", outputs: [{ name: "", type: "address" }], stateMutability: "view", type: "function" },
415
+ // #1435-adjacent: DotnsRegistry.isAuthorised(node, account) — verified against
416
+ // upstream IDotnsRegistry.sol at v0.7.0. The contract's own doc comment calls
417
+ // this "the canonical authorisation check the registry enforces on
418
+ // owner-gated entry points" and "the single source of truth" _authorised/
419
+ // isAuthorised both delegate to: a non-zero stored subnode owner must equal
420
+ // account; otherwise, for a tokenised node, the registrar's ERC-721 owner,
421
+ // an operator-for-all delegate, or a single-token approval all qualify.
422
+ // Strictly wider than a raw owner()-equality test. See
423
+ // checkNodeAuthorization below, which prefers this and falls back to
424
+ // owner()-equality only when this accessor is absent (a bare revert).
425
+ { inputs: [{ name: "node", type: "bytes32" }, { name: "account", type: "address" }], name: "isAuthorised", outputs: [{ name: "authorisedFlag", type: "bool" }], stateMutability: "view", type: "function" }
415
426
  ];
416
427
  var DOTNS_REGISTRY_SET_SUBNODE_OWNER_ABI_V07 = [
417
428
  { inputs: [{ name: "record", type: "tuple", components: [{ name: "parentNode", type: "bytes32" }, { name: "subLabel", type: "string" }, { name: "parentLabel", type: "string" }, { name: "owner", type: "address" }, { name: "persist", type: "bool" }] }], name: "setSubnodeOwner", outputs: [{ name: "subnode", type: "bytes32" }], stateMutability: "nonpayable", type: "function" }
@@ -819,13 +830,11 @@ function parseDomainName(input, tld = DEFAULT_TLD) {
819
830
  const sanitized = validateDomainLabel(parts[0]);
820
831
  return { isSubdomain: false, label: sanitized, sublabel: null, parentLabel: null, fullName: `${sanitized}.${tld}` };
821
832
  }
822
- if (parts.length === 2) {
823
- const sanitizedSub = validateDomainLabel(parts[0]);
824
- const sanitizedParent = validateDomainLabel(parts[1]);
825
- const fullLabel = `${sanitizedSub}.${sanitizedParent}`;
826
- return { isSubdomain: true, label: fullLabel, sublabel: sanitizedSub, parentLabel: sanitizedParent, fullName: `${fullLabel}.${tld}` };
827
- }
828
- throw new Error(`Invalid domain: only one level of subdomains supported (got ${parts.length} labels)`);
833
+ const restParts = parts.slice(1);
834
+ const sanitizedSub = validateDomainLabel(parts[0]);
835
+ const sanitizedParent = restParts.map((p) => validateDomainLabel(p)).join(".");
836
+ const fullLabel = `${sanitizedSub}.${sanitizedParent}`;
837
+ return { isSubdomain: true, label: fullLabel, sublabel: sanitizedSub, parentLabel: sanitizedParent, fullName: `${fullLabel}.${tld}` };
829
838
  }
830
839
  function parseProofOfPersonhoodStatus(status) {
831
840
  const s = (status ?? "none").toLowerCase();
@@ -2216,6 +2225,82 @@ var DotNS = class _DotNS {
2216
2225
  return { owned: false, owner: null };
2217
2226
  }
2218
2227
  }
2228
+ /**
2229
+ * Raw probe for DotnsRegistry.isAuthorised(node, account) — returns the
2230
+ * decoded bool when the accessor exists, or `null` when it is absent from
2231
+ * this registry deployment (a bare selector-not-found revert). Shares the
2232
+ * bare-revert-vs-real-revert discrimination (isBareRevertResult) with
2233
+ * resolveSubnodeOwnerShape's v0.7 shape probe above: a revert WITH data
2234
+ * means the function exists and the on-chain call itself is a normal view
2235
+ * read that should never revert for a real reason (see _isAuthorised in
2236
+ * DotnsRegistry.sol — it only ever returns a bool), so that branch
2237
+ * propagates as an unexpected failure rather than being folded into
2238
+ * "absent".
2239
+ */
2240
+ async probeIsAuthorised(node, account) {
2241
+ this.ensureConnected();
2242
+ if (!this.clientWrapper) throw new Error("probeIsAuthorised: polkadot-api client not available");
2243
+ const contractAddress = this._contracts.DOTNS_REGISTRY;
2244
+ const isAuthorisedAbi = DOTNS_REGISTRY_ABI;
2245
+ const isAuthorisedArgs = [node, account];
2246
+ const encodedCallData = encodeFunctionData({ abi: isAuthorisedAbi, functionName: "isAuthorised", args: isAuthorisedArgs });
2247
+ const callResult = await this.clientWrapper.performDryRunCall(this.substrateAddress, contractAddress, 0n, encodedCallData);
2248
+ if (callResult.result.isOk) {
2249
+ const rawData = callResult.result.value.data ?? "0x";
2250
+ if (rawData.length > 2) {
2251
+ return decodeFunctionResult({ abi: DOTNS_REGISTRY_ABI, functionName: "isAuthorised", data: rawData });
2252
+ }
2253
+ return null;
2254
+ }
2255
+ const errorData = callResult.result.value;
2256
+ const revertData = errorData?.data;
2257
+ const revertFlags = errorData?.flags;
2258
+ if (isBareRevertResult(revertData, revertFlags)) return null;
2259
+ throw new Error(formatContractDryRunFailure({
2260
+ revertData,
2261
+ revertFlags,
2262
+ gasConsumed: callResult.gasConsumed,
2263
+ gasRequired: callResult.gasRequired,
2264
+ storageDeposit: callResult.storageDeposit?.value
2265
+ }, {
2266
+ contractAddress,
2267
+ functionName: "isAuthorised",
2268
+ signerSubstrateAddress: this.substrateAddress,
2269
+ signerEvmAddress: this.evmAddress ?? void 0,
2270
+ value: 0n,
2271
+ encodedData: encodedCallData,
2272
+ args: [node, account],
2273
+ contracts: this._contracts
2274
+ }));
2275
+ }
2276
+ /**
2277
+ * Ask the registry who may write `node`, per DotnsRegistry.isAuthorised —
2278
+ * the contract's own "single source of truth" for owner-gated entry
2279
+ * points (setSubnodeOwner, setSubnodeResolver, setResolver): a non-zero
2280
+ * stored subnode owner must equal `account`; otherwise, for a tokenised
2281
+ * node, the registrar's ERC-721 owner, an operator-for-all delegate, or a
2282
+ * single-token approval all qualify. Strictly wider than a raw
2283
+ * owner()-equality test, which refuses an approved/operator delegate the
2284
+ * chain would accept — the contract's own comment calls operator-for-all
2285
+ * "the common marketplace / escrow delegation path".
2286
+ *
2287
+ * Falls back to owner()-equality when isAuthorised is absent from this
2288
+ * registry deployment (a bare revert on the probe) so a missing accessor
2289
+ * never turns into a refusal. `owner` is always the node's registry-read
2290
+ * owner (for informative messaging), independent of which path decided
2291
+ * `authorised`.
2292
+ */
2293
+ async checkNodeAuthorization(node, account) {
2294
+ this.ensureConnected();
2295
+ const owner = await withTimeout(
2296
+ this.contractCallNullable(this._contracts.DOTNS_REGISTRY, DOTNS_REGISTRY_ABI, "owner", [node]),
2297
+ 3e4,
2298
+ "owner"
2299
+ );
2300
+ const authorised = await this.probeIsAuthorised(node, account);
2301
+ if (authorised !== null) return { authorised, owner };
2302
+ return { authorised: owner !== null && owner.toLowerCase() === account.toLowerCase(), owner };
2303
+ }
2219
2304
  /** Live transfer-fee quote. transferFloor is a pure PopRules view — it
2220
2305
  * classifies the label and reads both tiers, so it works BEFORE the name is
2221
2306
  * registered (unlike quoteTransferFee, which reverts on an unregistered token). */
@@ -2266,9 +2351,12 @@ var DotNS = class _DotNS {
2266
2351
  * transferName/transferFrom — the registrar has no token for them. Instead
2267
2352
  * the *parent-domain* owner reassigns a subname via the registry's
2268
2353
  * setSubnodeOwner (the same call registerSubdomain uses to create it).
2269
- * Authorisation is on parent ownership, not on the subname's current owner,
2270
- * so the connected signer must own `${parentLabel}.${this._tld}`. Idempotent:
2271
- * a no-op when the recipient already owns it.
2354
+ * Authorisation is on the parent node, not on the subname's current owner
2355
+ * checked via the registry's own isAuthorised(parentNode, account)
2356
+ * (checkNodeAuthorization), so the connected signer may be the parent's
2357
+ * owner OR an operator-for-all/single-token approval on it, matching what
2358
+ * the chain itself allows on setSubnodeOwner. Idempotent: a no-op when the
2359
+ * recipient already owns it.
2272
2360
  *
2273
2361
  * Every node here is derived via computeSubnodeIds, which routes through the
2274
2362
  * single ensNode() primitive (#1304, see the comment above ensNode) — the
@@ -2284,17 +2372,13 @@ var DotNS = class _DotNS {
2284
2372
  const fullName = `${sublabel}.${parentLabel}.${this._tld}`;
2285
2373
  assertNotZeroRecipient(toH160, fullName);
2286
2374
  const { parentNode, subnode } = computeSubnodeIds(sublabel, parentLabel, this._tld);
2287
- const parentOwner = await withTimeout(
2288
- this.contractCallNullable(this._contracts.DOTNS_REGISTRY, DOTNS_REGISTRY_ABI, "owner", [parentNode]),
2289
- 3e4,
2290
- "owner"
2291
- );
2375
+ const { authorised: parentAuthorised, owner: parentOwner } = await this.checkNodeAuthorization(parentNode, this.evmAddress);
2292
2376
  if (!parentOwner || parentOwner === zeroAddress) {
2293
2377
  throw new Error(`Cannot transfer ${fullName}: parent ${parentLabel}.${this._tld} is not registered.`);
2294
2378
  }
2295
- if (parentOwner.toLowerCase() !== this.evmAddress.toLowerCase()) {
2379
+ if (!parentAuthorised) {
2296
2380
  throw new Error(
2297
- `Cannot transfer ${fullName}: it is a subname, which only the owner of the parent ${parentLabel}.${this._tld} can reassign (subnames are not transferable tokens). Parent is owned by ${parentOwner}, but the signer is ${this.evmAddress}. Sign as the parent owner (e.g. pass its --mnemonic).`
2381
+ `Cannot transfer ${fullName}: it is a subname, which only the owner of the parent ${parentLabel}.${this._tld} (or an account it has approved) can reassign (subnames are not transferable tokens). Parent is owned by ${parentOwner}, but the signer is ${this.evmAddress} and is not approved. Sign as the parent owner, or as an approved account (e.g. pass its --mnemonic).`
2298
2382
  );
2299
2383
  }
2300
2384
  const current = await withTimeout(
@@ -4,10 +4,10 @@ import {
4
4
  } from "./chunk-5FLTDWWP.js";
5
5
  import {
6
6
  DEFAULT_MNEMONIC
7
- } from "./chunk-FJTZNSNU.js";
7
+ } from "./chunk-2GKEZI5B.js";
8
8
  import {
9
9
  DOT_PRODUCT_ID
10
- } from "./chunk-Q7CHACT6.js";
10
+ } from "./chunk-CWLLC46X.js";
11
11
 
12
12
  // src/deploy-actors.ts
13
13
  var DEFAULT_WORKER_SURI = DEFAULT_MNEMONIC;
@@ -13,13 +13,13 @@ import {
13
13
  setBulletinEndpoints,
14
14
  storeDirectory,
15
15
  storeFile
16
- } from "./chunk-Q6NVSUCX.js";
16
+ } from "./chunk-FWMFCXIB.js";
17
17
  import {
18
18
  DEFAULT_TLD,
19
19
  DotNS,
20
20
  TX_KIND_SKIPPED,
21
21
  stripTldSuffix
22
- } from "./chunk-FJTZNSNU.js";
22
+ } from "./chunk-2GKEZI5B.js";
23
23
  import {
24
24
  DEFAULT_ENV_ID,
25
25
  getPopSelfServeConfig,
@@ -33,7 +33,7 @@ import {
33
33
  setDeployAttribute,
34
34
  withManifestSpan,
35
35
  withSpan
36
- } from "./chunk-HIODF4QF.js";
36
+ } from "./chunk-DOLHX2AM.js";
37
37
 
38
38
  // src/manifest/publish.ts
39
39
  import * as fs2 from "fs/promises";
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-HDGD5FYX.js";
7
7
  import {
8
8
  VERSION
9
- } from "./chunk-HIODF4QF.js";
9
+ } from "./chunk-DOLHX2AM.js";
10
10
 
11
11
  // src/auth-config.ts
12
12
  import { existsSync, readdirSync } from "fs";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-GRPLHUYC.js";
4
4
  import {
5
5
  DOT_DAPP_ID
6
- } from "./chunk-Q7CHACT6.js";
6
+ } from "./chunk-CWLLC46X.js";
7
7
 
8
8
  // src/sss-allowance-cache.ts
9
9
  import { mkdir, readFile, writeFile, unlink } from "fs/promises";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  package_default,
3
3
  writeRunState
4
- } from "./chunk-SSV2KD3B.js";
4
+ } from "./chunk-QCZKXFCY.js";
5
5
 
6
6
  // src/memory-report.ts
7
7
  import * as fs2 from "fs";
@@ -1,9 +1,12 @@
1
+ import {
2
+ subnameNestingLevels
3
+ } from "./chunk-HNJWIY55.js";
1
4
  import {
2
5
  deriveProductSigner
3
6
  } from "./chunk-M5AKL3FL.js";
4
7
  import {
5
8
  preflightSssAllowance
6
- } from "./chunk-RULOELNF.js";
9
+ } from "./chunk-D6ONN6VJ.js";
7
10
  import {
8
11
  statementSigningAccount
9
12
  } from "./chunk-GRPLHUYC.js";
@@ -29,18 +32,18 @@ import {
29
32
  } from "./chunk-WPC2PUCV.js";
30
33
  import {
31
34
  setDeployContext
32
- } from "./chunk-3BDYD4BG.js";
35
+ } from "./chunk-W76SHNTO.js";
33
36
  import {
34
37
  getBestBlockNumber,
35
38
  probeChunks,
36
39
  probeFinalityGap
37
- } from "./chunk-64UKPUK4.js";
40
+ } from "./chunk-ZHSULISU.js";
38
41
  import {
39
42
  packSection
40
43
  } from "./chunk-C2TS5MER.js";
41
44
  import {
42
45
  resolveStorageSigner
43
- } from "./chunk-2WGCBESY.js";
46
+ } from "./chunk-6BNYZN7R.js";
44
47
  import {
45
48
  createSlotAccountSigner,
46
49
  requestResourceAllocation
@@ -50,12 +53,13 @@ import {
50
53
  DotNS,
51
54
  TX_TIMEOUT_MS,
52
55
  classifyRegistrability,
56
+ computeDomainNode,
53
57
  fetchNonce,
54
58
  formatUnregistrableReason,
55
59
  parseDomainName,
56
60
  popStatusName,
57
61
  verifyNonceAdvanced
58
- } from "./chunk-FJTZNSNU.js";
62
+ } from "./chunk-2GKEZI5B.js";
59
63
  import {
60
64
  derivePoolAccounts,
61
65
  detectTestnet,
@@ -69,7 +73,7 @@ import {
69
73
  STALE_SESSION_MESSAGE,
70
74
  getPeopleChainEndpoints,
71
75
  hasPersistedSession
72
- } from "./chunk-Q7CHACT6.js";
76
+ } from "./chunk-CWLLC46X.js";
73
77
  import {
74
78
  CLI_NAME
75
79
  } from "./chunk-TSPERKUS.js";
@@ -84,7 +88,7 @@ import {
84
88
  } from "./chunk-ZOC4GITL.js";
85
89
  import {
86
90
  ChainHealthSampler
87
- } from "./chunk-6HPDXI7E.js";
91
+ } from "./chunk-IAPBFRWN.js";
88
92
  import {
89
93
  VERSION,
90
94
  captureWarning,
@@ -98,7 +102,7 @@ import {
98
102
  truncateAddress,
99
103
  withDeploySpan,
100
104
  withSpan
101
- } from "./chunk-HIODF4QF.js";
105
+ } from "./chunk-DOLHX2AM.js";
102
106
 
103
107
  // src/merkle.ts
104
108
  import * as fs2 from "fs";
@@ -2025,11 +2029,18 @@ function assertSubdomainOwnerMatchesSigner(result, signerEvmAddress, sublabel, p
2025
2029
  }
2026
2030
  }
2027
2031
  function formatSubdomainParentError(fullName, parentLabel, parentOwner, selfAddress, tld = DEFAULT_TLD, profile = "poprules-startingPrice") {
2028
- if (parentOwner !== null) {
2029
- const transferBullet = selfAddress ? ` - ask the ${parentOwner} account to hand the parent to this signer, run BY that account: ${CLI_NAME} transfer ${parentLabel}.${tld} --to ${selfAddress} --mnemonic <the ${parentOwner} account's key>
2032
+ const owner = parentOwner !== null && /^0x0{40}$/i.test(parentOwner) ? null : parentOwner;
2033
+ const parentIsNested = parentLabel.includes(".");
2034
+ if (owner === null && parentIsNested) {
2035
+ return `Cannot deploy ${fullName}: parent ${parentLabel}.${tld} does not exist.
2036
+
2037
+ It is itself a subname, so it cannot be registered directly \u2014 whoever owns ${parentLabel.slice(parentLabel.indexOf(".") + 1)}.${tld} has to create it first, then hand it to this signer (${selfAddress || "this account"}).`;
2038
+ }
2039
+ if (owner !== null) {
2040
+ const transferBullet = selfAddress ? ` - ask the ${owner} account to hand the parent to this signer, run BY that account: ${CLI_NAME} transfer ${parentLabel}.${tld} --to ${selfAddress} --mnemonic <the ${owner} account's key>
2030
2041
  ` : "";
2031
2042
  const ownedParentBullet = ` - deploy the subdomain under a parent this signer already owns instead.`;
2032
- return `Cannot deploy ${fullName}: parent ${parentLabel}.${tld} is owned by ${parentOwner}, not by this signer.
2043
+ return `Cannot deploy ${fullName}: parent ${parentLabel}.${tld} is owned by ${owner}, not by this signer.
2033
2044
 
2034
2045
  ` + (transferBullet ? `Either:
2035
2046
  ${transferBullet}${ownedParentBullet}` : ownedParentBullet);
@@ -2158,6 +2169,10 @@ async function deploy(content, domainName = null, options = {}) {
2158
2169
  _deployRpcFailedOver = false;
2159
2170
  POOL_SIZE = options.poolSize ?? parseInt(process.env.BULLETIN_POOL_SIZE ?? String(DEFAULT_POOL_SIZE), 10);
2160
2171
  let parsed = domainName ? parseDomainName(domainName, envTld) : null;
2172
+ if (parsed?.isSubdomain && parsed.parentLabel.includes(".")) {
2173
+ const levels = subnameNestingLevels(1 + parsed.parentLabel.split(".").length);
2174
+ console.log(` NOTE: "${domainName}" parses as sublabel "${parsed.sublabel}" under parent path "${parsed.parentLabel}.${envTld}" (${levels} levels of subname nesting).`);
2175
+ }
2161
2176
  let sessionCleanup;
2162
2177
  const hasSession = hasPersistedSession();
2163
2178
  const signerChoice = chooseSignerInput({
@@ -2264,6 +2279,9 @@ async function deploy(content, domainName = null, options = {}) {
2264
2279
  setDeployAttribute("deploy.env", envId);
2265
2280
  setDeployAttribute("deploy.label", parsed?.label ?? name);
2266
2281
  setDeployAttribute("deploy.subdomain", String(parsed?.isSubdomain ?? false));
2282
+ if (parsed?.isSubdomain) {
2283
+ setDeployAttribute("deploy.dotns.subname_levels", subnameNestingLevels(1 + parsed.parentLabel.split(".").length));
2284
+ }
2267
2285
  if (envNetwork) setDeployAttribute("deploy.network", envNetwork);
2268
2286
  if (envSource) setDeployAttribute("deploy.environments_source", envSource);
2269
2287
  setDeployAttribute("deploy.transfer.enabled", options.transferTo ? "true" : "false");
@@ -2296,8 +2314,9 @@ async function deploy(content, domainName = null, options = {}) {
2296
2314
  const subResult = await preflight.checkSubdomainOwnership(parsed.sublabel, parsed.parentLabel);
2297
2315
  assertSubdomainOwnerMatchesSigner(subResult, preflight.evmAddress, parsed.sublabel, parsed.parentLabel, envTld);
2298
2316
  if (!subResult.owned) {
2299
- const { owned: parentOwned, owner: parentOwner } = await preflight.checkOwnership(parsed.parentLabel);
2300
- if (!parentOwned) {
2317
+ const parentNode = computeDomainNode(parsed.parentLabel, envTld);
2318
+ const { authorised: parentAuthorised, owner: parentOwner } = await preflight.checkNodeAuthorization(parentNode, preflight.evmAddress);
2319
+ if (!parentAuthorised) {
2301
2320
  throw new NonRetryableError(
2302
2321
  formatSubdomainParentError(parsed.fullName, parsed.parentLabel, parentOwner ?? null, preflight.evmAddress ?? "", envTld, preflight.protocolVersion)
2303
2322
  );
@@ -2554,8 +2573,9 @@ async function deploy(content, domainName = null, options = {}) {
2554
2573
  } else if (owner) {
2555
2574
  throw new Error(`Subdomain ${parsed.fullName} is owned by ${owner}, not ${dotns.evmAddress}`);
2556
2575
  } else {
2557
- const parentOwnership = await dotns.checkOwnership(parsed.parentLabel);
2558
- if (!parentOwnership.owned) throw new Error(`You must own ${parsed.parentLabel}.${envTld} to register subdomains under it`);
2576
+ const parentNode = computeDomainNode(parsed.parentLabel, envTld);
2577
+ const { authorised: parentAuthorised } = await dotns.checkNodeAuthorization(parentNode, dotns.evmAddress);
2578
+ if (!parentAuthorised) throw new Error(`You must own (or be approved for) ${parsed.parentLabel}.${envTld} to register subdomains under it`);
2559
2579
  console.log(` Status: Registering subdomain...`);
2560
2580
  await dotns.registerSubdomain(parsed.sublabel, parsed.parentLabel);
2561
2581
  registeredFresh = true;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-HIODF4QF.js";
3
+ } from "./chunk-DOLHX2AM.js";
4
4
 
5
5
  // src/version-check.ts
6
6
  import { execSync, execFileSync } from "child_process";
@@ -0,0 +1,8 @@
1
+ // src/subname-depth.ts
2
+ function subnameNestingLevels(labelsBeforeTld) {
3
+ return labelsBeforeTld - 1;
4
+ }
5
+
6
+ export {
7
+ subnameNestingLevels
8
+ };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  emitIntervalSpan,
3
3
  setDeployAttribute
4
- } from "./chunk-HIODF4QF.js";
4
+ } from "./chunk-DOLHX2AM.js";
5
5
 
6
6
  // src/chain-health.ts
7
7
  var DEFAULT_WINDOW_BLOCKS = 10;
@@ -6,7 +6,7 @@ import * as path from "path";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "bulletin-deploy",
9
- version: "0.18.1-rc.1",
9
+ version: "0.18.2",
10
10
  private: false,
11
11
  repository: {
12
12
  type: "git",
@@ -52,7 +52,7 @@ var package_default = {
52
52
  "tools/verify-baked-dsn.mjs"
53
53
  ],
54
54
  scripts: {
55
- build: "tsup src/suppress-localstorage-warning.ts src/index.ts src/deploy.ts src/dotns.ts src/dotns-protocol.ts src/pool.ts src/telemetry.ts src/chain-health.ts src/memory-report.ts src/merkle.ts src/version-check.ts src/bug-report.ts src/run-state.ts src/environments.ts src/errors.ts src/manifest.ts src/chunk-probe.ts src/manifest-embed.ts src/manifest-fetch.ts src/manifest-roundtrip.ts src/incremental-stats.ts src/chunker.ts src/personhood/encoding.ts src/personhood/hashing.ts src/personhood/constants.ts src/personhood/member-key.ts src/personhood/people-client.ts src/personhood/proof-validity.ts src/personhood/ring-proof.ts src/personhood/reprove.ts src/personhood/bind-personal-id.ts src/personhood/claim-pgas.ts src/personhood/bind-paid-alias.ts src/personhood/bootstrap.ts src/personhood/chain-prereqs.ts src/manifest/types.ts src/manifest/schema.ts src/manifest/byte-budget.ts src/manifest/config-load.ts src/manifest/publish.ts src/auth/index.ts src/auth/vendor/index.ts src/auth/vendor/ui/index.ts src/auth-config.ts src/commands/login.ts src/commands/logout.ts src/commands/whoami.ts src/commands/transfer.ts src/storage-signer.ts src/spinner.ts src/sss-allowance.ts src/sss-allowance-cache.ts src/deploy-actors.ts src/product-account.ts --format esm --dts --clean --target node22",
55
+ build: "tsup src/suppress-localstorage-warning.ts src/index.ts src/deploy.ts src/dotns.ts src/dotns-protocol.ts src/pool.ts src/telemetry.ts src/chain-health.ts src/memory-report.ts src/merkle.ts src/version-check.ts src/bug-report.ts src/run-state.ts src/environments.ts src/errors.ts src/subname-depth.ts src/manifest.ts src/chunk-probe.ts src/manifest-embed.ts src/manifest-fetch.ts src/manifest-roundtrip.ts src/incremental-stats.ts src/chunker.ts src/personhood/encoding.ts src/personhood/hashing.ts src/personhood/constants.ts src/personhood/member-key.ts src/personhood/people-client.ts src/personhood/proof-validity.ts src/personhood/ring-proof.ts src/personhood/reprove.ts src/personhood/bind-personal-id.ts src/personhood/claim-pgas.ts src/personhood/bind-paid-alias.ts src/personhood/bootstrap.ts src/personhood/chain-prereqs.ts src/manifest/types.ts src/manifest/schema.ts src/manifest/byte-budget.ts src/manifest/config-load.ts src/manifest/publish.ts src/auth/index.ts src/auth/vendor/index.ts src/auth/vendor/ui/index.ts src/auth-config.ts src/commands/login.ts src/commands/logout.ts src/commands/whoami.ts src/commands/transfer.ts src/storage-signer.ts src/spinner.ts src/sss-allowance.ts src/sss-allowance-cache.ts src/deploy-actors.ts src/product-account.ts --format esm --dts --clean --target node22",
56
56
  "refresh-environments": "node scripts/refresh-environments.mjs",
57
57
  postinstall: "patch-package || true",
58
58
  prepare: "npm run build",
@@ -2,15 +2,15 @@ import {
2
2
  classifyErrorArea,
3
3
  isInteractive,
4
4
  promptYesNo
5
- } from "./chunk-UPQ2JGIO.js";
5
+ } from "./chunk-H3ZDWTNY.js";
6
6
  import {
7
7
  VERSION,
8
8
  getCurrentSentryTraceId,
9
9
  resolveIssueRepoSlug
10
- } from "./chunk-HIODF4QF.js";
10
+ } from "./chunk-DOLHX2AM.js";
11
11
  import {
12
12
  package_default
13
- } from "./chunk-SSV2KD3B.js";
13
+ } from "./chunk-QCZKXFCY.js";
14
14
 
15
15
  // src/bug-report.ts
16
16
  import { execSync, execFileSync } from "child_process";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  captureWarning
3
- } from "./chunk-HIODF4QF.js";
3
+ } from "./chunk-DOLHX2AM.js";
4
4
 
5
5
  // src/chunk-probe.ts
6
6
  import { Twox128, Blake2128Concat, decAnyMetadata, unifyMetadata } from "@polkadot-api/substrate-bindings";
@@ -8,9 +8,9 @@ import {
8
8
  getBestBlockNumber,
9
9
  probeChunks,
10
10
  probeFinalityGap
11
- } from "./chunk-64UKPUK4.js";
12
- import "./chunk-HIODF4QF.js";
13
- import "./chunk-SSV2KD3B.js";
11
+ } from "./chunk-ZHSULISU.js";
12
+ import "./chunk-DOLHX2AM.js";
13
+ import "./chunk-QCZKXFCY.js";
14
14
  export {
15
15
  ChainProbeCrossValidationError,
16
16
  ChainProbeMetadataError,
@@ -4,11 +4,12 @@ import {
4
4
  import {
5
5
  isBenignTeardownError,
6
6
  waitForBulletinAuthorization
7
- } from "../chunk-Q6NVSUCX.js";
7
+ } from "../chunk-FWMFCXIB.js";
8
+ import "../chunk-HNJWIY55.js";
8
9
  import "../chunk-M5AKL3FL.js";
9
10
  import {
10
11
  preflightSssAllowance
11
- } from "../chunk-RULOELNF.js";
12
+ } from "../chunk-D6ONN6VJ.js";
12
13
  import {
13
14
  statementSigningAccount
14
15
  } from "../chunk-GRPLHUYC.js";
@@ -16,11 +17,11 @@ import "../chunk-IW3X2MJF.js";
16
17
  import "../chunk-LPTKBQII.js";
17
18
  import "../chunk-3MAIF2SF.js";
18
19
  import "../chunk-WPC2PUCV.js";
19
- import "../chunk-3BDYD4BG.js";
20
- import "../chunk-UPQ2JGIO.js";
21
- import "../chunk-64UKPUK4.js";
20
+ import "../chunk-W76SHNTO.js";
21
+ import "../chunk-H3ZDWTNY.js";
22
+ import "../chunk-ZHSULISU.js";
22
23
  import "../chunk-C2TS5MER.js";
23
- import "../chunk-2WGCBESY.js";
24
+ import "../chunk-6BNYZN7R.js";
24
25
  import "../chunk-JQKKMUCT.js";
25
26
  import {
26
27
  BULLETIN_RESOURCE,
@@ -32,7 +33,7 @@ import {
32
33
  import {
33
34
  renderLoginStatus
34
35
  } from "../chunk-RIRDBSBG.js";
35
- import "../chunk-FJTZNSNU.js";
36
+ import "../chunk-2GKEZI5B.js";
36
37
  import "../chunk-SI2ZUOYD.js";
37
38
  import "../chunk-AYAVRPAP.js";
38
39
  import {
@@ -40,7 +41,7 @@ import {
40
41
  getAuthClient,
41
42
  getPeopleChainEndpoints,
42
43
  resolveBulletinEndpoints
43
- } from "../chunk-Q7CHACT6.js";
44
+ } from "../chunk-CWLLC46X.js";
44
45
  import {
45
46
  CLI_NAME
46
47
  } from "../chunk-TSPERKUS.js";
@@ -48,9 +49,9 @@ import {
48
49
  loadEnvironments
49
50
  } from "../chunk-HDGD5FYX.js";
50
51
  import "../chunk-ZOC4GITL.js";
51
- import "../chunk-6HPDXI7E.js";
52
- import "../chunk-HIODF4QF.js";
53
- import "../chunk-SSV2KD3B.js";
52
+ import "../chunk-IAPBFRWN.js";
53
+ import "../chunk-DOLHX2AM.js";
54
+ import "../chunk-QCZKXFCY.js";
54
55
  import "../chunk-7I3MTGOR.js";
55
56
 
56
57
  // src/commands/login.ts
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  clearSssAllowanceCache
3
- } from "../chunk-RULOELNF.js";
3
+ } from "../chunk-D6ONN6VJ.js";
4
4
  import "../chunk-GRPLHUYC.js";
5
5
  import "../chunk-JQKKMUCT.js";
6
6
  import "../chunk-5FLTDWWP.js";
@@ -9,12 +9,12 @@ import {
9
9
  } from "../chunk-RIRDBSBG.js";
10
10
  import {
11
11
  getAuthClient
12
- } from "../chunk-Q7CHACT6.js";
12
+ } from "../chunk-CWLLC46X.js";
13
13
  import "../chunk-TSPERKUS.js";
14
14
  import "../chunk-HDGD5FYX.js";
15
15
  import "../chunk-ZOC4GITL.js";
16
- import "../chunk-HIODF4QF.js";
17
- import "../chunk-SSV2KD3B.js";
16
+ import "../chunk-DOLHX2AM.js";
17
+ import "../chunk-QCZKXFCY.js";
18
18
 
19
19
  // src/commands/logout.ts
20
20
  function formatLogout(status) {
@@ -3,7 +3,7 @@ import {
3
3
  DEFAULT_TLD,
4
4
  DotNS,
5
5
  parseDomainName
6
- } from "../chunk-FJTZNSNU.js";
6
+ } from "../chunk-2GKEZI5B.js";
7
7
  import "../chunk-SI2ZUOYD.js";
8
8
  import "../chunk-AYAVRPAP.js";
9
9
  import {
@@ -15,9 +15,9 @@ import {
15
15
  resolveEndpoints
16
16
  } from "../chunk-HDGD5FYX.js";
17
17
  import "../chunk-ZOC4GITL.js";
18
- import "../chunk-6HPDXI7E.js";
19
- import "../chunk-HIODF4QF.js";
20
- import "../chunk-SSV2KD3B.js";
18
+ import "../chunk-IAPBFRWN.js";
19
+ import "../chunk-DOLHX2AM.js";
20
+ import "../chunk-QCZKXFCY.js";
21
21
  import "../chunk-7I3MTGOR.js";
22
22
 
23
23
  // src/commands/transfer.ts