tangled
alpha
login
or
join now
leaflet.pub
/
leaflet
289
fork
atom
a tool for shared writing and social publishing
289
fork
atom
overview
issues
27
pulls
pipelines
update migration workflow to handle old/new records
awarm.space
1 month ago
c2ed386a
fb84b493
+125
1 changed file
expand all
collapse all
unified
split
app
api
inngest
functions
migrate_user_to_standard.ts
+125
app/api/inngest/functions/migrate_user_to_standard.ts
···
38
38
const stats = {
39
39
publicationsMigrated: 0,
40
40
documentsMigrated: 0,
41
41
+
standardDocumentsFixed: 0,
41
42
userSubscriptionsMigrated: 0,
42
43
referencesUpdated: 0,
43
44
errors: [] as string[],
···
320
321
stats.errors.push(
321
322
`Document ${result.oldUri}: Database error: ${result.error}`,
322
323
);
324
324
+
}
325
325
+
}
326
326
+
327
327
+
// Step 4b: Fix existing site.standard.document records that reference pub.leaflet.publication
328
328
+
// This handles the case where site.standard.document records were created pointing to
329
329
+
// pub.leaflet.publication URIs before the publication was migrated to site.standard.publication
330
330
+
const existingStandardDocs = await step.run(
331
331
+
"fetch-existing-standard-documents",
332
332
+
async () => {
333
333
+
const { data, error } = await supabaseServerClient
334
334
+
.from("documents")
335
335
+
.select("uri, data")
336
336
+
.like("uri", `at://${did}/site.standard.document/%`);
337
337
+
338
338
+
if (error)
339
339
+
throw new Error(
340
340
+
`Failed to fetch existing standard documents: ${error.message}`,
341
341
+
);
342
342
+
return data || [];
343
343
+
},
344
344
+
);
345
345
+
346
346
+
// Find documents that reference pub.leaflet.publication and need their site field updated
347
347
+
const standardDocsToFix = existingStandardDocs
348
348
+
.map((doc) => {
349
349
+
const data = doc.data as SiteStandardDocument.Record;
350
350
+
const site = data?.site;
351
351
+
352
352
+
// Check if site field references a pub.leaflet.publication
353
353
+
if (!site || !site.includes("/pub.leaflet.publication/")) {
354
354
+
return null;
355
355
+
}
356
356
+
357
357
+
try {
358
358
+
const oldPubAturi = new AtUri(site);
359
359
+
const newPubUri = `at://${oldPubAturi.hostname}/site.standard.publication/${oldPubAturi.rkey}`;
360
360
+
361
361
+
// Only fix if we have the new publication in our map (meaning it was migrated)
362
362
+
// or if the new publication exists (check against all migrated publications)
363
363
+
if (
364
364
+
publicationUriMap[site] ||
365
365
+
Object.values(publicationUriMap).includes(newPubUri)
366
366
+
) {
367
367
+
const docAturi = new AtUri(doc.uri);
368
368
+
const updatedRecord: SiteStandardDocument.Record = {
369
369
+
...data,
370
370
+
site: newPubUri,
371
371
+
};
372
372
+
373
373
+
return {
374
374
+
doc,
375
375
+
rkey: docAturi.rkey,
376
376
+
oldSite: site,
377
377
+
newSite: newPubUri,
378
378
+
updatedRecord,
379
379
+
};
380
380
+
}
381
381
+
} catch (e) {
382
382
+
stats.errors.push(`Invalid site URI in document ${doc.uri}: ${site}`);
383
383
+
}
384
384
+
385
385
+
return null;
386
386
+
})
387
387
+
.filter((x) => x !== null);
388
388
+
389
389
+
// Update these documents on PDS and in database
390
390
+
if (standardDocsToFix.length > 0) {
391
391
+
const fixResults = await Promise.all(
392
392
+
standardDocsToFix.map(({ doc, rkey, oldSite, newSite, updatedRecord }) =>
393
393
+
step.run(`fix-standard-document-${doc.uri}`, async () => {
394
394
+
// PDS write to update the site field
395
395
+
const agent = await createAuthenticatedAgent(did);
396
396
+
await agent.com.atproto.repo.putRecord({
397
397
+
repo: did,
398
398
+
collection: "site.standard.document",
399
399
+
rkey,
400
400
+
record: updatedRecord,
401
401
+
validate: false,
402
402
+
});
403
403
+
404
404
+
// DB write
405
405
+
const { error: dbError } = await supabaseServerClient
406
406
+
.from("documents")
407
407
+
.update({ data: updatedRecord as Json })
408
408
+
.eq("uri", doc.uri);
409
409
+
410
410
+
if (dbError) {
411
411
+
return {
412
412
+
success: false as const,
413
413
+
uri: doc.uri,
414
414
+
error: dbError.message,
415
415
+
};
416
416
+
}
417
417
+
418
418
+
// Update documents_in_publications to point to new publication URI
419
419
+
await supabaseServerClient
420
420
+
.from("documents_in_publications")
421
421
+
.upsert({
422
422
+
publication: newSite,
423
423
+
document: doc.uri,
424
424
+
});
425
425
+
426
426
+
// Remove old publication reference if different
427
427
+
if (oldSite !== newSite) {
428
428
+
await supabaseServerClient
429
429
+
.from("documents_in_publications")
430
430
+
.delete()
431
431
+
.eq("publication", oldSite)
432
432
+
.eq("document", doc.uri);
433
433
+
}
434
434
+
435
435
+
return { success: true as const, uri: doc.uri };
436
436
+
}),
437
437
+
),
438
438
+
);
439
439
+
440
440
+
for (const result of fixResults) {
441
441
+
if (result.success) {
442
442
+
stats.standardDocumentsFixed++;
443
443
+
} else {
444
444
+
stats.errors.push(
445
445
+
`Fix standard document ${result.uri}: Database error: ${result.error}`,
446
446
+
);
447
447
+
}
323
448
}
324
449
}
325
450