@midnames/sdk 0.1.1

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/README.md ADDED
@@ -0,0 +1,46 @@
1
+ ># @midnames/sdk
2
+
3
+ SDK to resolve Midnames domains, and render a profile widget.
4
+
5
+ ## Build
6
+
7
+ Run the `build` script with `npm`, `bun`, etc.
8
+
9
+ ## Usage
10
+
11
+ Resolve a domain:
12
+
13
+ ```ts
14
+ import { resolveDomain, getDomainProfile } from '@midnames/sdk';
15
+ import type { PublicDataProvider } from '@midnight-ntwrk/midnight-js-types';
16
+
17
+ async function demo(provider: PublicDataProvider) {
18
+ const target = await resolveDomain(provider, 'alice.night');
19
+ const profile = await getDomainProfile(provider, 'id.alice.night');
20
+ console.log(target, profile.fields);
21
+ }
22
+ ```
23
+
24
+ React widget:
25
+
26
+ ```tsx
27
+ import '@midnames/sdk/styles.css';
28
+ import { DomainProfileWidget } from '@midnames/sdk/react';
29
+
30
+ <DomainProfileWidget fullDomain="id.alice.night" publicDataProvider={provider} />
31
+ ```
32
+
33
+ Fields recognized for display: `name`, `bio`, `avatar`, `banner`, `website`, `twitter`, `github`, `location`, and `epk`.
34
+
35
+ ## API
36
+
37
+ - `resolveDomain(provider, domain): Promise<string|null>`
38
+ - `getDomainProfile(provider, fullDomain): Promise<{ fullDomain, resolvedTarget, info, fields, settings }>`
39
+
40
+ ```ts
41
+ export interface DomainInfo { owner: string; resolver: string; contractAddress?: string; }
42
+ export interface DomainSettings { coinColor: Uint8Array; domainCost: bigint; }
43
+ ```
44
+
45
+ Notes: Uses TestNet TLD contract by default. Provide a custom TLD address in `resolveDomain` if needed.
46
+
package/dist/core.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import type { PublicDataProvider } from '@midnight-ntwrk/midnight-js-types';
2
+ import type { DomainInfo, DomainSettings, DomainProfileData, Result } from './types.js';
3
+ export declare function resolveDomain(publicDataProvider: PublicDataProvider, domain: string, tldAddress?: string): Promise<Result<string>>;
4
+ export declare function getDomainInfo(publicDataProvider: PublicDataProvider, contractAddress: string, domainName: string): Promise<Result<DomainInfo>>;
5
+ export declare function getDomainInfoByResolving(publicDataProvider: PublicDataProvider, fullDomain: string): Promise<Result<DomainInfo>>;
6
+ export declare function getDomainFields(publicDataProvider: PublicDataProvider, contractAddress: string): Promise<Result<Array<[string, string]>>>;
7
+ export declare function getNamespacedDomainFields(publicDataProvider: PublicDataProvider, _parentContractAddress: string, fullDomainName: string): Promise<Result<Array<[string, string]>>>;
8
+ export declare function getDomainSettings(publicDataProvider: PublicDataProvider, contractAddress: string): Promise<Result<DomainSettings>>;
9
+ export declare function getDomainProfile(publicDataProvider: PublicDataProvider, fullDomain: string): Promise<Result<DomainProfileData>>;
package/dist/core.js ADDED
@@ -0,0 +1,204 @@
1
+ import { getNetworkId, getZswapNetworkId, NetworkId } from '@midnight-ntwrk/midnight-js-network-id';
2
+ import { ShieldedCoinPublicKey } from '@midnight-ntwrk/wallet-sdk-address-format';
3
+ import { ledger } from '../managed/index.js';
4
+ import { formatContractAddress } from './utils/address.js';
5
+ import { normalizeDomain, parseFullDomain } from './utils/domain.js';
6
+ import { success, failure, NetworkError, ContractNotFoundError, DomainNotFoundError, InvalidDomainError, ProviderError } from './types.js';
7
+ const TLD = 'night';
8
+ const TESTNET_TLD_ADDRESS = '020015552e604cfd348b3b43bb6043692c6da7f79e107801d4d5989714f8e2e08402';
9
+ function getDefaultTldAddress() {
10
+ const currentNetwork = getNetworkId();
11
+ switch (currentNetwork) {
12
+ case NetworkId.TestNet:
13
+ return TESTNET_TLD_ADDRESS;
14
+ default:
15
+ throw new Error('Provide an address to use the resolver on a Standalone Network.');
16
+ }
17
+ }
18
+ function getTargetFromLedger(contractLedger) {
19
+ const target = contractLedger.DOMAIN_TARGET;
20
+ if (target.is_left) {
21
+ const coinPublicKey = new ShieldedCoinPublicKey(Buffer.from(target.left.bytes));
22
+ return ShieldedCoinPublicKey.codec.encode(getZswapNetworkId(), coinPublicKey).asString();
23
+ }
24
+ else {
25
+ return formatContractAddress(target.right.bytes);
26
+ }
27
+ }
28
+ async function queryContractStateSafely(publicDataProvider, contractAddress) {
29
+ try {
30
+ const contractState = await publicDataProvider.queryContractState(contractAddress);
31
+ if (contractState == null) {
32
+ return failure(new ContractNotFoundError(contractAddress));
33
+ }
34
+ return success(contractState);
35
+ }
36
+ catch (error) {
37
+ return failure(new ProviderError(`Failed to query contract state: ${error instanceof Error ? error.message : String(error)}`, error));
38
+ }
39
+ }
40
+ async function getResolverAddress(publicDataProvider, fullDomain) {
41
+ try {
42
+ const tldAddress = getDefaultTldAddress();
43
+ const domainParts = fullDomain.split('.');
44
+ const traversalParts = domainParts.slice(0, -1).reverse();
45
+ if (traversalParts.length === 0)
46
+ return success(tldAddress);
47
+ let currentResolver = tldAddress;
48
+ for (const part of traversalParts) {
49
+ const contractStateResult = await queryContractStateSafely(publicDataProvider, currentResolver);
50
+ if (!contractStateResult.success) {
51
+ return failure(contractStateResult.error);
52
+ }
53
+ const contractLedger = ledger(contractStateResult.data.data);
54
+ if (!contractLedger.domains.member(part)) {
55
+ return failure(new DomainNotFoundError(`${part} in ${currentResolver}`));
56
+ }
57
+ const domainData = contractLedger.domains.lookup(part);
58
+ const resolverBytes = domainData.resolver.bytes;
59
+ currentResolver = formatContractAddress(resolverBytes);
60
+ }
61
+ return success(currentResolver);
62
+ }
63
+ catch (error) {
64
+ return failure(new NetworkError(`Failed to get resolver address: ${error instanceof Error ? error.message : String(error)}`, error));
65
+ }
66
+ }
67
+ export async function resolveDomain(publicDataProvider, domain, tldAddress) {
68
+ const tldContractAddress = tldAddress || getDefaultTldAddress();
69
+ const fullDomain = normalizeDomain(domain);
70
+ try {
71
+ const domainParts = fullDomain.split('.');
72
+ if (domainParts[domainParts.length - 1] !== TLD) {
73
+ return failure(new InvalidDomainError(fullDomain, `Domain must end with .${TLD}`));
74
+ }
75
+ const parsedDomain = domainParts.slice(0, -1).reverse();
76
+ let currentResolver = tldContractAddress;
77
+ if (parsedDomain.length === 0) {
78
+ const contractStateResult = await queryContractStateSafely(publicDataProvider, currentResolver);
79
+ if (!contractStateResult.success)
80
+ return failure(contractStateResult.error);
81
+ const contractLedger = ledger(contractStateResult.data.data);
82
+ return success(getTargetFromLedger(contractLedger));
83
+ }
84
+ for (const part of parsedDomain) {
85
+ const contractStateResult = await queryContractStateSafely(publicDataProvider, currentResolver);
86
+ if (!contractStateResult.success)
87
+ return failure(contractStateResult.error);
88
+ const contractLedger = ledger(contractStateResult.data.data);
89
+ if (!contractLedger.domains.member(part)) {
90
+ return failure(new DomainNotFoundError(`${part} in ${fullDomain}`));
91
+ }
92
+ const domainData = contractLedger.domains.lookup(part);
93
+ const resolverBytes = domainData.resolver.bytes;
94
+ currentResolver = formatContractAddress(resolverBytes);
95
+ }
96
+ const finalContractStateResult = await queryContractStateSafely(publicDataProvider, currentResolver);
97
+ if (!finalContractStateResult.success)
98
+ return failure(finalContractStateResult.error);
99
+ const finalLedger = ledger(finalContractStateResult.data.data);
100
+ return success(getTargetFromLedger(finalLedger));
101
+ }
102
+ catch (error) {
103
+ return failure(new NetworkError(`Failed to resolve domain: ${error instanceof Error ? error.message : String(error)}`, error));
104
+ }
105
+ }
106
+ export async function getDomainInfo(publicDataProvider, contractAddress, domainName) {
107
+ try {
108
+ const contractStateResult = await queryContractStateSafely(publicDataProvider, contractAddress);
109
+ if (!contractStateResult.success)
110
+ return failure(contractStateResult.error);
111
+ const contractLedger = ledger(contractStateResult.data.data);
112
+ if (!contractLedger.domains.member(domainName)) {
113
+ return failure(new DomainNotFoundError(domainName));
114
+ }
115
+ const domainData = contractLedger.domains.lookup(domainName);
116
+ const ownerCoinPublicKey = new ShieldedCoinPublicKey(Buffer.from(domainData.owner.bytes));
117
+ const ownerAddress = ShieldedCoinPublicKey.codec.encode(getZswapNetworkId(), ownerCoinPublicKey).asString();
118
+ return success({ owner: ownerAddress, resolver: formatContractAddress(domainData.resolver.bytes) });
119
+ }
120
+ catch (error) {
121
+ return failure(new NetworkError(`Failed to get domain info: ${error instanceof Error ? error.message : String(error)}`, error));
122
+ }
123
+ }
124
+ export async function getDomainInfoByResolving(publicDataProvider, fullDomain) {
125
+ try {
126
+ const normalizedDomain = normalizeDomain(fullDomain);
127
+ const parsed = parseFullDomain(normalizedDomain);
128
+ if (!parsed.isValid) {
129
+ return failure(new InvalidDomainError(fullDomain, 'Invalid domain format'));
130
+ }
131
+ const parentContractAddressResult = await getResolverAddress(publicDataProvider, parsed.parentDomainPath);
132
+ if (!parentContractAddressResult.success)
133
+ return failure(parentContractAddressResult.error);
134
+ const infoResult = await getDomainInfo(publicDataProvider, parentContractAddressResult.data, parsed.domainName);
135
+ if (!infoResult.success)
136
+ return failure(infoResult.error);
137
+ return success({ ...infoResult.data, contractAddress: parentContractAddressResult.data });
138
+ }
139
+ catch (error) {
140
+ return failure(new NetworkError(`Failed to get domain info by resolving: ${error instanceof Error ? error.message : String(error)}`, error));
141
+ }
142
+ }
143
+ export async function getDomainFields(publicDataProvider, contractAddress) {
144
+ try {
145
+ const contractStateResult = await queryContractStateSafely(publicDataProvider, contractAddress);
146
+ if (!contractStateResult.success)
147
+ return failure(contractStateResult.error);
148
+ const contractLedger = ledger(contractStateResult.data.data);
149
+ const fields = [];
150
+ for (const [key, value] of contractLedger.fields)
151
+ fields.push([key, value]);
152
+ return success(fields);
153
+ }
154
+ catch (error) {
155
+ return failure(new NetworkError(`Failed to get domain fields: ${error instanceof Error ? error.message : String(error)}`, error));
156
+ }
157
+ }
158
+ export async function getNamespacedDomainFields(publicDataProvider, _parentContractAddress, fullDomainName) {
159
+ try {
160
+ const domainContractAddressResult = await getResolverAddress(publicDataProvider, fullDomainName);
161
+ if (!domainContractAddressResult.success)
162
+ return failure(domainContractAddressResult.error);
163
+ return await getDomainFields(publicDataProvider, domainContractAddressResult.data);
164
+ }
165
+ catch (error) {
166
+ return failure(new NetworkError(`Failed to get namespaced domain fields: ${error instanceof Error ? error.message : String(error)}`, error));
167
+ }
168
+ }
169
+ export async function getDomainSettings(publicDataProvider, contractAddress) {
170
+ try {
171
+ const contractStateResult = await queryContractStateSafely(publicDataProvider, contractAddress);
172
+ if (!contractStateResult.success)
173
+ return failure(contractStateResult.error);
174
+ const contractLedger = ledger(contractStateResult.data.data);
175
+ return success({ coinColor: contractLedger.COIN_COLOR, domainCost: contractLedger.DOMAIN_COST });
176
+ }
177
+ catch (error) {
178
+ return failure(new NetworkError(`Failed to get domain settings: ${error instanceof Error ? error.message : String(error)}`, error));
179
+ }
180
+ }
181
+ export async function getDomainProfile(publicDataProvider, fullDomain) {
182
+ try {
183
+ const normalized = normalizeDomain(fullDomain);
184
+ const [resolvedTargetResult, infoResult] = await Promise.all([
185
+ resolveDomain(publicDataProvider, normalized),
186
+ getDomainInfoByResolving(publicDataProvider, normalized)
187
+ ]);
188
+ const resolvedTarget = resolvedTargetResult.success ? resolvedTargetResult.data : null;
189
+ const info = infoResult.success ? infoResult.data : null;
190
+ if (info && info.contractAddress) {
191
+ const [fieldsResult, settingsResult] = await Promise.all([
192
+ getNamespacedDomainFields(publicDataProvider, info.contractAddress, normalized),
193
+ getDomainSettings(publicDataProvider, info.resolver)
194
+ ]);
195
+ const fields = fieldsResult.success ? fieldsResult.data : [];
196
+ const settings = settingsResult.success ? settingsResult.data : null;
197
+ return success({ fullDomain: normalized, resolvedTarget, info, fields, settings });
198
+ }
199
+ return success({ fullDomain: normalized, resolvedTarget, info, fields: [], settings: null });
200
+ }
201
+ catch (error) {
202
+ return failure(new NetworkError(`Failed to get domain profile: ${error instanceof Error ? error.message : String(error)}`, error));
203
+ }
204
+ }
@@ -0,0 +1,4 @@
1
+ export * from './types.js';
2
+ export * from './utils/domain.js';
3
+ export * from './utils/address.js';
4
+ export * from './core.js';
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from './types.js';
2
+ export * from './utils/domain.js';
3
+ export * from './utils/address.js';
4
+ export * from './core.js';
@@ -0,0 +1,9 @@
1
+ export { type DomainData as LeafDomainData } from "./leaf/contract/index.cjs";
2
+ export * as Leaf from "./leaf/contract/index.cjs";
3
+ import ContractModule from './leaf/contract/index.cjs';
4
+ import type { Contract as ContractType, Witnesses } from './leaf/contract/index.cjs';
5
+ export declare const ledger: typeof ContractModule.ledger;
6
+ export declare const pureCircuits: ContractModule.PureCircuits;
7
+ export declare const Contract: typeof ContractModule.Contract;
8
+ export type Contract<T, W extends Witnesses<T> = Witnesses<T>> = ContractType<T, W>;
9
+ export type Ledger = ContractModule.Ledger;
@@ -0,0 +1,6 @@
1
+ export * as Leaf from "./leaf/contract/index.cjs";
2
+ import ContractModule from './leaf/contract/index.cjs';
3
+ export const ledger = ContractModule.ledger;
4
+ export const pureCircuits = ContractModule.pureCircuits;
5
+ export const { Contract } = ContractModule;
6
+ //# sourceMappingURL=index.js.map