import { createSync } from 'nango';
import { z } from 'zod';
const SyncCursor = z.object({
currentStartTime: z.string().optional(),
lastProcessedId: z.string().optional(),
totalProcessed: z.number().optional()
});
const DataRecord = z.object({
id: z.string(),
data: z.any()
});
const sync = createSync({
description: '24-hour extended sync for large datasets',
version: '1.0.0',
frequency: 'every day',
autoStart: true,
syncType: 'full',
endpoints: [
{
method: 'GET',
path: '/data',
group: 'Data'
}
],
models: {
DataRecord: DataRecord
},
metadata: SyncCursor,
exec: async (nango) => {
const START_TIME = Date.now();
const MAX_RUNTIME_MS = 23.5 * 60 * 60 * 1000; // 23.5 hours in milliseconds
// Get or initialize sync metadata
let metadata = await nango.getMetadata<z.infer<typeof SyncCursor>>();
// Initialize sync window if first run
if (!metadata?.currentStartTime) {
await nango.updateMetadata({
currentStartTime: new Date().toISOString(),
lastProcessedId: null,
totalProcessed: 0
});
metadata = await nango.getMetadata<z.infer<typeof SyncCursor>>();
}
let shouldContinue = true;
while (shouldContinue) {
// Check if we're approaching the 24h limit
const timeElapsed = Date.now() - START_TIME;
if (timeElapsed >= MAX_RUNTIME_MS) {
// Save progress and exit gracefully
await nango.log('Approaching 24h limit, saving progress and exiting');
return;
}
// Fetch and process data batch
const response = await fetchDataBatch(metadata.lastProcessedId);
await processAndSaveData(response.data);
// Update progress
await nango.updateMetadata({
lastProcessedId: response.lastId,
totalProcessed: (metadata.totalProcessed || 0) + response.data.length
});
// Check if we're done
if (response.isLastPage) {
// Reset metadata for fresh start
await nango.updateMetadata({
currentStartTime: null,
lastProcessedId: null,
totalProcessed: 0
});
shouldContinue = false;
}
}
}
});
async function fetchDataBatch(lastId: string | null): Promise<{data: any[], lastId: string, isLastPage: boolean}> {
const config = {
endpoint: '/data',
params: {
after: lastId,
limit: 100
},
retries: 10
};
const response = await nango.get(config);
return {
data: response.data.records,
lastId: response.data.records[response.data.records.length - 1]?.id,
isLastPage: !response.data.nextRecordsUrl
};
}