@devtion/backend 0.0.0-7e983e3

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.
Files changed (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -0
  3. package/dist/src/functions/index.js +2644 -0
  4. package/dist/src/functions/index.mjs +2596 -0
  5. package/dist/types/functions/ceremony.d.ts +33 -0
  6. package/dist/types/functions/ceremony.d.ts.map +1 -0
  7. package/dist/types/functions/circuit.d.ts +63 -0
  8. package/dist/types/functions/circuit.d.ts.map +1 -0
  9. package/dist/types/functions/index.d.ts +7 -0
  10. package/dist/types/functions/index.d.ts.map +1 -0
  11. package/dist/types/functions/participant.d.ts +58 -0
  12. package/dist/types/functions/participant.d.ts.map +1 -0
  13. package/dist/types/functions/storage.d.ts +37 -0
  14. package/dist/types/functions/storage.d.ts.map +1 -0
  15. package/dist/types/functions/timeout.d.ts +26 -0
  16. package/dist/types/functions/timeout.d.ts.map +1 -0
  17. package/dist/types/functions/user.d.ts +15 -0
  18. package/dist/types/functions/user.d.ts.map +1 -0
  19. package/dist/types/lib/errors.d.ts +75 -0
  20. package/dist/types/lib/errors.d.ts.map +1 -0
  21. package/dist/types/lib/services.d.ts +9 -0
  22. package/dist/types/lib/services.d.ts.map +1 -0
  23. package/dist/types/lib/utils.d.ts +141 -0
  24. package/dist/types/lib/utils.d.ts.map +1 -0
  25. package/dist/types/types/enums.d.ts +13 -0
  26. package/dist/types/types/enums.d.ts.map +1 -0
  27. package/dist/types/types/index.d.ts +130 -0
  28. package/dist/types/types/index.d.ts.map +1 -0
  29. package/package.json +89 -0
  30. package/src/functions/ceremony.ts +333 -0
  31. package/src/functions/circuit.ts +1092 -0
  32. package/src/functions/index.ts +36 -0
  33. package/src/functions/participant.ts +526 -0
  34. package/src/functions/storage.ts +548 -0
  35. package/src/functions/timeout.ts +294 -0
  36. package/src/functions/user.ts +142 -0
  37. package/src/lib/errors.ts +237 -0
  38. package/src/lib/services.ts +28 -0
  39. package/src/lib/utils.ts +472 -0
  40. package/src/types/enums.ts +12 -0
  41. package/src/types/index.ts +140 -0
  42. package/test/index.test.ts +62 -0
@@ -0,0 +1,28 @@
1
+ import { S3Client } from "@aws-sdk/client-s3"
2
+ import { COMMON_ERRORS, logAndThrowError } from "./errors"
3
+
4
+ /**
5
+ * Return a configured and connected instance of the AWS S3 client.
6
+ * @dev this method check and utilize the environment variables to configure the connection
7
+ * w/ the S3 client.
8
+ * @returns <Promise<S3Client>> - the instance of the connected S3 Client instance.
9
+ */
10
+ export const getS3Client = async (): Promise<S3Client> => {
11
+ if (
12
+ !process.env.AWS_ACCESS_KEY_ID ||
13
+ !process.env.AWS_SECRET_ACCESS_KEY ||
14
+ !process.env.AWS_REGION ||
15
+ !process.env.AWS_PRESIGNED_URL_EXPIRATION ||
16
+ !process.env.AWS_CEREMONY_BUCKET_POSTFIX
17
+ )
18
+ logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION)
19
+
20
+ // Return the connected S3 Client instance.
21
+ return new S3Client({
22
+ credentials: {
23
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
24
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!
25
+ },
26
+ region: process.env.AWS_REGION!
27
+ })
28
+ }
@@ -0,0 +1,472 @@
1
+ import {
2
+ DocumentData,
3
+ QuerySnapshot,
4
+ DocumentSnapshot,
5
+ QueryDocumentSnapshot,
6
+ Timestamp,
7
+ WhereFilterOp
8
+ } from "firebase-admin/firestore"
9
+ import admin from "firebase-admin"
10
+ import dotenv from "dotenv"
11
+ import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3"
12
+ import { getSignedUrl } from "@aws-sdk/s3-request-presigner"
13
+ import { createWriteStream, fstat } from "node:fs"
14
+ import { pipeline } from "node:stream"
15
+ import { promisify } from "node:util"
16
+ import { readFileSync } from "fs"
17
+ import mime from "mime-types"
18
+ import { encode } from "html-entities"
19
+ import { setTimeout } from "timers/promises"
20
+ import {
21
+ commonTerms,
22
+ getCircuitsCollectionPath,
23
+ getContributionsCollectionPath,
24
+ getTimeoutsCollectionPath,
25
+ CeremonyState,
26
+ finalContributionIndex,
27
+ CircuitDocument
28
+ } from "@p0tion/actions"
29
+ import fetch from "@adobe/node-fetch-retry"
30
+ import path from "path"
31
+ import os from "os"
32
+ import { SSMClient } from "@aws-sdk/client-ssm"
33
+ import { EC2Client } from "@aws-sdk/client-ec2"
34
+ import { COMMON_ERRORS, logAndThrowError, SPECIFIC_ERRORS } from "./errors"
35
+ import { getS3Client } from "./services"
36
+
37
+ dotenv.config()
38
+
39
+ /**
40
+ * Get a specific document from database.
41
+ * @dev this method differs from the one in the `actions` package because we need to use
42
+ * the admin SDK here; therefore the Firestore instances are not interchangeable between admin
43
+ * and user instance.
44
+ * @param collection <string> - the name of the collection.
45
+ * @param documentId <string> - the unique identifier of the document in the collection.
46
+ * @returns <Promise<DocumentSnapshot<DocumentData>>> - the requested document w/ relative data.
47
+ */
48
+ export const getDocumentById = async (
49
+ collection: string,
50
+ documentId: string
51
+ ): Promise<DocumentSnapshot<DocumentData>> => {
52
+ // Prepare Firestore db instance.
53
+ const firestore = admin.firestore()
54
+
55
+ // Get document.
56
+ const doc = await firestore.collection(collection).doc(documentId).get()
57
+
58
+ // Return only if doc exists; otherwise throw error.
59
+ return doc.exists ? doc : logAndThrowError(COMMON_ERRORS.CM_INEXISTENT_DOCUMENT)
60
+ }
61
+
62
+ /**
63
+ * Get the current server timestamp.
64
+ * @dev the value is in milliseconds.
65
+ * @returns <number> - the timestamp of the server (ms).
66
+ */
67
+ export const getCurrentServerTimestampInMillis = (): number => Timestamp.now().toMillis()
68
+
69
+ /**
70
+ * Interrupt the current execution for a specified amount of time.
71
+ * @param ms <number> - the amount of time expressed in milliseconds.
72
+ */
73
+ export const sleep = async (ms: number): Promise<void> => setTimeout(ms)
74
+
75
+ /**
76
+ * Query for ceremony circuits.
77
+ * @notice the order by sequence position is fundamental to maintain parallelism among contributions for different circuits.
78
+ * @param ceremonyId <string> - the unique identifier of the ceremony.
79
+ * @returns Promise<Array<FirebaseDocumentInfo>> - the ceremony' circuits documents ordered by sequence position.
80
+ */
81
+ export const getCeremonyCircuits = async (ceremonyId: string): Promise<Array<QueryDocumentSnapshot<DocumentData>>> => {
82
+ // Prepare Firestore db instance.
83
+ const firestore = admin.firestore()
84
+
85
+ // Execute query.
86
+ const querySnap = await firestore.collection(getCircuitsCollectionPath(ceremonyId)).get()
87
+
88
+ if (!querySnap.docs) logAndThrowError(SPECIFIC_ERRORS.SE_CONTRIBUTE_NO_CEREMONY_CIRCUITS)
89
+
90
+ return querySnap.docs.sort(
91
+ (a: DocumentData, b: DocumentData) => a.data().sequencePosition - b.data().sequencePosition
92
+ )
93
+ }
94
+
95
+ /**
96
+ * Query for ceremony circuit contributions.
97
+ * @param ceremonyId <string> - the unique identifier of the ceremony.
98
+ * @param circuitId <string> - the unique identifier of the circuitId.
99
+ * @returns Promise<Array<FirebaseDocumentInfo>> - the contributions of the ceremony circuit.
100
+ */
101
+ export const getCeremonyCircuitContributions = async (
102
+ ceremonyId: string,
103
+ circuitId: string
104
+ ): Promise<Array<QueryDocumentSnapshot<DocumentData>>> => {
105
+ // Prepare Firestore db instance.
106
+ const firestore = admin.firestore()
107
+
108
+ // Execute query.
109
+ const querySnap = await firestore.collection(getContributionsCollectionPath(ceremonyId, circuitId)).get()
110
+
111
+ if (!querySnap.docs) logAndThrowError(SPECIFIC_ERRORS.SE_FINALIZE_NO_CEREMONY_CONTRIBUTIONS)
112
+
113
+ return querySnap.docs
114
+ }
115
+
116
+ /**
117
+ * Query not expired timeouts.
118
+ * @notice a timeout is considered valid (aka not expired) if and only if the timeout end date
119
+ * value is less than current timestamp.
120
+ * @param ceremonyId <string> - the unique identifier of the ceremony.
121
+ * @param participantId <string> - the unique identifier of the participant.
122
+ * @returns <Promise<QuerySnapshot<DocumentData>>>
123
+ */
124
+ export const queryNotExpiredTimeouts = async (
125
+ ceremonyId: string,
126
+ participantId: string
127
+ ): Promise<QuerySnapshot<DocumentData>> => {
128
+ // Prepare Firestore db.
129
+ const firestoreDb = admin.firestore()
130
+
131
+ // Execute and return query result.
132
+ return firestoreDb
133
+ .collection(getTimeoutsCollectionPath(ceremonyId, participantId))
134
+ .where(commonTerms.collections.timeouts.fields.endDate, ">=", getCurrentServerTimestampInMillis())
135
+ .get()
136
+ }
137
+
138
+ /**
139
+ * Query for opened ceremonies.
140
+ * @param firestoreDatabase <Firestore> - the Firestore service instance associated to the current Firebase application.
141
+ * @returns <Promise<Array<FirebaseDocumentInfo>>>
142
+ */
143
+ export const queryOpenedCeremonies = async (): Promise<Array<QueryDocumentSnapshot<DocumentData>>> => {
144
+ const querySnap = await admin
145
+ .firestore()
146
+ .collection(commonTerms.collections.ceremonies.name)
147
+ .where(commonTerms.collections.ceremonies.fields.state, "==", CeremonyState.OPENED)
148
+ .where(commonTerms.collections.ceremonies.fields.endDate, ">=", getCurrentServerTimestampInMillis())
149
+ .get()
150
+
151
+ if (!querySnap.docs) logAndThrowError(SPECIFIC_ERRORS.SE_CONTRIBUTE_NO_OPENED_CEREMONIES)
152
+
153
+ return querySnap.docs
154
+ }
155
+
156
+ /**
157
+ * Get ceremony circuit document by sequence position.
158
+ * @param ceremonyId <string> - the unique identifier of the ceremony.
159
+ * @param sequencePosition <number> - the sequence position of the circuit.
160
+ * @returns Promise<QueryDocumentSnapshot<DocumentData>>
161
+ */
162
+ export const getCircuitDocumentByPosition = async (
163
+ ceremonyId: string,
164
+ sequencePosition: number
165
+ ): Promise<QueryDocumentSnapshot<DocumentData>> => {
166
+ // Query for all ceremony circuits.
167
+ const circuits = await getCeremonyCircuits(ceremonyId)
168
+
169
+ // Apply a filter using the sequence postion.
170
+ const matchedCircuits = circuits.filter(
171
+ (circuit: DocumentData) => circuit.data().sequencePosition === sequencePosition
172
+ )
173
+
174
+ if (matchedCircuits.length !== 1) logAndThrowError(COMMON_ERRORS.CM_NO_CIRCUIT_FOR_GIVEN_SEQUENCE_POSITION)
175
+
176
+ return matchedCircuits.at(0)!
177
+ }
178
+
179
+ /**
180
+ * Create a temporary file path in the virtual memory of the cloud function.
181
+ * @dev useful when downloading files from AWS S3 buckets for processing within cloud functions.
182
+ * @param completeFilename <string> - the complete file name (name + ext).
183
+ * @returns <string> - the path to the local temporary location.
184
+ */
185
+ export const createTemporaryLocalPath = (completeFilename: string): string => path.join(os.tmpdir(), completeFilename)
186
+
187
+ /**
188
+ * Download an artifact from the AWS S3 bucket.
189
+ * @dev this method uses streams.
190
+ * @param bucketName <string> - the name of the bucket.
191
+ * @param objectKey <string> - the unique key to identify the object inside the given AWS S3 bucket.
192
+ * @param localFilePath <string> - the local path where the file will be stored.
193
+ */
194
+ export const downloadArtifactFromS3Bucket = async (bucketName: string, objectKey: string, localFilePath: string) => {
195
+ // Prepare AWS S3 client instance.
196
+ const client = await getS3Client()
197
+
198
+ // Prepare command.
199
+ const command = new GetObjectCommand({ Bucket: bucketName, Key: objectKey })
200
+
201
+ // Generate a pre-signed url for downloading the file.
202
+ const url = await getSignedUrl(client, command, { expiresIn: Number(process.env.AWS_PRESIGNED_URL_EXPIRATION) })
203
+
204
+ // Execute download request.
205
+ // @ts-ignore
206
+ const response: any = await fetch(url, {
207
+ method: "GET",
208
+ headers: {
209
+ "Access-Control-Allow-Origin": "*"
210
+ }
211
+ })
212
+
213
+ if (response.status !== 200 || !response.ok) logAndThrowError(SPECIFIC_ERRORS.SE_STORAGE_DOWNLOAD_FAILED)
214
+
215
+ // Write the file locally using streams.
216
+ const writeStream = createWriteStream(localFilePath)
217
+ const streamPipeline = promisify(pipeline)
218
+ await streamPipeline(response.body, writeStream)
219
+
220
+ writeStream.on('finish', () => {
221
+ writeStream.end()
222
+ })
223
+ }
224
+
225
+ /**
226
+ * Upload a new artifact to the AWS S3 bucket.
227
+ * @dev this method uses streams.
228
+ * @param bucketName <string> - the name of the bucket.
229
+ * @param objectKey <string> - the unique key to identify the object inside the given AWS S3 bucket.
230
+ * @param localFilePath <string> - the local path where the file to be uploaded is stored.
231
+ */
232
+ export const uploadFileToBucket = async (
233
+ bucketName: string,
234
+ objectKey: string,
235
+ localFilePath: string,
236
+ isPublic: boolean = false
237
+ ) => {
238
+ // Prepare AWS S3 client instance.
239
+ const client = await getS3Client()
240
+
241
+ // Extract content type.
242
+ const contentType = mime.lookup(localFilePath) || ""
243
+
244
+ // Prepare command.
245
+ const command = new PutObjectCommand({
246
+ Bucket: bucketName,
247
+ Key: objectKey,
248
+ ContentType: contentType,
249
+ ACL: isPublic ? "public-read" : "private"
250
+ })
251
+
252
+ // Generate a pre-signed url for uploading the file.
253
+ const url = await getSignedUrl(client, command, { expiresIn: Number(process.env.AWS_PRESIGNED_URL_EXPIRATION) })
254
+
255
+ // Execute upload request.
256
+ // @ts-ignore
257
+ const response = await fetch(url, {
258
+ method: "PUT",
259
+ body: readFileSync(localFilePath),
260
+ headers: { "Content-Type": contentType }
261
+ })
262
+
263
+ if (response.status !== 200 || !response.ok) logAndThrowError(SPECIFIC_ERRORS.SE_STORAGE_UPLOAD_FAILED)
264
+ }
265
+
266
+ export const uploadFileToBucketNoFile = async (
267
+ bucketName: string,
268
+ objectKey: string,
269
+ data: string,
270
+ isPublic: boolean = false
271
+ ) => {
272
+ // Prepare AWS S3 client instance.
273
+ const client = await getS3Client()
274
+
275
+ // Prepare command.
276
+ const command = new PutObjectCommand({
277
+ Bucket: bucketName,
278
+ Key: objectKey,
279
+ ContentType: "text/plain",
280
+ ACL: isPublic ? "public-read" : "private"
281
+ })
282
+
283
+ // Generate a pre-signed url for uploading the file.
284
+ const url = await getSignedUrl(client, command, { expiresIn: Number(process.env.AWS_PRESIGNED_URL_EXPIRATION) })
285
+
286
+ // Execute upload request.
287
+ // @ts-ignore
288
+ const response = await fetch(url, {
289
+ method: "PUT",
290
+ body: data,
291
+ headers: { "Content-Type": "text/plain" }
292
+ })
293
+
294
+ if (response.status !== 200 || !response.ok) logAndThrowError(SPECIFIC_ERRORS.SE_STORAGE_UPLOAD_FAILED)
295
+ }
296
+
297
+ /**
298
+ * Upload an artifact from the AWS S3 bucket.
299
+ * @param bucketName <string> - the name of the bucket.
300
+ * @param objectKey <string> - the unique key to identify the object inside the given AWS S3 bucket.
301
+ */
302
+ export const deleteObject = async (bucketName: string, objectKey: string) => {
303
+ // Prepare AWS S3 client instance.
304
+ const client = await getS3Client()
305
+
306
+ // Prepare command.
307
+ const command = new DeleteObjectCommand({ Bucket: bucketName, Key: objectKey })
308
+
309
+ // Execute command.
310
+ const data = await client.send(command)
311
+
312
+ if (data.$metadata.httpStatusCode !== 204) logAndThrowError(SPECIFIC_ERRORS.SE_STORAGE_DELETE_FAILED)
313
+ }
314
+
315
+ /**
316
+ * Query ceremonies by state and (start/end) date value.
317
+ * @param state <string> - the state of the ceremony.
318
+ * @param needToCheckStartDate <boolean> - flag to discriminate when to check startDate (true) or endDate (false).
319
+ * @param check <WhereFilerOp> - the type of filter (query check - e.g., '<' or '>').
320
+ * @returns <Promise<admin.firestore.QuerySnapshot<admin.firestore.DocumentData>>> - the queried ceremonies after filtering operation.
321
+ */
322
+ export const queryCeremoniesByStateAndDate = async (
323
+ state: string,
324
+ needToCheckStartDate: boolean,
325
+ check: WhereFilterOp
326
+ ): Promise<admin.firestore.QuerySnapshot<admin.firestore.DocumentData>> =>
327
+ admin
328
+ .firestore()
329
+ .collection(commonTerms.collections.ceremonies.name)
330
+ .where(commonTerms.collections.ceremonies.fields.state, "==", state)
331
+ .where(
332
+ needToCheckStartDate
333
+ ? commonTerms.collections.ceremonies.fields.startDate
334
+ : commonTerms.collections.ceremonies.fields.endDate,
335
+ check,
336
+ getCurrentServerTimestampInMillis()
337
+ )
338
+ .get()
339
+
340
+ /**
341
+ * Return the document associated with the final contribution for a ceremony circuit.
342
+ * @dev this method is useful during ceremony finalization.
343
+ * @param ceremonyId <string> -
344
+ * @param circuitId <string> -
345
+ * @returns Promise<QueryDocumentSnapshot<DocumentData>> - the final contribution for the ceremony circuit.
346
+ */
347
+ export const getFinalContribution = async (
348
+ ceremonyId: string,
349
+ circuitId: string
350
+ ): Promise<QueryDocumentSnapshot<DocumentData>> => {
351
+ // Get contributions for the circuit.
352
+ const contributions = await getCeremonyCircuitContributions(ceremonyId, circuitId)
353
+
354
+ // Match the final one.
355
+ const matchContribution = contributions.filter(
356
+ (contribution: DocumentData) => contribution.data().zkeyIndex === finalContributionIndex
357
+ )
358
+
359
+ if (!matchContribution) logAndThrowError(SPECIFIC_ERRORS.SE_FINALIZE_NO_FINAL_CONTRIBUTION)
360
+
361
+ // Get the final contribution.
362
+ // nb. there must be only one final contributions x circuit.
363
+ const finalContribution = matchContribution.at(0)!
364
+
365
+ return finalContribution
366
+ }
367
+
368
+ /**
369
+ * Helper function to HTML encode circuit data.
370
+ * @param circuitDocument <CircuitDocument> - the circuit document to be encoded.
371
+ * @returns <CircuitDocument> - the circuit document encoded.
372
+ */
373
+ export const htmlEncodeCircuitData = (circuitDocument: CircuitDocument): CircuitDocument => ({
374
+ ...circuitDocument,
375
+ description: encode(circuitDocument.description),
376
+ name: encode(circuitDocument.name),
377
+ prefix: encode(circuitDocument.prefix)
378
+ })
379
+
380
+ /**
381
+ * Fetch the variables related to GitHub anti-sybil checks
382
+ * @returns <any> - the GitHub variables.
383
+ */
384
+ export const getGitHubVariables = (): any => {
385
+ if (
386
+ !process.env.GITHUB_MINIMUM_FOLLOWERS ||
387
+ !process.env.GITHUB_MINIMUM_FOLLOWING ||
388
+ !process.env.GITHUB_MINIMUM_PUBLIC_REPOS
389
+ )
390
+ logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION)
391
+
392
+ return {
393
+ minimumFollowers: Number(process.env.GITHUB_MINIMUM_FOLLOWERS),
394
+ minimumFollowing: Number(process.env.GITHUB_MINIMUM_FOLLOWING),
395
+ minimumPublicRepos: Number(process.env.GITHUB_MINIMUM_PUBLIC_REPOS)
396
+ }
397
+ }
398
+
399
+ /**
400
+ * Fetch the variables related to EC2 verification
401
+ * @returns <any> - the AWS EC2 variables.
402
+ */
403
+ export const getAWSVariables = (): any => {
404
+ if (
405
+ !process.env.AWS_ACCESS_KEY_ID ||
406
+ !process.env.AWS_SECRET_ACCESS_KEY ||
407
+ !process.env.AWS_ROLE_ARN ||
408
+ !process.env.AWS_AMI_ID ||
409
+ !process.env.AWS_SNS_TOPIC_ARN
410
+ )
411
+ logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION)
412
+
413
+ return {
414
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
415
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
416
+ region: process.env.AWS_REGION || "eu-central-1",
417
+ roleArn: process.env.AWS_ROLE_ARN!,
418
+ amiId: process.env.AWS_AMI_ID!,
419
+ snsTopic: process.env.AWS_SNS_TOPIC_ARN!
420
+ }
421
+ }
422
+
423
+ /**
424
+ * Create an EC2 client object
425
+ * @returns <Promise<EC2Client>> an EC2 client
426
+ */
427
+ export const createEC2Client = async (): Promise<EC2Client> => {
428
+ const { accessKeyId, secretAccessKey, region } = getAWSVariables()
429
+
430
+ const ec2: EC2Client = new EC2Client({
431
+ credentials: {
432
+ accessKeyId,
433
+ secretAccessKey
434
+ },
435
+ region
436
+ })
437
+
438
+ return ec2
439
+ }
440
+
441
+ /**
442
+ * Create an SSM client object
443
+ * @returns <Promise<SSMClient>> an SSM client
444
+ */
445
+ export const createSSMClient = async (): Promise<SSMClient> => {
446
+ const { accessKeyId, secretAccessKey, region } = getAWSVariables()
447
+
448
+ const ssm: SSMClient = new SSMClient({
449
+ credentials: {
450
+ accessKeyId,
451
+ secretAccessKey
452
+ },
453
+ region
454
+ })
455
+
456
+ return ssm
457
+ }
458
+
459
+ /**
460
+ * Get the instance id of the EC2 instance associated with the circuit
461
+ * @param circuitId <string> - the circuit id
462
+ * @returns <Promise<string>> - the EC2 instance id
463
+ */
464
+ export const getEC2InstanceId = async (circuitId: string): Promise<string> => {
465
+ const circuitDoc = await getDocumentById(commonTerms.collections.circuits.name, circuitId)
466
+
467
+ const circuitData = circuitDoc.data()
468
+
469
+ const { vmInstanceId } = circuitData!
470
+
471
+ return vmInstanceId
472
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Log levels.
3
+ * @notice useful to discriminate the log level for message printing.
4
+ * @enum {string}
5
+ */
6
+ export enum LogLevel {
7
+ INFO = "INFO",
8
+ DEBUG = "DEBUG",
9
+ WARN = "WARN",
10
+ ERROR = "ERROR",
11
+ LOG = "LOG"
12
+ }
@@ -0,0 +1,140 @@
1
+ import { CeremonyInputData, CircuitDocument, ETagWithPartNumber } from "@p0tion/actions"
2
+
3
+ /**
4
+ * Group all the necessary data needed for running the `setupCeremony` cloud function.
5
+ * @typedef {Object} SetupCeremonyData
6
+ * @property {CeremonyInputData} ceremonyInputData - the necessary input data for setup a new ceremony.
7
+ * @property {string} ceremonyPrefix - the ceremony prefix.
8
+ * @property {Array<CircuitDocument>} circuits - the necessary input data for setup the related ceremony circuits.
9
+ */
10
+ export type SetupCeremonyData = {
11
+ ceremonyInputData: CeremonyInputData
12
+ ceremonyPrefix: string
13
+ circuits: Array<CircuitDocument>
14
+ }
15
+
16
+ /**
17
+ * Group all the necessary data needed for running the `createBucket` cloud function.
18
+ * @typedef {Object} CreateBucketData
19
+ * @property {string} bucketName - the name of the bucket.
20
+ */
21
+ export type CreateBucketData = {
22
+ bucketName: string
23
+ }
24
+
25
+ /**
26
+ * Group all the necessary data needed for running the `checkIfObjectExist` or `generateGetObjectPreSignedUrl` cloud functions.
27
+ * @typedef {Object} BucketAndObjectKeyData
28
+ * @property {string} bucketName - the name of the bucket.
29
+ * @property {string} objectKey - the unique key to identify the object inside the given AWS S3 bucket.
30
+ */
31
+ export type BucketAndObjectKeyData = {
32
+ bucketName: string
33
+ objectKey: string
34
+ }
35
+
36
+ /**
37
+ * Group all the necessary data needed for running the `startMultiPartUpload` cloud function.
38
+ * @typedef {Object} StartMultiPartUploadData
39
+ * @property {string} bucketName - the name of the bucket.
40
+ * @property {string} objectKey - the unique key to identify the object inside the given AWS S3 bucket.
41
+ * @property {string} ceremonyId - the prefix of the ceremony.
42
+ */
43
+ export type StartMultiPartUploadData = BucketAndObjectKeyData & {
44
+ ceremonyId?: string
45
+ }
46
+
47
+ /**
48
+ * Group all the necessary data needed for running the `generatePreSignedUrlsParts` cloud function.
49
+ * @typedef {Object} GeneratePreSignedUrlsPartsData
50
+ * @property {string} bucketName - the name of the bucket.
51
+ * @property {string} objectKey - the unique key to identify the object inside the given AWS S3 bucket.
52
+ * @property {string} uploadId - the identifier of the initiated multi-part upload.
53
+ * @property {number} numberOfParts - the amount of chunks for which pre-signed urls are to be generated.
54
+ * @property {string} ceremonyId - the prefix of the ceremony.
55
+ */
56
+ export type GeneratePreSignedUrlsPartsData = BucketAndObjectKeyData & {
57
+ uploadId: string
58
+ numberOfParts: number
59
+ ceremonyId?: string
60
+ }
61
+
62
+ /**
63
+ * Group all the necessary data needed for running the `completeMultiPartUpload` cloud function.
64
+ * @typedef {Object} GeneratePreSignedUrlsPartsData
65
+ * @property {string} bucketName - the name of the bucket.
66
+ * @property {string} objectKey - the unique key to identify the object inside the given AWS S3 bucket.
67
+ * @property {string} uploadId - the identifier of the initiated multi-part upload.
68
+ * @property {Array<ETagWithPartNumber>} parts - the chunks of the file related to the multi-part upload.
69
+ * @property {string} [ceremonyId] - the unique identifier of the ceremony.
70
+ */
71
+ export type CompleteMultiPartUploadData = BucketAndObjectKeyData & {
72
+ uploadId: string
73
+ parts: Array<ETagWithPartNumber>
74
+ ceremonyId?: string
75
+ }
76
+
77
+ /**
78
+ * Group all the necessary data needed for running the `permanentlyStoreCurrentContributionTimeAndHash` cloud function.
79
+ * @typedef {Object} PermanentlyStoreCurrentContributionTimeAndHash
80
+ * @property {string} ceremonyId - the unique identifier of the ceremony.
81
+ * @property {number} contributionComputationTime - the time spent by the contributor to compute the contribution.
82
+ * @property {string} contributionHash - the hash of the contribution.
83
+ */
84
+ export type PermanentlyStoreCurrentContributionTimeAndHash = {
85
+ ceremonyId: string
86
+ contributionComputationTime: number
87
+ contributionHash: string
88
+ }
89
+
90
+ /**
91
+ * Group all the necessary data needed for running the `temporaryStoreCurrentContributionMultiPartUploadId` cloud function.
92
+ * @typedef {Object} TemporaryStoreCurrentContributionMultiPartUploadId
93
+ * @property {string} ceremonyId - the unique identifier of the ceremony.
94
+ * @property {number} uploadId - the unique identifier of the already started multi-part upload.
95
+ */
96
+ export type TemporaryStoreCurrentContributionMultiPartUploadId = {
97
+ ceremonyId: string
98
+ uploadId: string
99
+ }
100
+
101
+ /**
102
+ * Group all the necessary data needed for running the `temporaryStoreCurrentContributionUploadedChunkData` cloud function.
103
+ * @typedef {Object} TemporaryStoreCurrentContributionUploadedChunkData
104
+ * @property {string} ceremonyId - the unique identifier of the ceremony.
105
+ * @property {number} uploadId - the unique identifier of the already started multi-part upload.
106
+ */
107
+ export type TemporaryStoreCurrentContributionUploadedChunkData = {
108
+ ceremonyId: string
109
+ chunk: ETagWithPartNumber
110
+ }
111
+
112
+ /**
113
+ * Group all the necessary data needed for running the `verifycontribution` cloud function.
114
+ * @typedef {Object} VerifyContributionData
115
+ * @property {string} ceremonyId - the unique identifier of the ceremony.
116
+ * @property {string} circuitId - the unique identifier of the circuit.
117
+ * @property {string} bucketName - the name of the bucket.
118
+ * @property {string} contributorOrCoordinatorIdentifier - the identifier of the contributor or coordinator (only when finalizing).
119
+ */
120
+ export type VerifyContributionData = {
121
+ ceremonyId: string
122
+ circuitId: string
123
+ bucketName: string
124
+ contributorOrCoordinatorIdentifier: string
125
+ }
126
+
127
+ /**
128
+ * Group all the necessary data needed for running the `finalizeCircuit` cloud function.
129
+ * @typedef {Object} FinalizeCircuitData
130
+ * @property {string} ceremonyId - the unique identifier of the ceremony.
131
+ * @property {string} circuitId - the unique identifier of the circuit.
132
+ * @property {string} bucketName - the name of the bucket.
133
+ * @property {string} beacon - the value used to compute the final contribution while finalizing the ceremony.
134
+ */
135
+ export type FinalizeCircuitData = {
136
+ ceremonyId: string
137
+ circuitId: string
138
+ bucketName: string
139
+ beacon: string
140
+ }