bulletin-deploy 0.7.2 → 0.7.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.
@@ -9,9 +9,9 @@ import {
9
9
  offerBugReport,
10
10
  scrubSecrets,
11
11
  setDeployContext
12
- } from "./chunk-LMSMDKVU.js";
13
- import "./chunk-4UNQGG3O.js";
14
- import "./chunk-4FUUYJP2.js";
12
+ } from "./chunk-4EQERQRG.js";
13
+ import "./chunk-MDYSENTW.js";
14
+ import "./chunk-BYIVK52G.js";
15
15
  import "./chunk-QGM4M3NI.js";
16
16
  export {
17
17
  buildCliFlagsSummary,
@@ -2,11 +2,11 @@ import {
2
2
  classifyErrorArea,
3
3
  isInteractive,
4
4
  promptYesNo
5
- } from "./chunk-4UNQGG3O.js";
5
+ } from "./chunk-MDYSENTW.js";
6
6
  import {
7
7
  VERSION,
8
8
  getCurrentSentryTraceId
9
- } from "./chunk-4FUUYJP2.js";
9
+ } from "./chunk-BYIVK52G.js";
10
10
 
11
11
  // src/bug-report.ts
12
12
  import { execSync, execFileSync } from "child_process";
@@ -13,7 +13,7 @@ import * as path from "path";
13
13
  // package.json
14
14
  var package_default = {
15
15
  name: "bulletin-deploy",
16
- version: "0.7.2",
16
+ version: "0.7.3",
17
17
  private: false,
18
18
  repository: {
19
19
  type: "git",
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  setDeployContext
3
- } from "./chunk-LMSMDKVU.js";
3
+ } from "./chunk-4EQERQRG.js";
4
4
  import {
5
5
  DotNS,
6
6
  TX_TIMEOUT_MS,
7
7
  fetchNonce,
8
- popStatusName,
9
- validateDomainLabel
10
- } from "./chunk-NEV6WTYM.js";
8
+ parseDomainName,
9
+ popStatusName
10
+ } from "./chunk-M3H3F4FY.js";
11
11
  import {
12
12
  MirrorSkipped,
13
13
  mirrorToGitHubPages,
@@ -26,7 +26,7 @@ import {
26
26
  truncateAddress,
27
27
  withDeploySpan,
28
28
  withSpan
29
- } from "./chunk-4FUUYJP2.js";
29
+ } from "./chunk-BYIVK52G.js";
30
30
  import {
31
31
  merkleizeJS
32
32
  } from "./chunk-B7GUYYAN.js";
@@ -669,8 +669,8 @@ async function deploy(content, domainName = null, options = {}) {
669
669
  POOL_SIZE = options.poolSize ?? parseInt(process.env.BULLETIN_POOL_SIZE ?? String(DEFAULT_POOL_SIZE), 10);
670
670
  initTelemetry();
671
671
  const randomSuffix = Math.floor(Math.random() * 100).toString().padStart(2, "0");
672
- const rawName = domainName ? domainName.replace(".dot", "") : `test-domain-${Date.now().toString(36)}${randomSuffix}`;
673
- const name = validateDomainLabel(rawName);
672
+ const parsed = domainName ? parseDomainName(domainName) : null;
673
+ const name = parsed ? parsed.label : `test-domain-${Date.now().toString(36)}${randomSuffix}`;
674
674
  return withDeploySpan(name, async () => {
675
675
  const deployTag = options.tag ?? process.env.DEPLOY_TAG;
676
676
  if (deployTag) {
@@ -714,26 +714,43 @@ async function deploy(content, domainName = null, options = {}) {
714
714
  );
715
715
  }
716
716
  console.log(` Account: mapped`);
717
- let dotnsPreflight;
718
- try {
719
- dotnsPreflight = await preflight.preflight(name);
720
- } finally {
721
- preflight.disconnect();
722
- }
723
- console.log(` DotNS: ${name}.dot classifies as ${popStatusName(dotnsPreflight.classification.status)}`);
724
- if (dotnsPreflight.canProceed) {
725
- const fromName = popStatusName(dotnsPreflight.userStatus);
726
- if (dotnsPreflight.needsPopUpgrade && dotnsPreflight.targetPopStatus !== void 0) {
727
- console.log(` PoP: ${fromName} \u2192 will upgrade to ${popStatusName(dotnsPreflight.targetPopStatus)}`);
728
- } else {
729
- console.log(` PoP: ${fromName} (no upgrade required)`);
717
+ if (parsed?.isSubdomain) {
718
+ try {
719
+ const { owned: subOwned } = await preflight.checkSubdomainOwnership(parsed.sublabel, parsed.parentLabel);
720
+ if (!subOwned) {
721
+ const { owned: parentOwned, owner: parentOwner } = await preflight.checkOwnership(parsed.parentLabel);
722
+ if (!parentOwned) {
723
+ throw new NonRetryableError(
724
+ `Cannot deploy ${parsed.fullName}: parent ${parsed.parentLabel}.dot is owned by ${parentOwner ?? "no one"}, not by this signer.`
725
+ );
726
+ }
727
+ }
728
+ } finally {
729
+ preflight.disconnect();
730
+ }
731
+ console.log(` Mode: subdomain (parent ${parsed.parentLabel}.dot owned by signer)`);
732
+ } else {
733
+ let dotnsPreflight;
734
+ try {
735
+ dotnsPreflight = await preflight.preflight(name);
736
+ } finally {
737
+ preflight.disconnect();
738
+ }
739
+ console.log(` DotNS: ${name}.dot classifies as ${popStatusName(dotnsPreflight.classification.status)}`);
740
+ if (dotnsPreflight.canProceed) {
741
+ const fromName = popStatusName(dotnsPreflight.userStatus);
742
+ if (dotnsPreflight.needsPopUpgrade && dotnsPreflight.targetPopStatus !== void 0) {
743
+ console.log(` PoP: ${fromName} \u2192 will upgrade to ${popStatusName(dotnsPreflight.targetPopStatus)}`);
744
+ } else {
745
+ console.log(` PoP: ${fromName} (no upgrade required)`);
746
+ }
747
+ console.log(` Domain: ${dotnsPreflight.plannedAction === "already-owned-by-us" ? "owned by you" : "available"}`);
748
+ }
749
+ if (!dotnsPreflight.canProceed) {
750
+ throw new NonRetryableError(
751
+ dotnsPreflight.reason ?? "DotNS preflight rejected the deploy; please check the label and signer."
752
+ );
730
753
  }
731
- console.log(` Domain: ${dotnsPreflight.plannedAction === "already-owned-by-us" ? "owned by you" : "available"}`);
732
- }
733
- if (!dotnsPreflight.canProceed) {
734
- throw new NonRetryableError(
735
- dotnsPreflight.reason ?? "DotNS preflight rejected the deploy; please check the label and signer."
736
- );
737
754
  }
738
755
  provider = await reconnect();
739
756
  const providerWithReconnect = { ...provider, reconnect };
@@ -844,17 +861,31 @@ async function deploy(content, domainName = null, options = {}) {
844
861
  console.log("\n" + "=".repeat(60));
845
862
  console.log("DotNS");
846
863
  console.log("=".repeat(60));
847
- await withSpan("deploy.dotns", "2. dotns", { "deploy.domain": name }, async () => {
864
+ await withSpan("deploy.dotns", "2. dotns", { "deploy.domain": name, "deploy.subdomain": String(parsed?.isSubdomain ?? false) }, async () => {
848
865
  const dotns = new DotNS();
849
866
  await dotns.connect(
850
867
  options.signer && options.signerAddress ? { signer: options.signer, signerAddress: options.signerAddress } : options.mnemonic ? { mnemonic: options.mnemonic, derivationPath: options.derivationPath } : {}
851
868
  );
852
- const { owned } = await dotns.checkOwnership(name);
853
- if (owned) {
854
- console.log(` Status: Already owned`);
869
+ if (parsed?.isSubdomain) {
870
+ const { owned, owner } = await dotns.checkSubdomainOwnership(parsed.sublabel, parsed.parentLabel);
871
+ if (owned) {
872
+ console.log(` Status: Already owned`);
873
+ } else if (owner) {
874
+ throw new Error(`Subdomain ${parsed.fullName} is owned by ${owner}, not ${dotns.evmAddress}`);
875
+ } else {
876
+ const parentOwnership = await dotns.checkOwnership(parsed.parentLabel);
877
+ if (!parentOwnership.owned) throw new Error(`You must own ${parsed.parentLabel}.dot to register subdomains under it`);
878
+ console.log(` Status: Registering subdomain...`);
879
+ await dotns.registerSubdomain(parsed.sublabel, parsed.parentLabel);
880
+ }
855
881
  } else {
856
- console.log(` Status: Registering...`);
857
- await dotns.register(name);
882
+ const { owned } = await dotns.checkOwnership(name);
883
+ if (owned) {
884
+ console.log(` Status: Already owned`);
885
+ } else {
886
+ console.log(` Status: Registering...`);
887
+ await dotns.register(name);
888
+ }
858
889
  }
859
890
  const contenthashHex = `0x${encodeContenthash(cid)}`;
860
891
  await dotns.setContenthash(name, contenthashHex);
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  captureWarning,
3
3
  withSpan
4
- } from "./chunk-4FUUYJP2.js";
4
+ } from "./chunk-BYIVK52G.js";
5
5
  import {
6
6
  isTestnetSpecName
7
7
  } from "./chunk-JHNW2EKY.js";
@@ -116,6 +116,11 @@ var POP_RULES_ABI = [
116
116
  { inputs: [{ name: "status", type: "uint8" }], name: "setUserPopStatus", outputs: [], stateMutability: "nonpayable", type: "function" },
117
117
  { inputs: [{ name: "baseName", type: "string" }], name: "isBaseNameReserved", outputs: [{ name: "isReserved", type: "bool" }, { name: "reservationOwner", type: "address" }, { name: "expiryTimestamp", type: "uint64" }], stateMutability: "view", type: "function" }
118
118
  ];
119
+ var DOTNS_REGISTRY_ABI = [
120
+ { 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" },
121
+ { inputs: [{ name: "node", type: "bytes32" }, { name: "newResolver", type: "address" }], name: "setResolver", outputs: [], stateMutability: "nonpayable", type: "function" },
122
+ { inputs: [{ name: "node", type: "bytes32" }], name: "owner", outputs: [{ name: "", type: "address" }], stateMutability: "view", type: "function" }
123
+ ];
119
124
  var DOTNS_CONTENT_RESOLVER_ABI = [
120
125
  { inputs: [{ name: "node", type: "bytes32" }, { name: "hash", type: "bytes" }], name: "setContenthash", outputs: [], stateMutability: "nonpayable", type: "function" },
121
126
  { inputs: [{ name: "node", type: "bytes32" }], name: "contenthash", outputs: [{ name: "", type: "bytes" }], stateMutability: "view", type: "function" }
@@ -262,6 +267,20 @@ function simulateUserStatus(currentStatus, requiredStatus, options) {
262
267
  }
263
268
  return currentStatus;
264
269
  }
270
+ function parseDomainName(input) {
271
+ const name = input.replace(/\.dot$/, "");
272
+ const parts = name.split(".");
273
+ if (parts.length === 1) {
274
+ validateDomainLabel(parts[0]);
275
+ return { isSubdomain: false, label: parts[0], sublabel: null, parentLabel: null, fullName: `${parts[0]}.dot` };
276
+ }
277
+ if (parts.length === 2) {
278
+ validateDomainLabel(parts[0]);
279
+ validateDomainLabel(parts[1]);
280
+ return { isSubdomain: true, label: name, sublabel: parts[0], parentLabel: parts[1], fullName: `${name}.dot` };
281
+ }
282
+ throw new Error(`Invalid domain: only one level of subdomains supported (got ${parts.length} labels)`);
283
+ }
265
284
  function parseProofOfPersonhoodStatus(status) {
266
285
  const s = (status ?? "none").toLowerCase();
267
286
  if (s === "none" || s === "nostatus") return ProofOfPersonhoodStatus.NoStatus;
@@ -748,6 +767,35 @@ var DotNS = class {
748
767
  );
749
768
  return typeof result === "string" ? result : result?.toString?.() ?? String(result);
750
769
  }
770
+ async checkSubdomainOwnership(sublabel, parentLabel) {
771
+ this.ensureConnected();
772
+ const node = namehash(`${sublabel}.${parentLabel}.dot`);
773
+ try {
774
+ const owner = await withTimeout(this.contractCall(CONTRACTS.DOTNS_REGISTRY, DOTNS_REGISTRY_ABI, "owner", [node]), 3e4, "owner");
775
+ if (!owner || owner === zeroAddress) return { owned: false, owner: null };
776
+ const owned = owner.toLowerCase() === this.evmAddress.toLowerCase();
777
+ return { owned, owner };
778
+ } catch {
779
+ return { owned: false, owner: null };
780
+ }
781
+ }
782
+ async registerSubdomain(sublabel, parentLabel) {
783
+ return withSpan("deploy.dotns.register-subdomain", `2a. register ${sublabel}.${parentLabel}.dot`, {}, async () => {
784
+ this.ensureConnected();
785
+ console.log(`
786
+ Registering subdomain ${sublabel}.${parentLabel}.dot...`);
787
+ const parentNode = namehash(`${parentLabel}.dot`);
788
+ const subnodeRecord = { parentNode, subLabel: sublabel, parentLabel, owner: this.evmAddress };
789
+ const txHash = await this.contractTransaction(CONTRACTS.DOTNS_REGISTRY, 0n, DOTNS_REGISTRY_ABI, "setSubnodeOwner", [subnodeRecord], (s) => console.log(` ${s}`), { useNoncePolling: true });
790
+ console.log(` Tx: ${txHash}`);
791
+ console.log(` Setting resolver...`);
792
+ const subnodeNode = namehash(`${sublabel}.${parentLabel}.dot`);
793
+ const resolverTxHash = await this.contractTransaction(CONTRACTS.DOTNS_REGISTRY, 0n, DOTNS_REGISTRY_ABI, "setResolver", [subnodeNode, CONTRACTS.DOTNS_CONTENT_RESOLVER], (s) => console.log(` ${s}`), { useNoncePolling: true });
794
+ console.log(` Tx: ${resolverTxHash}`);
795
+ console.log(` Subdomain registered!`);
796
+ return { sublabel, parentLabel, owner: this.evmAddress };
797
+ });
798
+ }
751
799
  async setContenthash(domainName, contenthashHex) {
752
800
  return withSpan("deploy.dotns.set-contenthash", "2b. set-contenthash", {}, async () => {
753
801
  this.ensureConnected();
@@ -992,6 +1040,7 @@ export {
992
1040
  classifyDotnsLabel,
993
1041
  canRegister,
994
1042
  simulateUserStatus,
1043
+ parseDomainName,
995
1044
  parseProofOfPersonhoodStatus,
996
1045
  popStatusName,
997
1046
  DotNS,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-4FUUYJP2.js";
3
+ } from "./chunk-BYIVK52G.js";
4
4
 
5
5
  // src/version-check.ts
6
6
  import { execSync, execFileSync } from "child_process";
package/dist/deploy.js CHANGED
@@ -24,12 +24,12 @@ import {
24
24
  storeChunkedContent,
25
25
  storeDirectory,
26
26
  storeFile
27
- } from "./chunk-VJLTIZ6S.js";
28
- import "./chunk-LMSMDKVU.js";
29
- import "./chunk-4UNQGG3O.js";
30
- import "./chunk-NEV6WTYM.js";
27
+ } from "./chunk-EPNPPAMS.js";
28
+ import "./chunk-4EQERQRG.js";
29
+ import "./chunk-MDYSENTW.js";
30
+ import "./chunk-M3H3F4FY.js";
31
31
  import "./chunk-2Q2WSKFD.js";
32
- import "./chunk-4FUUYJP2.js";
32
+ import "./chunk-BYIVK52G.js";
33
33
  import "./chunk-B7GUYYAN.js";
34
34
  import "./chunk-JHNW2EKY.js";
35
35
  import "./chunk-QGM4M3NI.js";
package/dist/dotns.d.ts CHANGED
@@ -18,6 +18,13 @@ interface PriceValidationResult {
18
18
  userStatus: number;
19
19
  message: string;
20
20
  }
21
+ interface ParsedDomainName {
22
+ isSubdomain: boolean;
23
+ label: string;
24
+ sublabel: string | null;
25
+ parentLabel: string | null;
26
+ fullName: string;
27
+ }
21
28
  interface DotnsPreflightResult {
22
29
  label: string;
23
30
  classification: {
@@ -84,6 +91,7 @@ declare function simulateUserStatus(currentStatus: number, requiredStatus: numbe
84
91
  explicitStatus?: number;
85
92
  isTestnet: boolean;
86
93
  }): number;
94
+ declare function parseDomainName(input: string): ParsedDomainName;
87
95
  declare function parseProofOfPersonhoodStatus(status: string): number;
88
96
  declare function popStatusName(status: number): string;
89
97
  declare class ReviveClientWrapper {
@@ -154,6 +162,12 @@ declare class DotNS {
154
162
  finalizeRegistration(registration: any, priceWei: bigint): Promise<void>;
155
163
  verifyOwnership(label: string): Promise<void>;
156
164
  getContenthash(domainName: string): Promise<string>;
165
+ checkSubdomainOwnership(sublabel: string, parentLabel: string): Promise<OwnershipResult>;
166
+ registerSubdomain(sublabel: string, parentLabel: string): Promise<{
167
+ sublabel: string;
168
+ parentLabel: string;
169
+ owner: string;
170
+ }>;
157
171
  setContenthash(domainName: string, contenthashHex: string): Promise<{
158
172
  node: string;
159
173
  }>;
@@ -169,4 +183,4 @@ declare class DotNS {
169
183
  }
170
184
  declare const dotns: DotNS;
171
185
 
172
- export { CONNECTION_TIMEOUT_MS, CONTRACTS, DECIMALS, DEFAULT_MNEMONIC, DOTNS_TX_MAX_ATTEMPTS, DOT_NODE, DotNS, type DotNSConnectOptions, type DotnsPreflightResult, NATIVE_TO_ETH_RATIO, OPERATION_TIMEOUT_MS, type OwnershipResult, type PriceValidationResult, ProofOfPersonhoodStatus, RPC_ENDPOINTS, TX_CHAIN_TIME_BUDGET_MS, TX_TIMEOUT_MS, TX_WALL_CLOCK_CEILING_MS, WS_HEARTBEAT_TIMEOUT_MS, canRegister, classifyDotnsLabel, classifyTxRetryDecision, computeDomainTokenId, convertWeiToNative, countTrailingDigits, dotns, fetchNonce, isCommitmentMature, parseProofOfPersonhoodStatus, popStatusName, sanitizeDomainLabel, simulateUserStatus, stripTrailingDigits, validateDomainLabel };
186
+ export { CONNECTION_TIMEOUT_MS, CONTRACTS, DECIMALS, DEFAULT_MNEMONIC, DOTNS_TX_MAX_ATTEMPTS, DOT_NODE, DotNS, type DotNSConnectOptions, type DotnsPreflightResult, NATIVE_TO_ETH_RATIO, OPERATION_TIMEOUT_MS, type OwnershipResult, type ParsedDomainName, type PriceValidationResult, ProofOfPersonhoodStatus, RPC_ENDPOINTS, TX_CHAIN_TIME_BUDGET_MS, TX_TIMEOUT_MS, TX_WALL_CLOCK_CEILING_MS, WS_HEARTBEAT_TIMEOUT_MS, canRegister, classifyDotnsLabel, classifyTxRetryDecision, computeDomainTokenId, convertWeiToNative, countTrailingDigits, dotns, fetchNonce, isCommitmentMature, parseDomainName, parseProofOfPersonhoodStatus, popStatusName, sanitizeDomainLabel, simulateUserStatus, stripTrailingDigits, validateDomainLabel };
package/dist/dotns.js CHANGED
@@ -23,14 +23,15 @@ import {
23
23
  dotns,
24
24
  fetchNonce,
25
25
  isCommitmentMature,
26
+ parseDomainName,
26
27
  parseProofOfPersonhoodStatus,
27
28
  popStatusName,
28
29
  sanitizeDomainLabel,
29
30
  simulateUserStatus,
30
31
  stripTrailingDigits,
31
32
  validateDomainLabel
32
- } from "./chunk-NEV6WTYM.js";
33
- import "./chunk-4FUUYJP2.js";
33
+ } from "./chunk-M3H3F4FY.js";
34
+ import "./chunk-BYIVK52G.js";
34
35
  import "./chunk-JHNW2EKY.js";
35
36
  import "./chunk-QGM4M3NI.js";
36
37
  export {
@@ -58,6 +59,7 @@ export {
58
59
  dotns,
59
60
  fetchNonce,
60
61
  isCommitmentMature,
62
+ parseDomainName,
61
63
  parseProofOfPersonhoodStatus,
62
64
  popStatusName,
63
65
  sanitizeDomainLabel,
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { DeployContent, DeployOptions, DeployResult, deploy } from './deploy.js';
2
2
  export { PoolAccount, PoolAuthorization, bootstrapPool, derivePoolAccounts, ensureAuthorized, fetchPoolAuthorizations, selectAccount } from './pool.js';
3
- export { DotNS, DotNSConnectOptions, OwnershipResult, PriceValidationResult } from './dotns.js';
3
+ export { DotNS, DotNSConnectOptions, OwnershipResult, ParsedDomainName, PriceValidationResult, parseDomainName } from './dotns.js';
4
4
  export { MerkleizeResult, merkleizeJS } from './merkle.js';
5
5
  import 'multiformats/cid';
6
6
  import 'polkadot-api';
package/dist/index.js CHANGED
@@ -1,13 +1,14 @@
1
1
  import {
2
2
  deploy
3
- } from "./chunk-VJLTIZ6S.js";
4
- import "./chunk-LMSMDKVU.js";
5
- import "./chunk-4UNQGG3O.js";
3
+ } from "./chunk-EPNPPAMS.js";
4
+ import "./chunk-4EQERQRG.js";
5
+ import "./chunk-MDYSENTW.js";
6
6
  import {
7
- DotNS
8
- } from "./chunk-NEV6WTYM.js";
7
+ DotNS,
8
+ parseDomainName
9
+ } from "./chunk-M3H3F4FY.js";
9
10
  import "./chunk-2Q2WSKFD.js";
10
- import "./chunk-4FUUYJP2.js";
11
+ import "./chunk-BYIVK52G.js";
11
12
  import {
12
13
  merkleizeJS
13
14
  } from "./chunk-B7GUYYAN.js";
@@ -27,5 +28,6 @@ export {
27
28
  ensureAuthorized,
28
29
  fetchPoolAuthorizations,
29
30
  merkleizeJS,
31
+ parseDomainName,
30
32
  selectAccount
31
33
  };
@@ -5,7 +5,7 @@ import {
5
5
  maybeWriteMemoryReport,
6
6
  safeHeap,
7
7
  sampleFromBytes
8
- } from "./chunk-4FUUYJP2.js";
8
+ } from "./chunk-BYIVK52G.js";
9
9
  import "./chunk-QGM4M3NI.js";
10
10
  export {
11
11
  DEFAULT_THRESHOLD_MB,
package/dist/telemetry.js CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  truncateAddress,
22
22
  withDeploySpan,
23
23
  withSpan
24
- } from "./chunk-4FUUYJP2.js";
24
+ } from "./chunk-BYIVK52G.js";
25
25
  import "./chunk-QGM4M3NI.js";
26
26
  export {
27
27
  VERSION,
@@ -8,8 +8,8 @@ import {
8
8
  isPreReleaseVersion,
9
9
  preReleaseWarning,
10
10
  promptYesNo
11
- } from "./chunk-4UNQGG3O.js";
12
- import "./chunk-4FUUYJP2.js";
11
+ } from "./chunk-MDYSENTW.js";
12
+ import "./chunk-BYIVK52G.js";
13
13
  import "./chunk-QGM4M3NI.js";
14
14
  export {
15
15
  assessVersion,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulletin-deploy",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -61,4 +61,4 @@
61
61
  "engines": {
62
62
  "node": ">=22"
63
63
  }
64
- }
64
+ }