@@ -252,7 +252,7 @@ export class HypercertOperationsImpl extends EventEmitter<HypercertEvents> imple
252252 * @param rightsUri - URI of the associated rights record
253253 * @param rightsCid - CID of the associated rights record
254254 * @param imageBlobRef - Optional image blob reference
255- * @param locationRef - Optional strong reference to the associated location record
255+ * @param locationRefs - Optional array of strong references to the associated location records
256256 * @param contributorsData - Optional array of contributor data (inline or StrongRef) to embed in the claim
257257 * @param createdAt - ISO timestamp for creation
258258 * @param onProgress - Optional progress callback
@@ -266,7 +266,7 @@ export class HypercertOperationsImpl extends EventEmitter<HypercertEvents> imple
266266 rightsUri : string ,
267267 rightsCid : string ,
268268 imageBlobRef : JsonBlobRef | undefined ,
269- locationRef : { uri : string ; cid : string } | undefined ,
269+ locationRefs : Array < { uri : string ; cid : string } > | undefined ,
270270 contributorsData :
271271 | Array < { contributorIdentity : string ; contributionDetails ?: string | { uri : string ; cid : string } } >
272272 | undefined ,
@@ -290,9 +290,9 @@ export class HypercertOperationsImpl extends EventEmitter<HypercertEvents> imple
290290 hypercertRecord . image = imageBlobRef ;
291291 }
292292
293- // Add location as embedded StrongRef if provided
294- if ( locationRef ) {
295- hypercertRecord . locations = [ { uri : locationRef . uri , cid : locationRef . cid } ] ;
293+ // Add locations as embedded StrongRefs if provided
294+ if ( locationRefs && locationRefs . length > 0 ) {
295+ hypercertRecord . locations = locationRefs . map ( ( ref ) => ( { uri : ref . uri , cid : ref . cid } ) ) ;
296296 }
297297
298298 if ( params . shortDescriptionFacets ) {
@@ -349,8 +349,8 @@ export class HypercertOperationsImpl extends EventEmitter<HypercertEvents> imple
349349 type : params . rights . type ,
350350 description : params . rights . description ,
351351 } ,
352- // Location : use resolved StrongRef (uri+cid), not raw params which may be Blob
353- locationRef : locationRef ? { uri : locationRef . uri , cid : locationRef . cid } : undefined ,
352+ // Locations : use resolved StrongRefs (uri+cid), not raw params which may be Blob
353+ locationRefs : locationRefs ?. map ( ( ref ) => ( { uri : ref . uri , cid : ref . cid } ) ) ,
354354 // Contributors: use already-processed canonical format from processContributors()
355355 contributors : contributorsData ,
356356 } ;
@@ -522,9 +522,10 @@ export class HypercertOperationsImpl extends EventEmitter<HypercertEvents> imple
522522 * const result = await repo.hypercerts.create({
523523 * title: "My Impact",
524524 * description: "Description of impact work",
525+ * shortDescription: "Impact work",
525526 * workScope: "Education",
526- * workTimeframeFrom : "2024-01-01",
527- * workTimeframeTo : "2024-06-30",
527+ * startDate : "2024-01-01",
528+ * endDate : "2024-06-30",
528529 * rights: {
529530 * name: "Attribution",
530531 * type: "license",
@@ -540,11 +541,11 @@ export class HypercertOperationsImpl extends EventEmitter<HypercertEvents> imple
540541 * description: "Planted 10,000 trees...",
541542 * shortDescription: "10K trees planted",
542543 * workScope: "Environment",
543- * workTimeframeFrom : "2024-01-01",
544- * workTimeframeTo : "2024-12-31",
544+ * startDate : "2024-01-01",
545+ * endDate : "2024-12-31",
545546 * rights: { name: "Open", type: "impact", description: "..." },
546547 * image: coverImageBlob,
547- * location: { value: "Amazon, Brazil", name: "Amazon Basin" },
548+ * locations: [ { value: "Amazon, Brazil", name: "Amazon Basin" }] ,
548549 * contributions: [
549550 * { contributors: ["did:plc:org1"], role: "coordinator" },
550551 * { contributors: ["did:plc:org2"], role: "implementer" },
@@ -567,12 +568,12 @@ export class HypercertOperationsImpl extends EventEmitter<HypercertEvents> imple
567568 // Step 1: Upload image if provided
568569 const imageBlobRef = params . image ? await this . uploadImageBlob ( params . image , params . onProgress ) : undefined ;
569570
570- // Step 2: Create location record if provided (must be before hypercert)
571- // If location is provided, it must succeed - failing silently would change the rKey on retries
572- const locationRef = await this . processLocation ( params . location , params . onProgress ) ;
573- if ( locationRef ) {
574- result . locationUri = locationRef . uri ;
575- result . locationCid = locationRef . cid ;
571+ // Step 2: Create location records if provided (must be before hypercert)
572+ // If locations are provided, they must succeed - failing silently would change the rKey on retries
573+ const locationRefs = await this . processLocations ( params . locations , params . onProgress ) ;
574+ if ( locationRefs && locationRefs . length > 0 ) {
575+ result . locationUris = locationRefs . map ( ( ref ) => ref . uri ) ;
576+ result . locationCids = locationRefs . map ( ( ref ) => ref . cid ) ;
576577 }
577578
578579 // Step 3: Create rights record
@@ -587,13 +588,13 @@ export class HypercertOperationsImpl extends EventEmitter<HypercertEvents> imple
587588 // Step 4: Build contributors data for embedding (if provided)
588589 const contributorsData = await this . processContributors ( params . contributions , params . onProgress ) ;
589590
590- // Step 5: Create hypercert record (with embedded location , rights, and contributors)
591+ // Step 5: Create hypercert record (with embedded locations , rights, and contributors)
591592 const { uri : hypercertUri , cid : hypercertCid } = await this . createHypercertRecord (
592593 params ,
593594 rightsUri ,
594595 rightsCid ,
595596 imageBlobRef ,
596- locationRef ,
597+ locationRefs ,
597598 contributorsData ,
598599 createdAt ,
599600 params . onProgress ,
@@ -914,18 +915,25 @@ export class HypercertOperationsImpl extends EventEmitter<HypercertEvents> imple
914915 */
915916 async attachLocation ( hypercertUri : string , location : LocationParams ) : Promise < CreateResult > {
916917 try {
917- // Validate that hypercert exists (unused but confirms hypercert is valid)
918- await this . get ( hypercertUri ) ;
918+ // Get existing hypercert to preserve current locations
919+ const existing = await this . get ( hypercertUri ) ;
919920 const resolvedLocation = await this . resolveLocation ( location ) ;
920921
922+ // Build new locations array: existing + new location
923+ const existingLocations = existing . record . locations || [ ] ;
924+ const newLocations = [
925+ ...existingLocations ,
926+ {
927+ $type : "com.atproto.repo.strongRef" ,
928+ uri : resolvedLocation . uri ,
929+ cid : resolvedLocation . cid ,
930+ } as StrongRef ,
931+ ] ;
932+
921933 await this . update ( {
922934 uri : hypercertUri ,
923935 updates : {
924- location : {
925- $type : "com.atproto.repo.strongRef" ,
926- uri : resolvedLocation . uri ,
927- cid : resolvedLocation . cid ,
928- } ,
936+ locations : newLocations ,
929937 } ,
930938 } ) ;
931939
@@ -1108,28 +1116,28 @@ export class HypercertOperationsImpl extends EventEmitter<HypercertEvents> imple
11081116 }
11091117
11101118 /**
1111- * Processes location parameters, creating a location record if necessary.
1119+ * Processes location parameters, creating location records if necessary.
11121120 *
1113- * @param locationParams - Location parameters from create request
1121+ * @param locationParams - Location parameters array from create request
11141122 * @param onProgress - Optional progress callback
1115- * @returns Promise resolving to location StrongRef or undefined
1123+ * @returns Promise resolving to array of location StrongRefs or undefined
11161124 * @internal
11171125 */
1118- private async processLocation (
1119- locationParams : LocationParams | undefined ,
1126+ private async processLocations (
1127+ locationParams : LocationParams [ ] | undefined ,
11201128 onProgress ?: ( step : ProgressStep ) => void ,
1121- ) : Promise < { uri : string ; cid : string } | undefined > {
1122- if ( ! locationParams ) return undefined ;
1129+ ) : Promise < Array < { uri : string ; cid : string } > | undefined > {
1130+ if ( ! locationParams || locationParams . length === 0 ) return undefined ;
11231131
11241132 try {
11251133 this . emitProgress ( onProgress , { name : "createLocation" , status : "start" } ) ;
1126- const locationRef = await this . resolveLocation ( locationParams ) ;
1134+ const locationRefs = await Promise . all ( locationParams . map ( ( loc ) => this . resolveLocation ( loc ) ) ) ;
11271135 this . emitProgress ( onProgress , {
11281136 name : "createLocation" ,
11291137 status : "success" ,
1130- data : { uri : locationRef . uri } ,
1138+ data : { count : locationRefs . length } ,
11311139 } ) ;
1132- return locationRef ;
1140+ return locationRefs ;
11331141 } catch ( error ) {
11341142 this . emitProgress ( onProgress , { name : "createLocation" , status : "error" , error : error as Error } ) ;
11351143 this . logger ?. warn ( `Failed to create location: ${ error instanceof Error ? error . message : "Unknown" } ` ) ;
0 commit comments