@solana-mobile/dapp-store-cli 0.16.0 → 1.0.0
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/bin/dapp-store.js +3 -1
- package/lib/CliSetup.js +304 -505
- package/lib/CliUtils.js +6 -376
- package/lib/__tests__/CliSetupTest.js +484 -74
- package/lib/cli/__tests__/parseErrors.test.js +25 -0
- package/lib/cli/__tests__/signer.test.js +436 -0
- package/lib/cli/constants.js +23 -0
- package/lib/cli/messages.js +21 -0
- package/lib/cli/parseErrors.js +41 -0
- package/lib/{commands/publish/PublishCliSupport.js → cli/selfUpdate.js} +72 -38
- package/lib/{commands/publish/PublishCliRemove.js → cli/signer.js} +35 -56
- package/lib/index.js +96 -5
- package/lib/package.json +5 -24
- package/lib/portal/__tests__/releaseMetadata.test.js +647 -0
- package/lib/portal/__tests__/translators.test.js +76 -0
- package/lib/portal/__tests__/workflowClient.test.js +457 -0
- package/lib/portal/attestationClient.js +143 -0
- package/lib/portal/files.js +64 -0
- package/lib/portal/http.js +364 -0
- package/lib/portal/records.js +64 -0
- package/lib/portal/releaseMetadata.js +748 -0
- package/lib/portal/translators.js +460 -0
- package/lib/portal/types.js +1 -0
- package/lib/portal/workflowClient.js +704 -0
- package/lib/publication/PublicationProgressReporter.js +1051 -0
- package/lib/publication/__tests__/PublicationProgressReporter.test.js +174 -0
- package/lib/{commands/ValidateCommand.js → publication/__tests__/fundingPreflight.test.js} +90 -66
- package/lib/publication/__tests__/publicationSummary.test.js +26 -0
- package/lib/publication/cliValidation.js +482 -0
- package/lib/publication/fundingPreflight.js +246 -0
- package/lib/publication/publicationSummary.js +99 -0
- package/lib/{commands/utils.js → publication/runPublicationWorkflow.js} +16 -46
- package/package.json +5 -24
- package/src/CliSetup.ts +370 -505
- package/src/CliUtils.ts +9 -233
- package/src/__tests__/CliSetupTest.ts +272 -120
- package/src/cli/__tests__/parseErrors.test.ts +34 -0
- package/src/cli/__tests__/signer.test.ts +359 -0
- package/src/cli/constants.ts +3 -0
- package/src/cli/messages.ts +27 -0
- package/src/cli/parseErrors.ts +62 -0
- package/src/cli/selfUpdate.ts +59 -0
- package/src/cli/signer.ts +38 -0
- package/src/index.ts +31 -4
- package/src/portal/__tests__/releaseMetadata.test.ts +508 -0
- package/src/portal/__tests__/translators.test.ts +82 -0
- package/src/portal/__tests__/workflowClient.test.ts +278 -0
- package/src/portal/attestationClient.ts +19 -0
- package/src/portal/files.ts +73 -0
- package/src/portal/http.ts +170 -0
- package/src/portal/records.ts +38 -0
- package/src/portal/releaseMetadata.ts +489 -0
- package/src/portal/translators.ts +750 -0
- package/src/portal/types.ts +27 -0
- package/src/portal/workflowClient.ts +575 -0
- package/src/publication/PublicationProgressReporter.ts +1026 -0
- package/src/publication/__tests__/PublicationProgressReporter.test.ts +210 -0
- package/src/publication/__tests__/fundingPreflight.test.ts +78 -0
- package/src/publication/__tests__/publicationSummary.test.ts +30 -0
- package/src/publication/cliValidation.ts +264 -0
- package/src/publication/fundingPreflight.ts +123 -0
- package/src/publication/publicationSummary.ts +26 -0
- package/src/publication/runPublicationWorkflow.ts +46 -0
- package/lib/commands/create/CreateCliApp.js +0 -223
- package/lib/commands/create/CreateCliRelease.js +0 -290
- package/lib/commands/create/index.js +0 -40
- package/lib/commands/index.js +0 -3
- package/lib/commands/publish/PublishCliSubmit.js +0 -208
- package/lib/commands/publish/PublishCliUpdate.js +0 -211
- package/lib/commands/publish/index.js +0 -22
- package/lib/commands/scaffolding/ScaffoldInit.js +0 -15
- package/lib/commands/scaffolding/index.js +0 -1
- package/lib/config/EnvVariables.js +0 -59
- package/lib/config/PublishDetails.js +0 -915
- package/lib/config/S3StorageManager.js +0 -93
- package/lib/config/index.js +0 -2
- package/lib/generated/config_obj.json +0 -1
- package/lib/generated/config_schema.json +0 -1
- package/lib/prebuild_schema/publishing_source.yaml +0 -64
- package/lib/prebuild_schema/schemagen.js +0 -25
- package/lib/upload/CachedStorageDriver.js +0 -458
- package/lib/upload/TurboStorageDriver.js +0 -718
- package/lib/upload/__tests__/CachedStorageDriver.test.js +0 -437
- package/lib/upload/__tests__/TurboStorageDriver.test.js +0 -17
- package/lib/upload/__tests__/contentGateway.test.js +0 -17
- package/lib/upload/contentGateway.js +0 -23
- package/lib/upload/index.js +0 -2
- package/src/commands/ValidateCommand.ts +0 -82
- package/src/commands/create/CreateCliApp.ts +0 -93
- package/src/commands/create/CreateCliRelease.ts +0 -149
- package/src/commands/create/index.ts +0 -47
- package/src/commands/index.ts +0 -3
- package/src/commands/publish/PublishCliRemove.ts +0 -66
- package/src/commands/publish/PublishCliSubmit.ts +0 -93
- package/src/commands/publish/PublishCliSupport.ts +0 -66
- package/src/commands/publish/PublishCliUpdate.ts +0 -101
- package/src/commands/publish/index.ts +0 -29
- package/src/commands/scaffolding/ScaffoldInit.ts +0 -20
- package/src/commands/scaffolding/index.ts +0 -1
- package/src/commands/utils.ts +0 -33
- package/src/config/EnvVariables.ts +0 -39
- package/src/config/PublishDetails.ts +0 -456
- package/src/config/S3StorageManager.ts +0 -47
- package/src/config/index.ts +0 -2
- package/src/prebuild_schema/publishing_source.yaml +0 -64
- package/src/prebuild_schema/schemagen.js +0 -31
- package/src/upload/CachedStorageDriver.ts +0 -179
- package/src/upload/TurboStorageDriver.ts +0 -283
- package/src/upload/__tests__/CachedStorageDriver.test.ts +0 -246
- package/src/upload/__tests__/TurboStorageDriver.test.ts +0 -15
- package/src/upload/__tests__/contentGateway.test.ts +0 -31
- package/src/upload/contentGateway.ts +0 -37
- package/src/upload/index.ts +0 -2
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type PortalProcedureResult<T> =
|
|
2
|
+
| {
|
|
3
|
+
_tag: 'Left';
|
|
4
|
+
left: {
|
|
5
|
+
name?: string;
|
|
6
|
+
message: string;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
| {
|
|
10
|
+
_tag: 'Right';
|
|
11
|
+
right: T;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type PortalClientConfig = {
|
|
15
|
+
apiBaseUrl: string;
|
|
16
|
+
apiKey: string;
|
|
17
|
+
dappId?: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type PortalUploadTarget = {
|
|
21
|
+
uploadUrl: string;
|
|
22
|
+
key: string;
|
|
23
|
+
providerId: string;
|
|
24
|
+
publicUrl: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type PortalSourceKind = 'portal' | 'external';
|
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
PublicationBundle,
|
|
7
|
+
PublicationCleanupReleaseInput,
|
|
8
|
+
PublicationCleanupReleaseResult,
|
|
9
|
+
PublicationCreateIngestionSessionInput,
|
|
10
|
+
PublicationCreateUploadTargetInput,
|
|
11
|
+
PublicationCreateUploadTargetResult,
|
|
12
|
+
PublicationGetBundleInput,
|
|
13
|
+
PublicationGetIngestionSessionInput,
|
|
14
|
+
PublicationGetSessionInput,
|
|
15
|
+
PublicationIngestionSession,
|
|
16
|
+
PublicationPreparedReleaseTransaction,
|
|
17
|
+
PublicationPreparedVerifyCollectionTransaction,
|
|
18
|
+
PublicationPrepareReleaseNftTransactionInput,
|
|
19
|
+
PublicationPrepareVerifyCollectionTransactionInput,
|
|
20
|
+
PublicationSaveReleaseNftDataInput,
|
|
21
|
+
PublicationSaveReleaseNftDataResult,
|
|
22
|
+
PublicationSubmitSignedTransactionResult,
|
|
23
|
+
PublicationSubmitToStoreInput,
|
|
24
|
+
PublicationSubmitToStoreResult,
|
|
25
|
+
PublicationWorkflowClient,
|
|
26
|
+
} from "@solana-mobile/dapp-store-publishing-tools";
|
|
27
|
+
|
|
28
|
+
import {
|
|
29
|
+
ensureApkFileName,
|
|
30
|
+
fromBase64,
|
|
31
|
+
inferFileNameFromUrl,
|
|
32
|
+
toBase64,
|
|
33
|
+
} from "./files.js";
|
|
34
|
+
import {
|
|
35
|
+
callCreateIngestionSessionWithRetry,
|
|
36
|
+
callPortalProcedure,
|
|
37
|
+
uploadBytes,
|
|
38
|
+
} from "./http.js";
|
|
39
|
+
import { asRecord, isRecord } from "./records.js";
|
|
40
|
+
import {
|
|
41
|
+
inferPublicationSourceKind,
|
|
42
|
+
mapBackendBundleToPublicationBundle,
|
|
43
|
+
translateBackendIngestionSession,
|
|
44
|
+
translateBackendPublicationSession,
|
|
45
|
+
} from "./translators.js";
|
|
46
|
+
import {
|
|
47
|
+
buildReleaseMetadataDocument,
|
|
48
|
+
type ReleaseMetadataPortalClient,
|
|
49
|
+
} from "./releaseMetadata.js";
|
|
50
|
+
import type { PortalClientConfig, PortalUploadTarget } from "./types.js";
|
|
51
|
+
|
|
52
|
+
type PortalBackendResult = Record<string, unknown>;
|
|
53
|
+
|
|
54
|
+
type WorkflowClientState = {
|
|
55
|
+
currentPublicationSessionId?: string;
|
|
56
|
+
currentReleaseId?: string;
|
|
57
|
+
metadataUriByReleaseId: Map<string, string>;
|
|
58
|
+
publicationSessionIdByReleaseId: Map<string, string>;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
function createWorkflowClientState(): WorkflowClientState {
|
|
62
|
+
return {
|
|
63
|
+
metadataUriByReleaseId: new Map<string, string>(),
|
|
64
|
+
publicationSessionIdByReleaseId: new Map<string, string>(),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function rememberLinkedPublicationSession(
|
|
69
|
+
state: WorkflowClientState,
|
|
70
|
+
releaseId?: string | null,
|
|
71
|
+
publicationSessionId?: string | null
|
|
72
|
+
) {
|
|
73
|
+
if (releaseId && publicationSessionId) {
|
|
74
|
+
state.publicationSessionIdByReleaseId.set(releaseId, publicationSessionId);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function trackBackendIdentifiers(
|
|
79
|
+
state: WorkflowClientState,
|
|
80
|
+
backendResult: PortalBackendResult
|
|
81
|
+
) {
|
|
82
|
+
if (typeof backendResult.releaseId === "string") {
|
|
83
|
+
state.currentReleaseId = backendResult.releaseId;
|
|
84
|
+
}
|
|
85
|
+
if (typeof backendResult.publicationSessionId === "string") {
|
|
86
|
+
state.currentPublicationSessionId = backendResult.publicationSessionId;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
rememberLinkedPublicationSession(
|
|
90
|
+
state,
|
|
91
|
+
state.currentReleaseId,
|
|
92
|
+
state.currentPublicationSessionId
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function trackTranslatedIngestionSession(
|
|
97
|
+
state: WorkflowClientState,
|
|
98
|
+
session: PublicationIngestionSession
|
|
99
|
+
) {
|
|
100
|
+
rememberLinkedPublicationSession(
|
|
101
|
+
state,
|
|
102
|
+
session.releaseId,
|
|
103
|
+
session.publicationSessionId
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
if (session.publicationSessionId) {
|
|
107
|
+
state.currentPublicationSessionId = session.publicationSessionId;
|
|
108
|
+
} else if (session.publicationSession) {
|
|
109
|
+
state.currentPublicationSessionId = session.publicationSession.id;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (session.releaseId) {
|
|
113
|
+
state.currentReleaseId = session.releaseId;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function readLocalSourceFileOrThrow(filePath: string): Buffer {
|
|
118
|
+
try {
|
|
119
|
+
return fs.readFileSync(filePath);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
const code =
|
|
122
|
+
error && typeof error === "object" && "code" in error
|
|
123
|
+
? String((error as { code?: unknown }).code || "")
|
|
124
|
+
: "";
|
|
125
|
+
|
|
126
|
+
if (code === "EPERM" || code === "EACCES") {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`Cannot read local APK at ${filePath}. macOS denied access to this location (${code}). Move the APK out of Downloads into your workspace or another accessible folder, or grant this app Full Disk Access, then retry.`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function createPortalWorkflowClient(
|
|
137
|
+
config: PortalClientConfig
|
|
138
|
+
): PublicationWorkflowClient {
|
|
139
|
+
const state = createWorkflowClientState();
|
|
140
|
+
|
|
141
|
+
const createUploadTarget = async (
|
|
142
|
+
input: PublicationCreateUploadTargetInput
|
|
143
|
+
): Promise<PortalUploadTarget> => {
|
|
144
|
+
return await callPortalProcedure<PortalUploadTarget>(
|
|
145
|
+
config,
|
|
146
|
+
"publication.createUploadTarget",
|
|
147
|
+
input,
|
|
148
|
+
"mutation"
|
|
149
|
+
);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const translateIngestionBackendResult = (
|
|
153
|
+
backendResult: PortalBackendResult
|
|
154
|
+
) => {
|
|
155
|
+
const translated = translateBackendIngestionSession(
|
|
156
|
+
backendResult,
|
|
157
|
+
asRecord(backendResult.bundle),
|
|
158
|
+
asRecord(backendResult.publicationSession)
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
trackTranslatedIngestionSession(state, translated);
|
|
162
|
+
return translated;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const uploadReleaseMetadata = async (bundle: PublicationBundle) => {
|
|
166
|
+
const releaseId = bundle.releaseId;
|
|
167
|
+
const cached = state.metadataUriByReleaseId.get(releaseId);
|
|
168
|
+
if (cached) {
|
|
169
|
+
return cached;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (
|
|
173
|
+
typeof bundle.release.releaseMetadataUri === "string" &&
|
|
174
|
+
bundle.release.releaseMetadataUri.length > 0
|
|
175
|
+
) {
|
|
176
|
+
state.metadataUriByReleaseId.set(
|
|
177
|
+
releaseId,
|
|
178
|
+
bundle.release.releaseMetadataUri
|
|
179
|
+
);
|
|
180
|
+
return bundle.release.releaseMetadataUri;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const releaseMetadataClient: ReleaseMetadataPortalClient = {
|
|
184
|
+
createUploadTarget,
|
|
185
|
+
async fetchRemoteFile(input) {
|
|
186
|
+
return await callPortalProcedure<{
|
|
187
|
+
data: string;
|
|
188
|
+
fileName: string;
|
|
189
|
+
mimeType: string;
|
|
190
|
+
}>(config, "fetchRemoteFile", input, "query");
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const metadataDocument = await buildReleaseMetadataDocument(
|
|
195
|
+
releaseMetadataClient,
|
|
196
|
+
bundle,
|
|
197
|
+
inferPublicationSourceKind(
|
|
198
|
+
bundle.metadata.installFile.origin === "external"
|
|
199
|
+
? "externalUrl"
|
|
200
|
+
: "portalUpload"
|
|
201
|
+
)
|
|
202
|
+
);
|
|
203
|
+
delete (metadataDocument as Record<string, unknown>).__origin;
|
|
204
|
+
|
|
205
|
+
const metadataBytes = Buffer.from(JSON.stringify(metadataDocument), "utf8");
|
|
206
|
+
const fileHash = createHash("sha256").update(metadataBytes).digest("hex");
|
|
207
|
+
const uploadTarget = await createUploadTarget({
|
|
208
|
+
fileHash,
|
|
209
|
+
fileExtension: "json",
|
|
210
|
+
contentType: "application/json",
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
await uploadBytes(
|
|
214
|
+
uploadTarget.uploadUrl,
|
|
215
|
+
metadataBytes,
|
|
216
|
+
"application/json"
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
state.metadataUriByReleaseId.set(releaseId, uploadTarget.publicUrl);
|
|
220
|
+
return uploadTarget.publicUrl;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
async createUploadTarget(
|
|
225
|
+
input: PublicationCreateUploadTargetInput
|
|
226
|
+
): Promise<PublicationCreateUploadTargetResult> {
|
|
227
|
+
return await createUploadTarget(input);
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
async createIngestionSession(
|
|
231
|
+
input: PublicationCreateIngestionSessionInput
|
|
232
|
+
): Promise<PublicationIngestionSession> {
|
|
233
|
+
const dappId = input.dappId || config.dappId;
|
|
234
|
+
const idempotencyKey = input.idempotencyKey || `${Date.now()}`;
|
|
235
|
+
|
|
236
|
+
if (input.source.kind === "apk-file") {
|
|
237
|
+
const source = (() => {
|
|
238
|
+
const filePath = path.resolve(input.source.filePath);
|
|
239
|
+
const fileName = ensureApkFileName(
|
|
240
|
+
input.source.fileName || path.basename(filePath)
|
|
241
|
+
);
|
|
242
|
+
const fileBytes = readLocalSourceFileOrThrow(filePath);
|
|
243
|
+
const fileHash =
|
|
244
|
+
input.source.sha256 ||
|
|
245
|
+
createHash("sha256").update(fileBytes).digest("hex");
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
filePath,
|
|
249
|
+
fileName,
|
|
250
|
+
fileBytes,
|
|
251
|
+
fileHash,
|
|
252
|
+
fileExtension: "apk",
|
|
253
|
+
contentType:
|
|
254
|
+
input.source.mimeType ||
|
|
255
|
+
"application/vnd.android.package-archive",
|
|
256
|
+
releaseFileSize: input.source.size ?? fileBytes.byteLength,
|
|
257
|
+
};
|
|
258
|
+
})();
|
|
259
|
+
|
|
260
|
+
const uploadTarget = await createUploadTarget({
|
|
261
|
+
fileHash: source.fileHash,
|
|
262
|
+
fileExtension: source.fileExtension,
|
|
263
|
+
contentType: source.contentType,
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
await uploadBytes(
|
|
267
|
+
uploadTarget.uploadUrl,
|
|
268
|
+
fromBase64(toBase64(source.fileBytes)),
|
|
269
|
+
source.contentType
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
const backendResult = await callCreateIngestionSessionWithRetry(
|
|
273
|
+
config,
|
|
274
|
+
{
|
|
275
|
+
source: {
|
|
276
|
+
kind: "portalUpload",
|
|
277
|
+
releaseFileUrl: uploadTarget.publicUrl,
|
|
278
|
+
releaseFileName: source.fileName,
|
|
279
|
+
releaseFileSize: source.releaseFileSize,
|
|
280
|
+
},
|
|
281
|
+
whatsNew: input.whatsNew,
|
|
282
|
+
idempotencyKey,
|
|
283
|
+
...(dappId ? { dappId } : {}),
|
|
284
|
+
}
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
trackBackendIdentifiers(state, backendResult);
|
|
288
|
+
return translateIngestionBackendResult(backendResult);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const backendSource =
|
|
292
|
+
input.source.kind === "portalUpload"
|
|
293
|
+
? {
|
|
294
|
+
kind: "portalUpload",
|
|
295
|
+
releaseFileUrl: input.source.releaseFileUrl,
|
|
296
|
+
releaseFileName: input.source.releaseFileName,
|
|
297
|
+
releaseFileSize: input.source.releaseFileSize,
|
|
298
|
+
}
|
|
299
|
+
: input.source.kind === "existingRelease"
|
|
300
|
+
? {
|
|
301
|
+
kind: "existingRelease",
|
|
302
|
+
sourceReleaseId: input.source.sourceReleaseId,
|
|
303
|
+
}
|
|
304
|
+
: {
|
|
305
|
+
kind: "externalUrl",
|
|
306
|
+
apkUrl:
|
|
307
|
+
input.source.kind === "externalUrl"
|
|
308
|
+
? input.source.apkUrl
|
|
309
|
+
: input.source.url,
|
|
310
|
+
releaseFileName:
|
|
311
|
+
input.source.kind === "externalUrl"
|
|
312
|
+
? input.source.releaseFileName ||
|
|
313
|
+
inferFileNameFromUrl(input.source.apkUrl)
|
|
314
|
+
: input.source.fileName ||
|
|
315
|
+
inferFileNameFromUrl(input.source.url),
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
const backendResult = await callCreateIngestionSessionWithRetry(config, {
|
|
319
|
+
source: backendSource,
|
|
320
|
+
whatsNew: input.whatsNew,
|
|
321
|
+
idempotencyKey,
|
|
322
|
+
...(dappId ? { dappId } : {}),
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
trackBackendIdentifiers(state, backendResult);
|
|
326
|
+
return translateIngestionBackendResult(backendResult);
|
|
327
|
+
},
|
|
328
|
+
|
|
329
|
+
async getIngestionSession(
|
|
330
|
+
input: PublicationGetIngestionSessionInput
|
|
331
|
+
): Promise<PublicationIngestionSession> {
|
|
332
|
+
const resolvedSessionId =
|
|
333
|
+
input.sessionId ||
|
|
334
|
+
("ingestionSessionId" in input &&
|
|
335
|
+
typeof input.ingestionSessionId === "string" &&
|
|
336
|
+
input.ingestionSessionId.length > 0
|
|
337
|
+
? input.ingestionSessionId
|
|
338
|
+
: undefined);
|
|
339
|
+
|
|
340
|
+
if (!resolvedSessionId) {
|
|
341
|
+
throw new Error(
|
|
342
|
+
"publication.getIngestionSession requires a session id"
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const backendResult = await callPortalProcedure<PortalBackendResult>(
|
|
347
|
+
config,
|
|
348
|
+
"publication.getIngestionSession",
|
|
349
|
+
{
|
|
350
|
+
sessionId: resolvedSessionId,
|
|
351
|
+
},
|
|
352
|
+
"query"
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
trackBackendIdentifiers(state, backendResult);
|
|
356
|
+
return translateIngestionBackendResult(backendResult);
|
|
357
|
+
},
|
|
358
|
+
|
|
359
|
+
async getPublicationBundle(
|
|
360
|
+
input: PublicationGetBundleInput
|
|
361
|
+
): Promise<PublicationBundle> {
|
|
362
|
+
const backendBundle = await callPortalProcedure<PortalBackendResult>(
|
|
363
|
+
config,
|
|
364
|
+
"publication.getPublicationBundle",
|
|
365
|
+
{ releaseId: input.releaseId },
|
|
366
|
+
"query"
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
const linkedPublicationSessionId =
|
|
370
|
+
state.publicationSessionIdByReleaseId.get(input.releaseId) ||
|
|
371
|
+
state.currentPublicationSessionId;
|
|
372
|
+
const linkedPublicationSession = linkedPublicationSessionId
|
|
373
|
+
? translateBackendPublicationSession(
|
|
374
|
+
await callPortalProcedure<PortalBackendResult>(
|
|
375
|
+
config,
|
|
376
|
+
"publication.getPublicationSession",
|
|
377
|
+
{
|
|
378
|
+
publicationSessionId: linkedPublicationSessionId,
|
|
379
|
+
releaseId: input.releaseId,
|
|
380
|
+
},
|
|
381
|
+
"query"
|
|
382
|
+
)
|
|
383
|
+
)
|
|
384
|
+
: undefined;
|
|
385
|
+
|
|
386
|
+
const releaseMetadataUri =
|
|
387
|
+
state.metadataUriByReleaseId.get(input.releaseId) ||
|
|
388
|
+
(isRecord(backendBundle.release) &&
|
|
389
|
+
typeof backendBundle.release.nftMetadataUri === "string" &&
|
|
390
|
+
backendBundle.release.nftMetadataUri.length > 0
|
|
391
|
+
? backendBundle.release.nftMetadataUri
|
|
392
|
+
: await uploadReleaseMetadata(
|
|
393
|
+
mapBackendBundleToPublicationBundle(backendBundle, "", "portal")
|
|
394
|
+
));
|
|
395
|
+
|
|
396
|
+
state.metadataUriByReleaseId.set(input.releaseId, releaseMetadataUri);
|
|
397
|
+
|
|
398
|
+
const translated = mapBackendBundleToPublicationBundle(
|
|
399
|
+
backendBundle,
|
|
400
|
+
releaseMetadataUri,
|
|
401
|
+
inferPublicationSourceKind(
|
|
402
|
+
state.currentReleaseId &&
|
|
403
|
+
state.publicationSessionIdByReleaseId.has(state.currentReleaseId)
|
|
404
|
+
? "portalUpload"
|
|
405
|
+
: "externalUrl"
|
|
406
|
+
)
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
translated.releaseId = translated.releaseId || input.releaseId;
|
|
410
|
+
translated.publicationSessionId =
|
|
411
|
+
translated.publicationSessionId ||
|
|
412
|
+
linkedPublicationSession?.id ||
|
|
413
|
+
state.publicationSessionIdByReleaseId.get(input.releaseId) ||
|
|
414
|
+
state.currentPublicationSessionId ||
|
|
415
|
+
"";
|
|
416
|
+
translated.ingestionSessionId =
|
|
417
|
+
translated.ingestionSessionId ||
|
|
418
|
+
linkedPublicationSession?.ingestionSessionId ||
|
|
419
|
+
"";
|
|
420
|
+
|
|
421
|
+
state.currentReleaseId = translated.releaseId || state.currentReleaseId;
|
|
422
|
+
state.currentPublicationSessionId =
|
|
423
|
+
translated.publicationSessionId || state.currentPublicationSessionId;
|
|
424
|
+
|
|
425
|
+
rememberLinkedPublicationSession(
|
|
426
|
+
state,
|
|
427
|
+
translated.releaseId,
|
|
428
|
+
translated.publicationSessionId
|
|
429
|
+
);
|
|
430
|
+
|
|
431
|
+
return translated;
|
|
432
|
+
},
|
|
433
|
+
|
|
434
|
+
async getPublicationSession(input: PublicationGetSessionInput) {
|
|
435
|
+
const backendResult = await callPortalProcedure<PortalBackendResult>(
|
|
436
|
+
config,
|
|
437
|
+
"publication.getPublicationSession",
|
|
438
|
+
{
|
|
439
|
+
publicationSessionId:
|
|
440
|
+
input.publicationSessionId ||
|
|
441
|
+
(input.releaseId
|
|
442
|
+
? state.publicationSessionIdByReleaseId.get(input.releaseId)
|
|
443
|
+
: undefined),
|
|
444
|
+
releaseId: input.releaseId,
|
|
445
|
+
},
|
|
446
|
+
"query"
|
|
447
|
+
);
|
|
448
|
+
|
|
449
|
+
const translated = translateBackendPublicationSession(backendResult);
|
|
450
|
+
state.currentPublicationSessionId = translated.id;
|
|
451
|
+
state.currentReleaseId = translated.releaseId || state.currentReleaseId;
|
|
452
|
+
rememberLinkedPublicationSession(
|
|
453
|
+
state,
|
|
454
|
+
translated.releaseId,
|
|
455
|
+
translated.id
|
|
456
|
+
);
|
|
457
|
+
return translated;
|
|
458
|
+
},
|
|
459
|
+
|
|
460
|
+
async cleanupRelease(
|
|
461
|
+
input: PublicationCleanupReleaseInput
|
|
462
|
+
): Promise<PublicationCleanupReleaseResult> {
|
|
463
|
+
return await callPortalProcedure<PublicationCleanupReleaseResult>(
|
|
464
|
+
config,
|
|
465
|
+
"publication.cleanupRelease",
|
|
466
|
+
input,
|
|
467
|
+
"mutation"
|
|
468
|
+
);
|
|
469
|
+
},
|
|
470
|
+
|
|
471
|
+
async prepareReleaseNftTransaction(
|
|
472
|
+
input: PublicationPrepareReleaseNftTransactionInput
|
|
473
|
+
): Promise<PublicationPreparedReleaseTransaction> {
|
|
474
|
+
return await callPortalProcedure<PublicationPreparedReleaseTransaction>(
|
|
475
|
+
config,
|
|
476
|
+
"publication.prepareReleaseNftTransaction",
|
|
477
|
+
input,
|
|
478
|
+
"mutation"
|
|
479
|
+
);
|
|
480
|
+
},
|
|
481
|
+
|
|
482
|
+
async submitSignedTransaction(input: {
|
|
483
|
+
signedTransaction: string;
|
|
484
|
+
publicationSessionId?: string;
|
|
485
|
+
}): Promise<PublicationSubmitSignedTransactionResult> {
|
|
486
|
+
return await callPortalProcedure<PublicationSubmitSignedTransactionResult>(
|
|
487
|
+
config,
|
|
488
|
+
"publication.submitSignedTransaction",
|
|
489
|
+
{
|
|
490
|
+
signedTransaction: input.signedTransaction,
|
|
491
|
+
publicationSessionId:
|
|
492
|
+
input.publicationSessionId || state.currentPublicationSessionId,
|
|
493
|
+
},
|
|
494
|
+
"mutation"
|
|
495
|
+
);
|
|
496
|
+
},
|
|
497
|
+
|
|
498
|
+
async saveReleaseNftData(
|
|
499
|
+
input: PublicationSaveReleaseNftDataInput
|
|
500
|
+
): Promise<PublicationSaveReleaseNftDataResult> {
|
|
501
|
+
return await callPortalProcedure<PublicationSaveReleaseNftDataResult>(
|
|
502
|
+
config,
|
|
503
|
+
"publication.saveReleaseNftData",
|
|
504
|
+
input,
|
|
505
|
+
"mutation"
|
|
506
|
+
);
|
|
507
|
+
},
|
|
508
|
+
|
|
509
|
+
async prepareVerifyCollectionTransaction(
|
|
510
|
+
input: PublicationPrepareVerifyCollectionTransactionInput
|
|
511
|
+
): Promise<PublicationPreparedVerifyCollectionTransaction> {
|
|
512
|
+
return await callPortalProcedure<PublicationPreparedVerifyCollectionTransaction>(
|
|
513
|
+
config,
|
|
514
|
+
"publication.prepareVerifyCollectionTransaction",
|
|
515
|
+
input,
|
|
516
|
+
"mutation"
|
|
517
|
+
);
|
|
518
|
+
},
|
|
519
|
+
|
|
520
|
+
async markReleaseCollectionAsVerified(input: {
|
|
521
|
+
releaseId: string;
|
|
522
|
+
}): Promise<{ success: boolean; releaseId: string }> {
|
|
523
|
+
return await callPortalProcedure<{ success: boolean; releaseId: string }>(
|
|
524
|
+
config,
|
|
525
|
+
"publication.markReleaseCollectionAsVerified",
|
|
526
|
+
input,
|
|
527
|
+
"mutation"
|
|
528
|
+
);
|
|
529
|
+
},
|
|
530
|
+
|
|
531
|
+
async submitToStore(
|
|
532
|
+
input: PublicationSubmitToStoreInput
|
|
533
|
+
): Promise<PublicationSubmitToStoreResult> {
|
|
534
|
+
const attestation = isRecord(input.attestation)
|
|
535
|
+
? input.attestation
|
|
536
|
+
: undefined;
|
|
537
|
+
|
|
538
|
+
const payload =
|
|
539
|
+
typeof attestation?.payload === "string" &&
|
|
540
|
+
attestation.payload.length > 0
|
|
541
|
+
? attestation.payload
|
|
542
|
+
: typeof attestation?.attestationPayload === "string" &&
|
|
543
|
+
attestation.attestationPayload.length > 0
|
|
544
|
+
? attestation.attestationPayload
|
|
545
|
+
: typeof (input as Record<string, unknown>).attestationPayload ===
|
|
546
|
+
"string"
|
|
547
|
+
? String((input as Record<string, unknown>).attestationPayload)
|
|
548
|
+
: "";
|
|
549
|
+
const requestUniqueId =
|
|
550
|
+
typeof attestation?.requestUniqueId === "string"
|
|
551
|
+
? attestation.requestUniqueId
|
|
552
|
+
: typeof (input as Record<string, unknown>).requestUniqueId ===
|
|
553
|
+
"string"
|
|
554
|
+
? String((input as Record<string, unknown>).requestUniqueId)
|
|
555
|
+
: "";
|
|
556
|
+
|
|
557
|
+
return await callPortalProcedure<PublicationSubmitToStoreResult>(
|
|
558
|
+
config,
|
|
559
|
+
"publication.submitToStore",
|
|
560
|
+
{
|
|
561
|
+
releaseId: input.releaseId,
|
|
562
|
+
whatsNew: input.whatsNew,
|
|
563
|
+
criticalUpdate: input.criticalUpdate,
|
|
564
|
+
testingInstructions: input.testingInstructions,
|
|
565
|
+
isResubmission: input.isResubmission,
|
|
566
|
+
attestation: {
|
|
567
|
+
payload,
|
|
568
|
+
requestUniqueId,
|
|
569
|
+
},
|
|
570
|
+
},
|
|
571
|
+
"mutation"
|
|
572
|
+
);
|
|
573
|
+
},
|
|
574
|
+
};
|
|
575
|
+
}
|