@silvana-one/coordination 1.0.15
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/LICENSE +201 -0
- package/README.md +1 -0
- package/dist/node/agent.d.ts +93 -0
- package/dist/node/agent.js +278 -0
- package/dist/node/agent.js.map +1 -0
- package/dist/node/base58/base58.d.ts +5 -0
- package/dist/node/base58/base58.js +108 -0
- package/dist/node/base58/base58.js.map +1 -0
- package/dist/node/base58/bigint-helpers.d.ts +24 -0
- package/dist/node/base58/bigint-helpers.js +214 -0
- package/dist/node/base58/bigint-helpers.js.map +1 -0
- package/dist/node/base58/index.d.ts +2 -0
- package/dist/node/base58/index.js +3 -0
- package/dist/node/base58/index.js.map +1 -0
- package/dist/node/base58/public-key.d.ts +4 -0
- package/dist/node/base58/public-key.js +7 -0
- package/dist/node/base58/public-key.js.map +1 -0
- package/dist/node/base58/signature.d.ts +3 -0
- package/dist/node/base58/signature.js +65 -0
- package/dist/node/base58/signature.js.map +1 -0
- package/dist/node/base58/versions.d.ts +11 -0
- package/dist/node/base58/versions.js +12 -0
- package/dist/node/base58/versions.js.map +1 -0
- package/dist/node/execute.d.ts +16 -0
- package/dist/node/execute.js +142 -0
- package/dist/node/execute.js.map +1 -0
- package/dist/node/fetch.d.ts +8 -0
- package/dist/node/fetch.js +41 -0
- package/dist/node/fetch.js.map +1 -0
- package/dist/node/index.cjs +878 -0
- package/dist/node/index.d.ts +9 -0
- package/dist/node/index.js +10 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node/mvr.d.ts +14 -0
- package/dist/node/mvr.js +70 -0
- package/dist/node/mvr.js.map +1 -0
- package/dist/node/publish.d.ts +9 -0
- package/dist/node/publish.js +40 -0
- package/dist/node/publish.js.map +1 -0
- package/dist/node/sleep.d.ts +1 -0
- package/dist/node/sleep.js +4 -0
- package/dist/node/sleep.js.map +1 -0
- package/dist/node/sui-client.d.ts +4 -0
- package/dist/node/sui-client.js +39 -0
- package/dist/node/sui-client.js.map +1 -0
- package/dist/node/types.d.ts +4 -0
- package/dist/node/types.js +2 -0
- package/dist/node/types.js.map +1 -0
- package/dist/node/upgrade.d.ts +13 -0
- package/dist/node/upgrade.js +51 -0
- package/dist/node/upgrade.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/tsconfig.web.tsbuildinfo +1 -0
- package/dist/web/agent.d.ts +93 -0
- package/dist/web/agent.js +278 -0
- package/dist/web/agent.js.map +1 -0
- package/dist/web/base58/base58.d.ts +5 -0
- package/dist/web/base58/base58.js +108 -0
- package/dist/web/base58/base58.js.map +1 -0
- package/dist/web/base58/bigint-helpers.d.ts +24 -0
- package/dist/web/base58/bigint-helpers.js +214 -0
- package/dist/web/base58/bigint-helpers.js.map +1 -0
- package/dist/web/base58/index.d.ts +2 -0
- package/dist/web/base58/index.js +3 -0
- package/dist/web/base58/index.js.map +1 -0
- package/dist/web/base58/public-key.d.ts +4 -0
- package/dist/web/base58/public-key.js +7 -0
- package/dist/web/base58/public-key.js.map +1 -0
- package/dist/web/base58/signature.d.ts +3 -0
- package/dist/web/base58/signature.js +65 -0
- package/dist/web/base58/signature.js.map +1 -0
- package/dist/web/base58/versions.d.ts +11 -0
- package/dist/web/base58/versions.js +12 -0
- package/dist/web/base58/versions.js.map +1 -0
- package/dist/web/execute.d.ts +16 -0
- package/dist/web/execute.js +142 -0
- package/dist/web/execute.js.map +1 -0
- package/dist/web/fetch.d.ts +8 -0
- package/dist/web/fetch.js +41 -0
- package/dist/web/fetch.js.map +1 -0
- package/dist/web/index.d.ts +9 -0
- package/dist/web/index.js +10 -0
- package/dist/web/index.js.map +1 -0
- package/dist/web/mvr.d.ts +14 -0
- package/dist/web/mvr.js +70 -0
- package/dist/web/mvr.js.map +1 -0
- package/dist/web/publish.d.ts +9 -0
- package/dist/web/publish.js +40 -0
- package/dist/web/publish.js.map +1 -0
- package/dist/web/sleep.d.ts +1 -0
- package/dist/web/sleep.js +4 -0
- package/dist/web/sleep.js.map +1 -0
- package/dist/web/sui-client.d.ts +4 -0
- package/dist/web/sui-client.js +39 -0
- package/dist/web/sui-client.js.map +1 -0
- package/dist/web/types.d.ts +4 -0
- package/dist/web/types.js +2 -0
- package/dist/web/types.js.map +1 -0
- package/dist/web/upgrade.d.ts +13 -0
- package/dist/web/upgrade.js +51 -0
- package/dist/web/upgrade.js.map +1 -0
- package/package.json +59 -0
- package/src/agent.ts +437 -0
- package/src/base58/base58.ts +121 -0
- package/src/base58/bigint-helpers.ts +236 -0
- package/src/base58/index.ts +2 -0
- package/src/base58/public-key.ts +13 -0
- package/src/base58/signature.ts +89 -0
- package/src/base58/versions.ts +12 -0
- package/src/execute.ts +176 -0
- package/src/fetch.ts +54 -0
- package/src/index.ts +9 -0
- package/src/mvr.ts +99 -0
- package/src/publish.ts +54 -0
- package/src/sleep.ts +3 -0
- package/src/sui-client.ts +42 -0
- package/src/types.ts +4 -0
- package/src/upgrade.ts +78 -0
package/src/agent.ts
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
import { Transaction } from "@mysten/sui/transactions";
|
|
2
|
+
import { SUI_CLOCK_OBJECT_ID } from "@mysten/sui/utils";
|
|
3
|
+
import { fetchSuiDynamicField } from "./fetch.js";
|
|
4
|
+
|
|
5
|
+
export interface Agent {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
image?: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
site?: string;
|
|
11
|
+
dockerImage: string;
|
|
12
|
+
dockerSha256?: string;
|
|
13
|
+
minMemoryGb: number;
|
|
14
|
+
minCpuCores: number;
|
|
15
|
+
supportsTEE: boolean;
|
|
16
|
+
createdAt: number;
|
|
17
|
+
updatedAt: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface Developer {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
github: string;
|
|
24
|
+
image?: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
site?: string;
|
|
27
|
+
owner: string;
|
|
28
|
+
createdAt: number;
|
|
29
|
+
updatedAt: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class AgentRegistry {
|
|
33
|
+
private readonly registry: string;
|
|
34
|
+
|
|
35
|
+
constructor(params: { registry: string }) {
|
|
36
|
+
this.registry = params.registry;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static createAgentRegistry(params: { name: string }): Transaction {
|
|
40
|
+
console.log("Creating agent registry", params.name);
|
|
41
|
+
const transaction = new Transaction();
|
|
42
|
+
transaction.moveCall({
|
|
43
|
+
target: `@silvana/agent::registry::create_registry`,
|
|
44
|
+
arguments: [transaction.pure.string(params.name)],
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return transaction;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
createDeveloper(params: {
|
|
51
|
+
name: string;
|
|
52
|
+
github: string;
|
|
53
|
+
image?: string;
|
|
54
|
+
description?: string;
|
|
55
|
+
site?: string;
|
|
56
|
+
}): Transaction {
|
|
57
|
+
const { name, github, image, description, site } = params;
|
|
58
|
+
const tx = new Transaction();
|
|
59
|
+
|
|
60
|
+
tx.moveCall({
|
|
61
|
+
target: `@silvana/agent::registry::add_developer`,
|
|
62
|
+
arguments: [
|
|
63
|
+
tx.object(this.registry),
|
|
64
|
+
tx.pure.string(name),
|
|
65
|
+
tx.pure.string(github),
|
|
66
|
+
tx.pure.option("string", image ?? null),
|
|
67
|
+
tx.pure.option("string", description ?? null),
|
|
68
|
+
tx.pure.option("string", site ?? null),
|
|
69
|
+
tx.object(SUI_CLOCK_OBJECT_ID),
|
|
70
|
+
],
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
return tx;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
updateDeveloper(params: {
|
|
77
|
+
name: string;
|
|
78
|
+
github: string;
|
|
79
|
+
image?: string;
|
|
80
|
+
description?: string;
|
|
81
|
+
site?: string;
|
|
82
|
+
}): Transaction {
|
|
83
|
+
const { name, github, image, description, site } = params;
|
|
84
|
+
const tx = new Transaction();
|
|
85
|
+
|
|
86
|
+
tx.moveCall({
|
|
87
|
+
target: `@silvana/agent::registry::update_developer`,
|
|
88
|
+
arguments: [
|
|
89
|
+
tx.object(this.registry),
|
|
90
|
+
tx.pure.string(name),
|
|
91
|
+
tx.pure.string(github),
|
|
92
|
+
tx.pure.option("string", image ?? null),
|
|
93
|
+
tx.pure.option("string", description ?? null),
|
|
94
|
+
tx.pure.option("string", site ?? null),
|
|
95
|
+
tx.object(SUI_CLOCK_OBJECT_ID),
|
|
96
|
+
],
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return tx;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
removeDeveloper(params: { name: string }): Transaction {
|
|
103
|
+
const { name } = params;
|
|
104
|
+
const tx = new Transaction();
|
|
105
|
+
|
|
106
|
+
tx.moveCall({
|
|
107
|
+
target: `@silvana/agent::registry::remove_developer`,
|
|
108
|
+
arguments: [tx.object(this.registry), tx.pure.string(name)],
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
return tx;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
createAgent(params: {
|
|
115
|
+
developer: string;
|
|
116
|
+
name: string;
|
|
117
|
+
image?: string;
|
|
118
|
+
description?: string;
|
|
119
|
+
site?: string;
|
|
120
|
+
docker_image: string;
|
|
121
|
+
docker_sha256?: string;
|
|
122
|
+
min_memory_gb: number;
|
|
123
|
+
min_cpu_cores: number;
|
|
124
|
+
supports_tee: boolean;
|
|
125
|
+
}): Transaction {
|
|
126
|
+
const {
|
|
127
|
+
developer,
|
|
128
|
+
name,
|
|
129
|
+
image,
|
|
130
|
+
description,
|
|
131
|
+
site,
|
|
132
|
+
docker_image,
|
|
133
|
+
docker_sha256,
|
|
134
|
+
min_memory_gb,
|
|
135
|
+
min_cpu_cores,
|
|
136
|
+
supports_tee,
|
|
137
|
+
} = params;
|
|
138
|
+
const tx = new Transaction();
|
|
139
|
+
|
|
140
|
+
tx.moveCall({
|
|
141
|
+
target: `@silvana/agent::registry::add_agent`,
|
|
142
|
+
arguments: [
|
|
143
|
+
tx.object(this.registry),
|
|
144
|
+
tx.pure.string(developer),
|
|
145
|
+
tx.pure.string(name),
|
|
146
|
+
tx.pure.option("string", image ?? null),
|
|
147
|
+
tx.pure.option("string", description ?? null),
|
|
148
|
+
tx.pure.option("string", site ?? null),
|
|
149
|
+
tx.pure.string(docker_image),
|
|
150
|
+
tx.pure.option("string", docker_sha256 ?? null),
|
|
151
|
+
tx.pure.u16(min_memory_gb),
|
|
152
|
+
tx.pure.u16(min_cpu_cores),
|
|
153
|
+
tx.pure.bool(supports_tee),
|
|
154
|
+
tx.object(SUI_CLOCK_OBJECT_ID),
|
|
155
|
+
],
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
return tx;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
updateAgent(params: {
|
|
162
|
+
developer: string;
|
|
163
|
+
name: string;
|
|
164
|
+
image?: string;
|
|
165
|
+
description?: string;
|
|
166
|
+
site?: string;
|
|
167
|
+
docker_image: string;
|
|
168
|
+
docker_sha256?: string;
|
|
169
|
+
min_memory_gb: number;
|
|
170
|
+
min_cpu_cores: number;
|
|
171
|
+
supports_tee: boolean;
|
|
172
|
+
}): Transaction {
|
|
173
|
+
const {
|
|
174
|
+
developer,
|
|
175
|
+
name,
|
|
176
|
+
image,
|
|
177
|
+
description,
|
|
178
|
+
site,
|
|
179
|
+
docker_image,
|
|
180
|
+
docker_sha256,
|
|
181
|
+
min_memory_gb,
|
|
182
|
+
min_cpu_cores,
|
|
183
|
+
supports_tee,
|
|
184
|
+
} = params;
|
|
185
|
+
const tx = new Transaction();
|
|
186
|
+
|
|
187
|
+
tx.moveCall({
|
|
188
|
+
target: `@silvana/agent::registry::update_agent`,
|
|
189
|
+
arguments: [
|
|
190
|
+
tx.object(this.registry),
|
|
191
|
+
tx.pure.string(developer),
|
|
192
|
+
tx.pure.string(name),
|
|
193
|
+
tx.pure.option("string", image ?? null),
|
|
194
|
+
tx.pure.option("string", description ?? null),
|
|
195
|
+
tx.pure.option("string", site ?? null),
|
|
196
|
+
tx.pure.string(docker_image),
|
|
197
|
+
tx.pure.option("string", docker_sha256 ?? null),
|
|
198
|
+
tx.pure.u16(min_memory_gb),
|
|
199
|
+
tx.pure.u16(min_cpu_cores),
|
|
200
|
+
tx.pure.bool(supports_tee),
|
|
201
|
+
tx.object(SUI_CLOCK_OBJECT_ID),
|
|
202
|
+
],
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
return tx;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
removeAgent(params: { developer: string; agent: string }): Transaction {
|
|
209
|
+
const { developer, agent } = params;
|
|
210
|
+
const tx = new Transaction();
|
|
211
|
+
|
|
212
|
+
tx.moveCall({
|
|
213
|
+
target: `@silvana/agent::registry::remove_agent`,
|
|
214
|
+
arguments: [
|
|
215
|
+
tx.object(this.registry),
|
|
216
|
+
tx.pure.string(developer),
|
|
217
|
+
tx.pure.string(agent),
|
|
218
|
+
],
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
return tx;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async getDeveloper(params: { name: string }): Promise<Developer | undefined> {
|
|
225
|
+
const developerObject = await fetchSuiDynamicField({
|
|
226
|
+
objectID: this.registry,
|
|
227
|
+
fieldName: "developers",
|
|
228
|
+
type: "0x1::string::String",
|
|
229
|
+
key: params.name,
|
|
230
|
+
});
|
|
231
|
+
if (!developerObject) {
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
const developer = {
|
|
235
|
+
id: (developerObject as any)?.id?.id,
|
|
236
|
+
name: (developerObject as any).name,
|
|
237
|
+
github: (developerObject as any).github,
|
|
238
|
+
image: (developerObject as any)?.image ?? undefined,
|
|
239
|
+
description: (developerObject as any)?.description ?? undefined,
|
|
240
|
+
site: (developerObject as any)?.site ?? undefined,
|
|
241
|
+
owner: (developerObject as any).owner,
|
|
242
|
+
createdAt: Number((developerObject as any).created_at),
|
|
243
|
+
updatedAt: Number((developerObject as any).updated_at),
|
|
244
|
+
};
|
|
245
|
+
if (
|
|
246
|
+
!developer.id ||
|
|
247
|
+
!developer.name ||
|
|
248
|
+
!developer.github ||
|
|
249
|
+
!developer.owner ||
|
|
250
|
+
!developer.createdAt ||
|
|
251
|
+
!developer.updatedAt
|
|
252
|
+
) {
|
|
253
|
+
return undefined;
|
|
254
|
+
}
|
|
255
|
+
return developer as Developer;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async getAgent(params: {
|
|
259
|
+
developer: string;
|
|
260
|
+
agent: string;
|
|
261
|
+
}): Promise<Agent | undefined> {
|
|
262
|
+
const developerObject = await fetchSuiDynamicField({
|
|
263
|
+
objectID: this.registry,
|
|
264
|
+
fieldName: "developers",
|
|
265
|
+
type: "0x1::string::String",
|
|
266
|
+
key: params.developer,
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
const id = (developerObject as any)?.agents?.fields?.id?.id;
|
|
270
|
+
if (!id) {
|
|
271
|
+
return undefined;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const agentObject = await fetchSuiDynamicField({
|
|
275
|
+
parentID: id,
|
|
276
|
+
fieldName: "agents",
|
|
277
|
+
type: "0x1::string::String",
|
|
278
|
+
key: params.agent,
|
|
279
|
+
});
|
|
280
|
+
if (!agentObject) {
|
|
281
|
+
return undefined;
|
|
282
|
+
}
|
|
283
|
+
const agent = {
|
|
284
|
+
id: (agentObject as any)?.id?.id,
|
|
285
|
+
name: (agentObject as any).name,
|
|
286
|
+
image: (agentObject as any)?.image ?? undefined,
|
|
287
|
+
description: (agentObject as any)?.description ?? undefined,
|
|
288
|
+
site: (agentObject as any)?.site ?? undefined,
|
|
289
|
+
dockerImage: (agentObject as any).docker_image,
|
|
290
|
+
dockerSha256: (agentObject as any)?.docker_sha256 ?? undefined,
|
|
291
|
+
minMemoryGb: Number((agentObject as any).min_memory_gb),
|
|
292
|
+
minCpuCores: Number((agentObject as any).min_cpu_cores),
|
|
293
|
+
supportsTEE: Boolean((agentObject as any).supports_tee),
|
|
294
|
+
createdAt: Number((agentObject as any).created_at),
|
|
295
|
+
updatedAt: Number((agentObject as any).updated_at),
|
|
296
|
+
};
|
|
297
|
+
if (
|
|
298
|
+
!agent.id ||
|
|
299
|
+
!agent.name ||
|
|
300
|
+
!agent.dockerImage ||
|
|
301
|
+
!agent.minMemoryGb ||
|
|
302
|
+
!agent.minCpuCores ||
|
|
303
|
+
!agent.createdAt ||
|
|
304
|
+
!agent.updatedAt
|
|
305
|
+
) {
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
return agent as Agent;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
static async getDockerImageDetails(params: { dockerImage: string }): Promise<
|
|
312
|
+
| {
|
|
313
|
+
sha256: string;
|
|
314
|
+
numberOfLayers: number;
|
|
315
|
+
}
|
|
316
|
+
| undefined
|
|
317
|
+
> {
|
|
318
|
+
try {
|
|
319
|
+
const { dockerImage } = params;
|
|
320
|
+
|
|
321
|
+
// Parse image_source to extract repository and tag
|
|
322
|
+
const colonPos = dockerImage.lastIndexOf(":");
|
|
323
|
+
const repository =
|
|
324
|
+
colonPos !== -1 ? dockerImage.slice(0, colonPos) : dockerImage;
|
|
325
|
+
const tag = colonPos !== -1 ? dockerImage.slice(colonPos + 1) : "latest";
|
|
326
|
+
|
|
327
|
+
// 1. Get token
|
|
328
|
+
const tokenResponse = await fetch(
|
|
329
|
+
"https://auth.docker.io/token?" +
|
|
330
|
+
new URLSearchParams({
|
|
331
|
+
service: "registry.docker.io",
|
|
332
|
+
scope: `repository:${repository}:pull`,
|
|
333
|
+
})
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
if (!tokenResponse.ok) {
|
|
337
|
+
return undefined;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const tokenData = await tokenResponse.json();
|
|
341
|
+
const token = tokenData.token;
|
|
342
|
+
|
|
343
|
+
if (!token) {
|
|
344
|
+
return undefined;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// 2. Fetch manifest/index
|
|
348
|
+
const manifestResponse = await fetch(
|
|
349
|
+
`https://registry-1.docker.io/v2/${repository}/manifests/${tag}`,
|
|
350
|
+
{
|
|
351
|
+
headers: {
|
|
352
|
+
Authorization: `Bearer ${token}`,
|
|
353
|
+
Accept:
|
|
354
|
+
"application/vnd.docker.distribution.manifest.list.v2+json, application/vnd.oci.image.index.v1+json, application/vnd.docker.distribution.manifest.v2+json",
|
|
355
|
+
},
|
|
356
|
+
}
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
if (!manifestResponse.ok) {
|
|
360
|
+
return undefined;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const contentType = manifestResponse.headers.get("content-type") || "";
|
|
364
|
+
|
|
365
|
+
// Extract the digest from the response headers
|
|
366
|
+
let digest = manifestResponse.headers.get("docker-content-digest") || "";
|
|
367
|
+
|
|
368
|
+
let manifest: any;
|
|
369
|
+
|
|
370
|
+
if (contentType.includes("index") || contentType.includes("list")) {
|
|
371
|
+
// This is a manifest index (multi-platform)
|
|
372
|
+
const idx = await manifestResponse.json();
|
|
373
|
+
|
|
374
|
+
// Pick amd64/linux manifest
|
|
375
|
+
const platformManifest = idx.manifests?.find(
|
|
376
|
+
(m: any) =>
|
|
377
|
+
m.platform?.architecture === "amd64" && m.platform?.os === "linux"
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
if (!platformManifest) {
|
|
381
|
+
return undefined;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const platformDigest = platformManifest.digest;
|
|
385
|
+
|
|
386
|
+
// 3. Fetch the actual manifest
|
|
387
|
+
const actualManifestResponse = await fetch(
|
|
388
|
+
`https://registry-1.docker.io/v2/${repository}/manifests/${platformDigest}`,
|
|
389
|
+
{
|
|
390
|
+
headers: {
|
|
391
|
+
Authorization: `Bearer ${token}`,
|
|
392
|
+
Accept: "application/vnd.docker.distribution.manifest.v2+json",
|
|
393
|
+
},
|
|
394
|
+
}
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
if (!actualManifestResponse.ok) {
|
|
398
|
+
return undefined;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
manifest = await actualManifestResponse.json();
|
|
402
|
+
|
|
403
|
+
// Update digest from the actual manifest response
|
|
404
|
+
const actualDigest = actualManifestResponse.headers.get(
|
|
405
|
+
"docker-content-digest"
|
|
406
|
+
);
|
|
407
|
+
if (actualDigest) {
|
|
408
|
+
digest = actualDigest;
|
|
409
|
+
}
|
|
410
|
+
} else {
|
|
411
|
+
// This is already a direct manifest (single platform)
|
|
412
|
+
manifest = await manifestResponse.json();
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (!manifest?.layers || !Array.isArray(manifest.layers)) {
|
|
416
|
+
return undefined;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const numberOfLayers = manifest.layers.length;
|
|
420
|
+
|
|
421
|
+
// Remove the "sha256:" prefix if present
|
|
422
|
+
const sha256 = digest.startsWith("sha256:") ? digest.slice(7) : digest;
|
|
423
|
+
|
|
424
|
+
if (!sha256) {
|
|
425
|
+
return undefined;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return {
|
|
429
|
+
sha256,
|
|
430
|
+
numberOfLayers,
|
|
431
|
+
};
|
|
432
|
+
} catch (error) {
|
|
433
|
+
console.error("Error fetching Docker image details:", error);
|
|
434
|
+
return undefined;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { sha256 } from "js-sha256";
|
|
2
|
+
import { changeBase } from "./bigint-helpers.js";
|
|
3
|
+
|
|
4
|
+
export { fromBase58Check, alphabet };
|
|
5
|
+
|
|
6
|
+
const alphabet =
|
|
7
|
+
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".split("");
|
|
8
|
+
let inverseAlphabet: Record<string, number> = {};
|
|
9
|
+
alphabet.forEach((c, i) => {
|
|
10
|
+
inverseAlphabet[c] = i;
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export function toBytesWithVersionNumber(t: bigint[], versionNumber: number) {
|
|
14
|
+
let bytes = toBytes(t, versionNumber);
|
|
15
|
+
bytes.unshift(versionNumber);
|
|
16
|
+
return bytes;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function bigIntToBytes(x: bigint, length: number) {
|
|
20
|
+
if (x < 0n) {
|
|
21
|
+
throw Error(`bigIntToBytes: negative numbers are not supported, got ${x}`);
|
|
22
|
+
}
|
|
23
|
+
let bytes: number[] = Array(length);
|
|
24
|
+
for (let i = 0; i < length; i++, x >>= 8n) {
|
|
25
|
+
bytes[i] = Number(x & 0xffn);
|
|
26
|
+
}
|
|
27
|
+
if (x > 0n) {
|
|
28
|
+
throw Error(`bigIntToBytes: input does not fit in ${length} bytes`);
|
|
29
|
+
}
|
|
30
|
+
return bytes;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function toBytes(t: bigint[], versionNumber: number) {
|
|
34
|
+
if (t.length !== 2) throw new Error("Expected 2 elements in t");
|
|
35
|
+
|
|
36
|
+
let bytes: number[] = [];
|
|
37
|
+
/*
|
|
38
|
+
let n = 2;
|
|
39
|
+
for (let i = 0; i < 2; i++) {
|
|
40
|
+
let subBytes = bigIntToBytes(t[i], 32);
|
|
41
|
+
bytes.push(...subBytes);
|
|
42
|
+
}
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
let subBytes1 = bigIntToBytes(t[0], 32);
|
|
46
|
+
subBytes1.unshift(versionNumber);
|
|
47
|
+
bytes.push(...subBytes1);
|
|
48
|
+
bytes.push(Number(t[1]));
|
|
49
|
+
|
|
50
|
+
return bytes;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function toBase58Check(
|
|
54
|
+
input: number[] | Uint8Array,
|
|
55
|
+
versionByte: number
|
|
56
|
+
) {
|
|
57
|
+
let withVersion = [versionByte, ...input];
|
|
58
|
+
let checksum = computeChecksum(withVersion);
|
|
59
|
+
let withChecksum = withVersion.concat(checksum);
|
|
60
|
+
return toBase58(withChecksum);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function toBase58(bytes: number[] | Uint8Array) {
|
|
64
|
+
// count the leading zeroes. these get turned into leading zeroes in the output
|
|
65
|
+
let z = 0;
|
|
66
|
+
while (bytes[z] === 0) z++;
|
|
67
|
+
// for some reason, this is big-endian, so we need to reverse
|
|
68
|
+
let digits = [...bytes].map(BigInt).reverse();
|
|
69
|
+
// change base and reverse
|
|
70
|
+
let base58Digits = changeBase(digits, 256n, 58n).reverse();
|
|
71
|
+
// add leading zeroes, map into alphabet
|
|
72
|
+
base58Digits = Array(z).fill(0n).concat(base58Digits);
|
|
73
|
+
return base58Digits.map((x) => alphabet[Number(x)]).join("");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function fromBase58Check(base58: string, versionByte: number) {
|
|
77
|
+
// throws on invalid character
|
|
78
|
+
let bytes = fromBase58(base58);
|
|
79
|
+
// check checksum
|
|
80
|
+
let checksum = bytes.slice(-4);
|
|
81
|
+
let originalBytes = bytes.slice(0, -4);
|
|
82
|
+
let actualChecksum = computeChecksum(originalBytes);
|
|
83
|
+
if (!arrayEqual(checksum, actualChecksum))
|
|
84
|
+
throw Error("fromBase58Check: invalid checksum");
|
|
85
|
+
// check version byte
|
|
86
|
+
if (originalBytes[0] !== versionByte)
|
|
87
|
+
throw Error(
|
|
88
|
+
`fromBase58Check: input version byte ${versionByte} does not match encoded version byte ${originalBytes[0]}`
|
|
89
|
+
);
|
|
90
|
+
// return result
|
|
91
|
+
return originalBytes.slice(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function fromBase58(base58: string) {
|
|
95
|
+
let base58Digits = [...base58].map((c) => {
|
|
96
|
+
let digit = inverseAlphabet[c];
|
|
97
|
+
if (digit === undefined) throw Error("fromBase58: invalid character");
|
|
98
|
+
return BigInt(digit);
|
|
99
|
+
});
|
|
100
|
+
let z = 0;
|
|
101
|
+
while (base58Digits[z] === 0n) z++;
|
|
102
|
+
let digits = changeBase(base58Digits.reverse(), 58n, 256n).reverse();
|
|
103
|
+
digits = Array(z).fill(0n).concat(digits);
|
|
104
|
+
return digits.map(Number);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function computeChecksum(input: number[] | Uint8Array) {
|
|
108
|
+
let hash1 = sha256.create();
|
|
109
|
+
hash1.update(input);
|
|
110
|
+
let hash2 = sha256.create();
|
|
111
|
+
hash2.update(hash1.array());
|
|
112
|
+
return hash2.array().slice(0, 4);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function arrayEqual(a: unknown[], b: unknown[]) {
|
|
116
|
+
if (a.length !== b.length) return false;
|
|
117
|
+
for (let i = 0; i < a.length; i++) {
|
|
118
|
+
if (a[i] !== b[i]) return false;
|
|
119
|
+
}
|
|
120
|
+
return true;
|
|
121
|
+
}
|