@ar.io/sdk 3.19.0-alpha.1 → 3.19.0-alpha.11
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 +155 -7
- package/bundles/web.bundle.min.js +88 -72
- package/lib/cjs/cli/cli.js +14 -1
- package/lib/cjs/cli/commands/antCommands.js +82 -16
- package/lib/cjs/cli/options.js +36 -1
- package/lib/cjs/cli/utils.js +25 -11
- package/lib/cjs/common/ant.js +452 -12
- package/lib/cjs/common/io.js +2 -2
- package/lib/cjs/constants.js +2 -1
- package/lib/cjs/types/ant.js +18 -0
- package/lib/cjs/utils/ant.js +4 -0
- package/lib/cjs/utils/ao.js +3 -1
- package/lib/cjs/utils/processes.js +1 -1
- package/lib/cjs/version.js +1 -1
- package/lib/esm/cli/cli.js +16 -3
- package/lib/esm/cli/commands/antCommands.js +81 -17
- package/lib/esm/cli/options.js +35 -0
- package/lib/esm/cli/utils.js +24 -11
- package/lib/esm/common/ant.js +453 -13
- package/lib/esm/common/io.js +2 -2
- package/lib/esm/constants.js +1 -0
- package/lib/esm/types/ant.js +18 -0
- package/lib/esm/utils/ant.js +4 -0
- package/lib/esm/utils/ao.js +3 -1
- package/lib/esm/utils/processes.js +1 -1
- package/lib/esm/version.js +1 -1
- package/lib/types/cli/commands/antCommands.d.ts +12 -0
- package/lib/types/cli/options.d.ts +25 -0
- package/lib/types/cli/types.d.ts +1 -0
- package/lib/types/cli/utils.d.ts +15 -2
- package/lib/types/common/ant.d.ts +167 -6
- package/lib/types/common/io.d.ts +1 -1
- package/lib/types/constants.d.ts +1 -0
- package/lib/types/types/ant.d.ts +131 -9
- package/lib/types/types/common.d.ts +31 -0
- package/lib/types/utils/ant.d.ts +4 -0
- package/lib/types/utils/ao.d.ts +2 -1
- package/lib/types/utils/processes.d.ts +1 -1
- package/lib/types/version.d.ts +1 -1
- package/package.json +3 -2
package/lib/cjs/common/ant.js
CHANGED
|
@@ -17,6 +17,8 @@ exports.AoANTWriteable = exports.AoANTReadable = exports.ANT = void 0;
|
|
|
17
17
|
* limitations under the License.
|
|
18
18
|
*/
|
|
19
19
|
const zod_1 = require("zod");
|
|
20
|
+
const constants_js_1 = require("../constants.js");
|
|
21
|
+
const constants_js_2 = require("../constants.js");
|
|
20
22
|
const ant_js_1 = require("../types/ant.js");
|
|
21
23
|
const index_js_1 = require("../types/index.js");
|
|
22
24
|
const ant_js_2 = require("../utils/ant.js");
|
|
@@ -43,6 +45,149 @@ class ANT {
|
|
|
43
45
|
* @param config
|
|
44
46
|
*/
|
|
45
47
|
static fork = ao_js_1.forkANT;
|
|
48
|
+
/**
|
|
49
|
+
* Upgrade an ANT by forking it to the latest version and reassigning names.
|
|
50
|
+
*
|
|
51
|
+
*
|
|
52
|
+
* @param config Configuration object for the upgrade process
|
|
53
|
+
* @returns Promise resolving to the forked process ID and successfully reassigned names
|
|
54
|
+
*/
|
|
55
|
+
static async upgrade({ signer, antProcessId, reassignAffiliatedNames = true, names, arioProcessId = constants_js_1.ARIO_MAINNET_PROCESS_ID, antRegistryId = constants_js_2.ANT_REGISTRY_ID, ao, logger = index_js_2.Logger.default, skipVersionCheck = false, onSigningProgress, hyperbeamUrl, }) {
|
|
56
|
+
// run time check if names is not empty but reassignAffiliatedNames it true, throw
|
|
57
|
+
if (names !== undefined &&
|
|
58
|
+
names.length > 0 &&
|
|
59
|
+
reassignAffiliatedNames !== undefined &&
|
|
60
|
+
reassignAffiliatedNames !== false) {
|
|
61
|
+
throw new Error('Cannot reassign all affiliated names and provide specific names');
|
|
62
|
+
}
|
|
63
|
+
let namesToReassign = names !== undefined && names.length > 0 ? new Set(names) : new Set();
|
|
64
|
+
// use reassignAffiliatedNames if names is empty
|
|
65
|
+
const shouldReassignAll = names === undefined || names.length === 0
|
|
66
|
+
? (reassignAffiliatedNames ?? true)
|
|
67
|
+
: false;
|
|
68
|
+
const ario = index_js_2.ARIO.init({
|
|
69
|
+
process: new index_js_2.AOProcess({ processId: arioProcessId, ao }),
|
|
70
|
+
});
|
|
71
|
+
const getAllAffiliatedNames = async () => {
|
|
72
|
+
let cursor = undefined;
|
|
73
|
+
let hasMore = true;
|
|
74
|
+
const affiliatedNames = new Set();
|
|
75
|
+
while (hasMore) {
|
|
76
|
+
const page = await ario.getArNSRecords({
|
|
77
|
+
filters: { processId: antProcessId },
|
|
78
|
+
cursor,
|
|
79
|
+
limit: 100,
|
|
80
|
+
});
|
|
81
|
+
page.items.forEach((r) => {
|
|
82
|
+
affiliatedNames.add(r.name);
|
|
83
|
+
});
|
|
84
|
+
cursor = page.nextCursor;
|
|
85
|
+
hasMore = page.hasMore;
|
|
86
|
+
}
|
|
87
|
+
return affiliatedNames;
|
|
88
|
+
};
|
|
89
|
+
// get all the affiliated names if reassign all affiliated names is true
|
|
90
|
+
if (shouldReassignAll) {
|
|
91
|
+
onSigningProgress?.('fetching-affiliated-names', {
|
|
92
|
+
arioProcessId,
|
|
93
|
+
antProcessId,
|
|
94
|
+
});
|
|
95
|
+
namesToReassign = await getAllAffiliatedNames();
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
if (names === undefined || names.length === 0) {
|
|
99
|
+
throw new Error('Names are required when reassignAffiliatedNames is false.');
|
|
100
|
+
}
|
|
101
|
+
onSigningProgress?.('validating-names', {
|
|
102
|
+
arioProcessId,
|
|
103
|
+
antProcessId,
|
|
104
|
+
names,
|
|
105
|
+
});
|
|
106
|
+
// confirm all names are affiliated with the ANT
|
|
107
|
+
const allAffiliatedNames = await getAllAffiliatedNames();
|
|
108
|
+
if (!names.every((name) => allAffiliatedNames.has(name))) {
|
|
109
|
+
// find any that are not affiliated with the ANT
|
|
110
|
+
const notAffiliatedNames = names.filter((name) => !allAffiliatedNames.has(name));
|
|
111
|
+
throw new Error(`All names must be affiliated with the ANT on the provided ARIO process. The following names are not affiliated to this ANT: ${notAffiliatedNames.join(', ')}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// if names is empty and reassign all affiliated names is false, throw an error
|
|
115
|
+
if (namesToReassign.size === 0) {
|
|
116
|
+
throw new Error('There are no names to reassign for this ANT.');
|
|
117
|
+
}
|
|
118
|
+
const existingAntProcess = ANT.init({
|
|
119
|
+
process: new index_js_2.AOProcess({
|
|
120
|
+
processId: antProcessId,
|
|
121
|
+
ao,
|
|
122
|
+
logger,
|
|
123
|
+
}),
|
|
124
|
+
hyperbeamUrl,
|
|
125
|
+
signer,
|
|
126
|
+
});
|
|
127
|
+
if (!skipVersionCheck) {
|
|
128
|
+
onSigningProgress?.('checking-version', {
|
|
129
|
+
antProcessId,
|
|
130
|
+
antRegistryId,
|
|
131
|
+
});
|
|
132
|
+
const isLatestVersion = await existingAntProcess.isLatestVersion({
|
|
133
|
+
antRegistryId,
|
|
134
|
+
});
|
|
135
|
+
if (isLatestVersion) {
|
|
136
|
+
return {
|
|
137
|
+
forkedProcessId: antProcessId,
|
|
138
|
+
reassignedNames: {},
|
|
139
|
+
failedReassignedNames: {},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const forkedProcessId = await ANT.fork({
|
|
144
|
+
signer,
|
|
145
|
+
antProcessId,
|
|
146
|
+
ao,
|
|
147
|
+
logger,
|
|
148
|
+
antRegistryId,
|
|
149
|
+
onSigningProgress,
|
|
150
|
+
});
|
|
151
|
+
// we could parallelize this, but then signing progress would be harder to track
|
|
152
|
+
const reassignedNames = {};
|
|
153
|
+
const failedReassignedNames = {};
|
|
154
|
+
for (const name of namesToReassign) {
|
|
155
|
+
let reassignmentResult;
|
|
156
|
+
try {
|
|
157
|
+
onSigningProgress?.('reassigning-name', {
|
|
158
|
+
name,
|
|
159
|
+
arioProcessId,
|
|
160
|
+
antProcessId: forkedProcessId,
|
|
161
|
+
});
|
|
162
|
+
reassignmentResult = await existingAntProcess.reassignName({
|
|
163
|
+
name,
|
|
164
|
+
arioProcessId,
|
|
165
|
+
antProcessId: forkedProcessId,
|
|
166
|
+
});
|
|
167
|
+
onSigningProgress?.('successfully-reassigned-name', {
|
|
168
|
+
name,
|
|
169
|
+
arioProcessId,
|
|
170
|
+
antProcessId: forkedProcessId,
|
|
171
|
+
});
|
|
172
|
+
reassignedNames[name] = reassignmentResult;
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
logger.error(`Failed to reassign name ${name}:`, { error });
|
|
176
|
+
onSigningProgress?.('failed-to-reassign-name', {
|
|
177
|
+
name,
|
|
178
|
+
arioProcessId,
|
|
179
|
+
antProcessId: forkedProcessId,
|
|
180
|
+
error,
|
|
181
|
+
});
|
|
182
|
+
// Continue with other names rather than failing completely
|
|
183
|
+
failedReassignedNames[name] = {
|
|
184
|
+
id: reassignmentResult?.id,
|
|
185
|
+
error,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return { forkedProcessId, reassignedNames, failedReassignedNames };
|
|
190
|
+
}
|
|
46
191
|
static init(config) {
|
|
47
192
|
if (config !== undefined && 'signer' in config) {
|
|
48
193
|
return new AoANTWriteable(config);
|
|
@@ -54,9 +199,11 @@ exports.ANT = ANT;
|
|
|
54
199
|
class AoANTReadable {
|
|
55
200
|
process;
|
|
56
201
|
processId;
|
|
57
|
-
strict;
|
|
58
202
|
hyperbeamUrl;
|
|
203
|
+
strict;
|
|
59
204
|
checkHyperBeamPromise;
|
|
205
|
+
moduleId;
|
|
206
|
+
moduleIdPromise;
|
|
60
207
|
logger = index_js_2.Logger.default;
|
|
61
208
|
constructor(config) {
|
|
62
209
|
this.strict = config.strict || false;
|
|
@@ -189,6 +336,185 @@ class AoANTReadable {
|
|
|
189
336
|
const info = await this.getInfo();
|
|
190
337
|
return info.Logo;
|
|
191
338
|
}
|
|
339
|
+
/**
|
|
340
|
+
* Gets the module ID of the current ANT process by querying its spawn transaction tags.
|
|
341
|
+
* Results are cached after the first successful fetch.
|
|
342
|
+
*
|
|
343
|
+
* @param graphqlUrl The GraphQL endpoint URL (defaults to Arweave's GraphQL endpoint)
|
|
344
|
+
* @param retries Number of retry attempts (defaults to 3)
|
|
345
|
+
* @returns Promise<string> The module ID used to spawn this ANT process
|
|
346
|
+
* @example
|
|
347
|
+
* ```ts
|
|
348
|
+
* const moduleId = await ant.getModuleId();
|
|
349
|
+
* console.log(`ANT was spawned with module: ${moduleId}`);
|
|
350
|
+
* ```
|
|
351
|
+
*/
|
|
352
|
+
async getModuleId({
|
|
353
|
+
// TODO: we could use wayfinder for this
|
|
354
|
+
graphqlUrl = 'https://arweave.net/graphql', retries = 3, } = {}) {
|
|
355
|
+
// Return cached result if available
|
|
356
|
+
if (this.moduleId !== undefined) {
|
|
357
|
+
this.logger.debug('Returning cached module ID', {
|
|
358
|
+
processId: this.processId,
|
|
359
|
+
moduleId: this.moduleId,
|
|
360
|
+
});
|
|
361
|
+
return this.moduleId;
|
|
362
|
+
}
|
|
363
|
+
// Return existing promise if already in flight
|
|
364
|
+
if (this.moduleIdPromise) {
|
|
365
|
+
this.logger.debug('Returning in-flight module ID promise', {
|
|
366
|
+
processId: this.processId,
|
|
367
|
+
});
|
|
368
|
+
return this.moduleIdPromise;
|
|
369
|
+
}
|
|
370
|
+
// Create and cache the promise to prevent multiple concurrent requests
|
|
371
|
+
this.moduleIdPromise = this.fetchModuleId({ graphqlUrl, retries });
|
|
372
|
+
try {
|
|
373
|
+
const moduleId = await this.moduleIdPromise;
|
|
374
|
+
this.moduleId = moduleId;
|
|
375
|
+
this.logger.debug('Successfully fetched and cached module ID', {
|
|
376
|
+
processId: this.processId,
|
|
377
|
+
moduleId,
|
|
378
|
+
});
|
|
379
|
+
return moduleId;
|
|
380
|
+
}
|
|
381
|
+
finally {
|
|
382
|
+
// Clear the promise so future calls can retry if this one failed
|
|
383
|
+
this.moduleIdPromise = undefined;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Internal method to fetch the module ID from GraphQL.
|
|
388
|
+
*
|
|
389
|
+
* TODO: this could be more like get process headers/metadata and fetch additional details.
|
|
390
|
+
*
|
|
391
|
+
* It seems like module is the only relevant one, but scheduler and authority are also available.
|
|
392
|
+
*/
|
|
393
|
+
async fetchModuleId({ graphqlUrl, retries, }) {
|
|
394
|
+
const query = JSON.stringify({
|
|
395
|
+
query: `
|
|
396
|
+
query {
|
|
397
|
+
transactions(
|
|
398
|
+
ids: ["${this.processId}"]
|
|
399
|
+
first: 1
|
|
400
|
+
) {
|
|
401
|
+
edges {
|
|
402
|
+
node {
|
|
403
|
+
tags {
|
|
404
|
+
name
|
|
405
|
+
value
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
`,
|
|
412
|
+
});
|
|
413
|
+
for (let i = 0; i < retries; i++) {
|
|
414
|
+
try {
|
|
415
|
+
const response = await fetch(graphqlUrl, {
|
|
416
|
+
method: 'POST',
|
|
417
|
+
body: query,
|
|
418
|
+
headers: {
|
|
419
|
+
'Content-Type': 'application/json',
|
|
420
|
+
},
|
|
421
|
+
signal: AbortSignal.timeout(10_000), // 10 second timeout
|
|
422
|
+
});
|
|
423
|
+
if (!response.ok) {
|
|
424
|
+
throw new Error(`GraphQL request failed: ${response.statusText}`);
|
|
425
|
+
}
|
|
426
|
+
const result = (await response.json());
|
|
427
|
+
if (result.errors) {
|
|
428
|
+
throw new Error(`GraphQL errors: ${result.errors.map((e) => e.message).join(', ')}`);
|
|
429
|
+
}
|
|
430
|
+
const edges = result.data?.transactions?.edges;
|
|
431
|
+
if (!edges || edges.length === 0) {
|
|
432
|
+
throw new Error(`No transaction found for process ID: ${this.processId}`);
|
|
433
|
+
}
|
|
434
|
+
const tags = edges[0].node.tags;
|
|
435
|
+
const moduleTag = tags.find((tag) => tag.name === 'Module');
|
|
436
|
+
if (!moduleTag) {
|
|
437
|
+
throw new Error(`No Module tag found for process ID: ${this.processId}`);
|
|
438
|
+
}
|
|
439
|
+
return moduleTag.value;
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
if (i === retries - 1) {
|
|
443
|
+
// Final attempt failed
|
|
444
|
+
this.logger.error('Failed to get ANT module ID after all retries:', {
|
|
445
|
+
error,
|
|
446
|
+
});
|
|
447
|
+
throw new Error(`Unable to determine module ID for ANT process ${this.processId}: ${error.message}`);
|
|
448
|
+
}
|
|
449
|
+
// Exponential backoff
|
|
450
|
+
await new Promise((resolve) => setTimeout(resolve, Math.pow(2, i) * 1000));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
throw new Error(`Unexpected error getting module ID for process ${this.processId}`);
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Gets the version string of the current ANT by matching its module ID
|
|
457
|
+
* with versions from the ANT registry.
|
|
458
|
+
*
|
|
459
|
+
* @param antRegistryId The ANT registry process ID (defaults to mainnet registry)
|
|
460
|
+
* @param graphqlUrl The GraphQL endpoint URL for getModuleId (defaults to Arweave's GraphQL endpoint)
|
|
461
|
+
* @param retries Number of retry attempts for getModuleId (defaults to 3)
|
|
462
|
+
* @returns Promise<string> The version string (e.g., "1.0.15") or "unknown" if not found
|
|
463
|
+
* @example
|
|
464
|
+
* ```ts
|
|
465
|
+
* const version = await ant.getVersion();
|
|
466
|
+
* console.log(`ANT is running version: ${version}`);
|
|
467
|
+
* ```
|
|
468
|
+
*/
|
|
469
|
+
async getVersion({ antRegistryId = constants_js_2.ANT_REGISTRY_ID, graphqlUrl = 'https://arweave.net/graphql', retries = 3, } = {}) {
|
|
470
|
+
// Get the current ANT's module ID
|
|
471
|
+
const currentModuleId = await this.getModuleId({ graphqlUrl, retries });
|
|
472
|
+
// Get all versions from the ANT registry
|
|
473
|
+
const antVersions = ant_versions_js_1.ANTVersions.init({
|
|
474
|
+
processId: antRegistryId,
|
|
475
|
+
});
|
|
476
|
+
const versions = await antVersions.getANTVersions();
|
|
477
|
+
// Find the version that matches our module ID
|
|
478
|
+
for (const [version, versionInfo] of Object.entries(versions)) {
|
|
479
|
+
if (versionInfo.moduleId === currentModuleId) {
|
|
480
|
+
this.logger.debug('Found matching ANT version', {
|
|
481
|
+
processId: this.processId,
|
|
482
|
+
moduleId: currentModuleId,
|
|
483
|
+
version,
|
|
484
|
+
});
|
|
485
|
+
return version;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
const versionForModuleId = Object.entries(versions)
|
|
489
|
+
.map(([version, versionInfo]) => ({
|
|
490
|
+
version,
|
|
491
|
+
...versionInfo,
|
|
492
|
+
}))
|
|
493
|
+
.find((obj) => obj.moduleId === currentModuleId);
|
|
494
|
+
return versionForModuleId?.version ?? 'unknown';
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Checks if the current ANT version is the latest according to the ANT registry.
|
|
498
|
+
*
|
|
499
|
+
* @param antRegistryId Optional ANT registry process ID. Defaults to mainnet ANT registry.
|
|
500
|
+
* @param graphqlUrl Optional GraphQL endpoint. Defaults to https://arweave.net/graphql.
|
|
501
|
+
* @param retries Optional number of retries for fetching module ID. Defaults to 3.
|
|
502
|
+
* @returns {Promise<boolean>} True if current ANT version is the latest, false otherwise.
|
|
503
|
+
*/
|
|
504
|
+
async isLatestVersion({ antRegistryId = constants_js_2.ANT_REGISTRY_ID, graphqlUrl = 'https://arweave.net/graphql', retries = 3, } = {}) {
|
|
505
|
+
// Get the current ANT's version
|
|
506
|
+
const currentVersion = await this.getVersion({
|
|
507
|
+
antRegistryId,
|
|
508
|
+
graphqlUrl,
|
|
509
|
+
retries,
|
|
510
|
+
});
|
|
511
|
+
// Get all versions from the ANT registry
|
|
512
|
+
const antVersions = ant_versions_js_1.ANTVersions.init({
|
|
513
|
+
processId: antRegistryId,
|
|
514
|
+
});
|
|
515
|
+
const latestVersion = await antVersions.getLatestANTVersion();
|
|
516
|
+
return currentVersion === latestVersion.version;
|
|
517
|
+
}
|
|
192
518
|
/**
|
|
193
519
|
* @param undername @type {string} The domain name.
|
|
194
520
|
* @returns {Promise<ANTRecord>} The record of the undername domain.
|
|
@@ -437,17 +763,31 @@ class AoANTWriteable extends AoANTReadable {
|
|
|
437
763
|
* @param undername @type {string} The record you want to set the transactionId and ttlSeconds of.
|
|
438
764
|
* @param transactionId @type {string} The transactionId of the record.
|
|
439
765
|
* @param ttlSeconds @type {number} The time to live of the record.
|
|
766
|
+
* @param owner @type {string} Optional owner address for the record.
|
|
767
|
+
* @param displayName @type {string} Optional display name for the record.
|
|
768
|
+
* @param logo @type {string} Optional logo transaction ID for the record.
|
|
769
|
+
* @param description @type {string} Optional description for the record.
|
|
770
|
+
* @param keywords @type {string[]} Optional keywords array for the record.
|
|
440
771
|
* @returns {Promise<AoMessageResult>} The result of the interaction.
|
|
441
772
|
*/
|
|
442
|
-
async setRecord({ undername, transactionId, ttlSeconds }, options) {
|
|
773
|
+
async setRecord({ undername, transactionId, ttlSeconds, owner, displayName, logo, description, keywords, }, options) {
|
|
774
|
+
const tags = [
|
|
775
|
+
...(options?.tags ?? []),
|
|
776
|
+
{ name: 'Action', value: 'Set-Record' },
|
|
777
|
+
{ name: 'Sub-Domain', value: undername },
|
|
778
|
+
{ name: 'Transaction-Id', value: transactionId },
|
|
779
|
+
{ name: 'TTL-Seconds', value: ttlSeconds.toString() },
|
|
780
|
+
{ name: 'Record-Owner', value: owner },
|
|
781
|
+
{ name: 'Display-Name', value: displayName },
|
|
782
|
+
{ name: 'Logo', value: logo },
|
|
783
|
+
{ name: 'Description', value: description },
|
|
784
|
+
{
|
|
785
|
+
name: 'Keywords',
|
|
786
|
+
value: keywords ? JSON.stringify(keywords) : undefined,
|
|
787
|
+
},
|
|
788
|
+
].filter((tag) => tag.value !== undefined);
|
|
443
789
|
return this.process.send({
|
|
444
|
-
tags
|
|
445
|
-
...(options?.tags ?? []),
|
|
446
|
-
{ name: 'Action', value: 'Set-Record' },
|
|
447
|
-
{ name: 'Sub-Domain', value: undername },
|
|
448
|
-
{ name: 'Transaction-Id', value: transactionId },
|
|
449
|
-
{ name: 'TTL-Seconds', value: ttlSeconds.toString() },
|
|
450
|
-
],
|
|
790
|
+
tags,
|
|
451
791
|
signer: this.signer,
|
|
452
792
|
});
|
|
453
793
|
}
|
|
@@ -456,17 +796,27 @@ class AoANTWriteable extends AoANTReadable {
|
|
|
456
796
|
*
|
|
457
797
|
* @param transactionId @type {string} The transactionId of the record.
|
|
458
798
|
* @param ttlSeconds @type {number} The time to live of the record.
|
|
799
|
+
* @param owner @type {string} Optional owner address for the record.
|
|
800
|
+
* @param displayName @type {string} Optional display name for the record.
|
|
801
|
+
* @param logo @type {string} Optional logo transaction ID for the record.
|
|
802
|
+
* @param description @type {string} Optional description for the record.
|
|
803
|
+
* @param keywords @type {string[]} Optional keywords array for the record.
|
|
459
804
|
* @returns {Promise<AoMessageResult>} The result of the interaction.
|
|
460
805
|
* @example
|
|
461
806
|
* ```ts
|
|
462
807
|
* ant.setBaseNameRecord({ transactionId: "432l1cy0aksiL_x9M359faGzM_yjralacHIUo8_nQXM", ttlSeconds: 100 }); // ardrive.ar.io will resolve to the provided transaction id and be cached for 100 seconds by clients
|
|
463
808
|
* ```
|
|
464
809
|
*/
|
|
465
|
-
async setBaseNameRecord({ transactionId, ttlSeconds }, options) {
|
|
810
|
+
async setBaseNameRecord({ transactionId, ttlSeconds, owner, displayName, logo, description, keywords, }, options) {
|
|
466
811
|
return this.setRecord({
|
|
467
812
|
transactionId,
|
|
468
813
|
ttlSeconds,
|
|
469
814
|
undername: '@',
|
|
815
|
+
owner,
|
|
816
|
+
displayName,
|
|
817
|
+
logo,
|
|
818
|
+
description,
|
|
819
|
+
keywords,
|
|
470
820
|
}, options);
|
|
471
821
|
}
|
|
472
822
|
/**
|
|
@@ -475,17 +825,27 @@ class AoANTWriteable extends AoANTReadable {
|
|
|
475
825
|
* @param undername @type {string} The undername of the ANT.
|
|
476
826
|
* @param transactionId @type {string} The transactionId of the record.
|
|
477
827
|
* @param ttlSeconds @type {number} The time to live of the record.
|
|
828
|
+
* @param owner @type {string} Optional owner address for the record.
|
|
829
|
+
* @param displayName @type {string} Optional display name for the record.
|
|
830
|
+
* @param logo @type {string} Optional logo transaction ID for the record.
|
|
831
|
+
* @param description @type {string} Optional description for the record.
|
|
832
|
+
* @param keywords @type {string[]} Optional keywords array for the record.
|
|
478
833
|
* @returns {Promise<AoMessageResult>} The result of the interaction.
|
|
479
834
|
* @example
|
|
480
835
|
* ```ts
|
|
481
836
|
* ant.setUndernameRecord({ undername: "dapp", transactionId: "432l1cy0aksiL_x9M359faGzM_yjralacHIUo8_nQXM", ttlSeconds: 100 }); // dapp_ardrive.ar.io will resolve to the provided transaction id and be cached for 100 seconds by clients
|
|
482
837
|
* ```
|
|
483
838
|
*/
|
|
484
|
-
async setUndernameRecord({ undername, transactionId, ttlSeconds }, options) {
|
|
839
|
+
async setUndernameRecord({ undername, transactionId, ttlSeconds, owner, displayName, logo, description, keywords, }, options) {
|
|
485
840
|
return this.setRecord({
|
|
486
841
|
undername,
|
|
487
842
|
transactionId,
|
|
488
843
|
ttlSeconds,
|
|
844
|
+
owner,
|
|
845
|
+
displayName,
|
|
846
|
+
logo,
|
|
847
|
+
description,
|
|
848
|
+
keywords,
|
|
489
849
|
}, options);
|
|
490
850
|
}
|
|
491
851
|
/**
|
|
@@ -708,7 +1068,9 @@ class AoANTWriteable extends AoANTReadable {
|
|
|
708
1068
|
* ant.removePrimaryNames({ names: ["ardrive", "dapp_ardrive"], arioProcessId: ARIO_MAINNET_PROCESS_ID, notifyOwners: true }); // removes the primary names and associated wallet addresses assigned to "ardrive" and "dapp_ardrive"
|
|
709
1069
|
* ```
|
|
710
1070
|
*/
|
|
711
|
-
async removePrimaryNames({ names, arioProcessId,
|
|
1071
|
+
async removePrimaryNames({ names, arioProcessId,
|
|
1072
|
+
// TODO: remove this param, its not used on the ANT contract
|
|
1073
|
+
notifyOwners = false, }, options) {
|
|
712
1074
|
return this.process.send({
|
|
713
1075
|
tags: [
|
|
714
1076
|
...(options?.tags ?? []),
|
|
@@ -721,5 +1083,83 @@ class AoANTWriteable extends AoANTReadable {
|
|
|
721
1083
|
signer: this.signer,
|
|
722
1084
|
});
|
|
723
1085
|
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Upgrade this ANT by forking it to the latest version and reassigning names.
|
|
1088
|
+
*
|
|
1089
|
+
* This is a convenience method that calls the static ANT.upgrade() method
|
|
1090
|
+
* using this instance's process ID and signer.
|
|
1091
|
+
*
|
|
1092
|
+
* current version with latest ANT registry version and skip if already up to date.
|
|
1093
|
+
*
|
|
1094
|
+
* @param names @type {string[]} The ArNS names to reassign to the upgraded ANT.
|
|
1095
|
+
* @param arioProcessId @type {string} The processId of the ARIO contract.
|
|
1096
|
+
* @param antRegistryId @type {string} Optional ANT registry ID.
|
|
1097
|
+
* @param onSigningProgress Progress callback function.
|
|
1098
|
+
* @returns {Promise} The upgrade results.
|
|
1099
|
+
* @example
|
|
1100
|
+
* ```ts
|
|
1101
|
+
* const result = await ant.upgrade({
|
|
1102
|
+
* names: ["example", "test"],
|
|
1103
|
+
* arioProcessId: ARIO_MAINNET_PROCESS_ID
|
|
1104
|
+
* });
|
|
1105
|
+
* console.log(`Upgraded to process: ${result.forkedProcessId}`);
|
|
1106
|
+
* ```
|
|
1107
|
+
*/
|
|
1108
|
+
async upgrade(params) {
|
|
1109
|
+
const { names, reassignAffiliatedNames, arioProcessId, antRegistryId, skipVersionCheck, onSigningProgress, } = params ?? {};
|
|
1110
|
+
// Determine if we should reassign all names or specific names
|
|
1111
|
+
const shouldReassignAll = names === undefined || names.length === 0
|
|
1112
|
+
? (reassignAffiliatedNames ?? true)
|
|
1113
|
+
: false;
|
|
1114
|
+
if (shouldReassignAll) {
|
|
1115
|
+
return ANT.upgrade({
|
|
1116
|
+
signer: this.signer,
|
|
1117
|
+
antProcessId: this.processId,
|
|
1118
|
+
ao: this.process.ao,
|
|
1119
|
+
hyperbeamUrl: this.hyperbeamUrl?.toString(),
|
|
1120
|
+
reassignAffiliatedNames: true,
|
|
1121
|
+
arioProcessId: arioProcessId,
|
|
1122
|
+
antRegistryId: antRegistryId,
|
|
1123
|
+
onSigningProgress: onSigningProgress,
|
|
1124
|
+
skipVersionCheck: skipVersionCheck,
|
|
1125
|
+
});
|
|
1126
|
+
}
|
|
1127
|
+
else {
|
|
1128
|
+
return ANT.upgrade({
|
|
1129
|
+
signer: this.signer,
|
|
1130
|
+
antProcessId: this.processId,
|
|
1131
|
+
ao: this.process.ao,
|
|
1132
|
+
hyperbeamUrl: this.hyperbeamUrl?.toString(),
|
|
1133
|
+
names: names,
|
|
1134
|
+
reassignAffiliatedNames: false,
|
|
1135
|
+
arioProcessId: arioProcessId,
|
|
1136
|
+
antRegistryId: antRegistryId,
|
|
1137
|
+
onSigningProgress: onSigningProgress,
|
|
1138
|
+
skipVersionCheck: skipVersionCheck,
|
|
1139
|
+
});
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
/**
|
|
1143
|
+
* Transfers ownership of a specific record (undername) to another address. This allows delegation of control for individual records within an ANT while maintaining the ANT owner's ultimate authority.
|
|
1144
|
+
*
|
|
1145
|
+
* @param undername @type {string} The subdomain/record whose ownership you want to transfer.
|
|
1146
|
+
* @param recipient @type {string} The address of the new owner for this record.
|
|
1147
|
+
* @returns {Promise<AoMessageResult>} The result of the interaction.
|
|
1148
|
+
* @example
|
|
1149
|
+
* ```ts
|
|
1150
|
+
* ant.transferRecord({ undername: "alice", recipient: "new-owner-address-123..." }); // transfers ownership of the "alice" record to the new owner
|
|
1151
|
+
* ```
|
|
1152
|
+
*/
|
|
1153
|
+
async transferRecord({ undername, recipient, }, options) {
|
|
1154
|
+
return this.process.send({
|
|
1155
|
+
tags: [
|
|
1156
|
+
...(options?.tags ?? []),
|
|
1157
|
+
{ name: 'Action', value: 'Transfer-Record' },
|
|
1158
|
+
{ name: 'Sub-Domain', value: undername },
|
|
1159
|
+
{ name: 'Recipient', value: recipient },
|
|
1160
|
+
],
|
|
1161
|
+
signer: this.signer,
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
724
1164
|
}
|
|
725
1165
|
exports.AoANTWriteable = AoANTWriteable;
|
package/lib/cjs/common/io.js
CHANGED
|
@@ -684,12 +684,12 @@ class ARIOReadable {
|
|
|
684
684
|
* @returns {Promise<AoArNSNameData[]>} The ARNS names associated with the address
|
|
685
685
|
*/
|
|
686
686
|
async getArNSRecordsForAddress(params) {
|
|
687
|
-
const {
|
|
687
|
+
const { antRegistryProcessId = constants_js_1.ANT_REGISTRY_ID, address } = params;
|
|
688
688
|
const antRegistry = ant_registry_js_1.ANTRegistry.init({
|
|
689
689
|
hyperbeamUrl: this.hyperbeamUrl,
|
|
690
690
|
process: new ao_process_js_1.AOProcess({
|
|
691
691
|
ao: this.process.ao,
|
|
692
|
-
processId:
|
|
692
|
+
processId: antRegistryProcessId,
|
|
693
693
|
}),
|
|
694
694
|
});
|
|
695
695
|
// Note: there could be a race condition here if the ACL changes during pagination requests, resulting in different results from the `getArNSRecords`.
|
package/lib/cjs/constants.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_SCHEDULER_ID = exports.AO_AUTHORITY = exports.ANT_LUA_ID = exports.AOS_MODULE_ID = exports.MARIO_PER_ARIO = exports.ANT_REGISTRY_ID = exports.ARIO_MAINNET_PROCESS_ID = exports.ARIO_TESTNET_PROCESS_ID = exports.arioDevnetProcessId = exports.ARIO_DEVNET_PROCESS_ID = exports.FQDN_REGEX = exports.ARWEAVE_TX_REGEX = void 0;
|
|
3
|
+
exports.DEFAULT_SCHEDULER_ID = exports.AO_AUTHORITY = exports.ANT_LUA_ID = exports.AOS_MODULE_ID = exports.MARIO_PER_ARIO = exports.ANT_REGISTRY_ID = exports.ANT_REGISTRY_TESTNET_ID = exports.ARIO_MAINNET_PROCESS_ID = exports.ARIO_TESTNET_PROCESS_ID = exports.arioDevnetProcessId = exports.ARIO_DEVNET_PROCESS_ID = exports.FQDN_REGEX = exports.ARWEAVE_TX_REGEX = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
|
|
6
6
|
*
|
|
@@ -24,6 +24,7 @@ exports.ARIO_DEVNET_PROCESS_ID = 'GaQrvEMKBpkjofgnBi_B3IgIDmY_XYelVLB6GcRGrHc';
|
|
|
24
24
|
exports.arioDevnetProcessId = exports.ARIO_DEVNET_PROCESS_ID;
|
|
25
25
|
exports.ARIO_TESTNET_PROCESS_ID = 'agYcCFJtrMG6cqMuZfskIkFTGvUPddICmtQSBIoPdiA';
|
|
26
26
|
exports.ARIO_MAINNET_PROCESS_ID = 'qNvAoz0TgcH7DMg8BCVn8jF32QH5L6T29VjHxhHqqGE';
|
|
27
|
+
exports.ANT_REGISTRY_TESTNET_ID = 'RR0vheYqtsKuJCWh6xj0beE35tjaEug5cejMw9n2aa8';
|
|
27
28
|
exports.ANT_REGISTRY_ID = 'i_le_yKKPVstLTDSmkHRqf-wYphMnwB9OhleiTgMkWc';
|
|
28
29
|
exports.MARIO_PER_ARIO = 1_000_000;
|
|
29
30
|
/**
|
package/lib/cjs/types/ant.js
CHANGED
|
@@ -55,6 +55,23 @@ exports.AntRecordSchema = zod_1.z.object({
|
|
|
55
55
|
transactionId: exports.ArweaveTxIdSchema.describe('The Target ID of the undername'),
|
|
56
56
|
ttlSeconds: zod_1.z.number(),
|
|
57
57
|
priority: zod_1.z.number().optional(),
|
|
58
|
+
owner: exports.AOAddressSchema.describe('The owner address of the record').optional(),
|
|
59
|
+
displayName: zod_1.z
|
|
60
|
+
.string()
|
|
61
|
+
.max(61)
|
|
62
|
+
.describe('Display name of the record (max 61 chars)')
|
|
63
|
+
.optional(),
|
|
64
|
+
logo: exports.ArweaveTxIdSchema.describe('Logo transaction ID for the record').optional(),
|
|
65
|
+
description: zod_1.z
|
|
66
|
+
.string()
|
|
67
|
+
.max(512)
|
|
68
|
+
.describe('Description of the record (max 512 chars)')
|
|
69
|
+
.optional(),
|
|
70
|
+
keywords: zod_1.z
|
|
71
|
+
.array(zod_1.z.string().max(32))
|
|
72
|
+
.max(16)
|
|
73
|
+
.describe('Keywords array (max 16, each max 32 chars)')
|
|
74
|
+
.optional(),
|
|
58
75
|
});
|
|
59
76
|
exports.AntRecordsSchema = zod_1.z.record(zod_1.z.string(), exports.AntRecordSchema);
|
|
60
77
|
exports.AntControllersSchema = zod_1.z.array(exports.AOAddressSchema.describe('Controller address'));
|
|
@@ -120,6 +137,7 @@ exports.AntWriteHandlers = [
|
|
|
120
137
|
'reassignName',
|
|
121
138
|
'approvePrimaryName',
|
|
122
139
|
'removePrimaryNames',
|
|
140
|
+
'transferRecordOwnership',
|
|
123
141
|
];
|
|
124
142
|
exports.AntHandlerNames = [...exports.AntReadHandlers, ...exports.AntWriteHandlers];
|
|
125
143
|
exports.AntHandlersSchema = zod_1.z
|
package/lib/cjs/utils/ant.js
CHANGED
|
@@ -41,6 +41,9 @@ const sortANTRecords = (antRecords) => {
|
|
|
41
41
|
return Object.fromEntries(sortedEntries.map(([a, aRecord], index) => [a, { ...aRecord, index }]));
|
|
42
42
|
};
|
|
43
43
|
exports.sortANTRecords = sortANTRecords;
|
|
44
|
+
/**
|
|
45
|
+
* @deprecated - this is no longer necessary because HyperBeam now uses the AoANTState type
|
|
46
|
+
*/
|
|
44
47
|
const isHyperBeamANTState = (state) => {
|
|
45
48
|
return ('name' in state &&
|
|
46
49
|
'ticker' in state &&
|
|
@@ -59,6 +62,7 @@ exports.isHyperBeamANTState = isHyperBeamANTState;
|
|
|
59
62
|
/**
|
|
60
63
|
* Convert HyperBeam serialized ANT state to backwards compatible format.
|
|
61
64
|
*
|
|
65
|
+
* @deprecated - this is no longer necessary because HyperBeam now uses the AOANTState type
|
|
62
66
|
* @param state - The HyperBeam serialized ANT state.
|
|
63
67
|
*/
|
|
64
68
|
const convertHyperBeamStateToAoANTState = (initialState) => {
|
package/lib/cjs/utils/ao.js
CHANGED
|
@@ -223,7 +223,7 @@ async function spawnANT({ signer, module, ao = (0, aoconnect_1.connect)({
|
|
|
223
223
|
}
|
|
224
224
|
return processId;
|
|
225
225
|
}
|
|
226
|
-
async function forkANT({ signer, antProcessId, logger = index_js_1.Logger.default, ao, antRegistryId = constants_js_1.ANT_REGISTRY_ID, onSigningProgress = (name, payload) => {
|
|
226
|
+
async function forkANT({ signer, antProcessId, logger = index_js_1.Logger.default, ao, moduleId, antRegistryId = constants_js_1.ANT_REGISTRY_ID, onSigningProgress = (name, payload) => {
|
|
227
227
|
logger.debug('Forking ANT', { name, payload });
|
|
228
228
|
}, }) {
|
|
229
229
|
// get the state of the current ANT and use it to spawn a new ANT
|
|
@@ -241,7 +241,9 @@ async function forkANT({ signer, antProcessId, logger = index_js_1.Logger.defaul
|
|
|
241
241
|
const forkedProcessId = await spawnANT({
|
|
242
242
|
signer,
|
|
243
243
|
antRegistryId,
|
|
244
|
+
ao,
|
|
244
245
|
logger,
|
|
246
|
+
module: moduleId,
|
|
245
247
|
onSigningProgress,
|
|
246
248
|
state: {
|
|
247
249
|
owner: state.Owner,
|
|
@@ -26,7 +26,7 @@ const io_js_1 = require("../common/io.js");
|
|
|
26
26
|
const logger_js_1 = require("../common/logger.js");
|
|
27
27
|
const constants_js_1 = require("../constants.js");
|
|
28
28
|
/**
|
|
29
|
-
* @
|
|
29
|
+
* @deprecated Use getArNSRecordsForAddress instead
|
|
30
30
|
*/
|
|
31
31
|
const getANTProcessesOwnedByWallet = async ({ address, registry = ant_registry_js_1.ANTRegistry.init(), }) => {
|
|
32
32
|
const res = await registry.accessControlList({ address });
|
package/lib/cjs/version.js
CHANGED