File uploads and jobs
uploadGeofences
uploadGeofences imports a geofence file and waits for the import job to finish. It requests a presigned upload URL, uploads the file, finalizes the upload, starts the import job, and polls until the job reaches a terminal status.
import {SpatialFlow, uploadGeofences} from '@spatialflow/sdk';
const client = new SpatialFlow({apiKey: process.env.SPATIALFLOW_API_KEY});
const result = await uploadGeofences({
client,
filePath: 'boundaries.geojson',
groupName: 'regions',
timeout: 120_000,
onStatus: (status) => console.log(`Status: ${status}`),
});
console.log(`Created ${result.createdCount}, failed ${result.failedCount}`);
for (const geofence of result.createdGeofences) {
console.log(geofence.id, geofence.name);
}
for (const failure of result.errors) {
console.log(failure.index, failure.name, failure.error);
}
Options
| Option | Type | Default | Description |
|---|---|---|---|
client | SpatialFlow | required | The client to use |
filePath | string | required | Path to a .geojson, .json, .kml, or .gpx file |
groupName | string | none | Group name for the created geofences |
timeout | number | 300000 | Polling budget in milliseconds, spent in pollInterval steps (see pollJob) |
pollInterval | number | 2000 | Time between status polls, in milliseconds |
onStatus | (status, response) => void | none | Called after each poll |
An API key needs geofences:create, geofences:read, and storage:write, and its owner must be an owner or manager. The helper reads the whole file into memory and uses the global fetch, so it needs Node.js 18 or later.
Result
uploadGeofences resolves to a JobResult:
| Field | Type | Description |
|---|---|---|
jobId | string | Import job ID |
status | string | Final status |
createdCount | number | Geofences created |
failedCount | number | Features that failed |
totalFeatures | number | Features in the file |
createdGeofences | {id, name}[] | The geofences that were created |
errors | {index, name, error}[] | Per-feature failures |
warnings | string[] | Warnings from processing |
duration | number | undefined | Duration in seconds, when reported |
results | Record<string, unknown> | The raw results object |
rawResponse | unknown | The last status response |
pollJob
pollJob polls any job-status call until the status is completed or failed. uploadGeofences uses it for the import job.
import {SpatialFlow, pollJob, JobFailedError, JobTimeoutError} from '@spatialflow/sdk';
const client = new SpatialFlow({apiKey: process.env.SPATIALFLOW_API_KEY});
const jobId = '3f1b6a52-0000-0000-0000-000000000000';
try {
const result = await pollJob({
fetchStatus: () => client.geofences.appsGeofencesApiGetUploadJobStatus(jobId),
timeout: 120_000,
pollInterval: 2000,
onStatus: (status) => console.log(`Status: ${status}`),
});
console.log(`Created ${result.createdCount} geofences`);
} catch (error) {
if (error instanceof JobFailedError) {
console.log(`Job ${error.jobId} failed: ${error.errorMessage}`);
} else if (error instanceof JobTimeoutError) {
console.log(`Gave up after ${error.timeoutMs} ms, last status ${error.lastStatus}`);
} else {
throw error;
}
}
Options
| Option | Type | Default | Description |
|---|---|---|---|
fetchStatus | () => Promise<T> | required | Fetches the current job status |
timeout | number | 300000 | Polling budget in milliseconds. Each pass adds pollInterval to a counter, and the time spent in status calls is not counted |
pollInterval | number | 2000 | Time between polls, in milliseconds |
terminalStatuses | string[] | ['completed', 'failed'] | Statuses that end polling |
onStatus | (status, response) => void | none | Called after each poll |
extractJobId | (response) => string | reads job_id | Custom job ID lookup |
extractStatus | (response) => string | reads status | Custom status lookup |
A job with status failed rejects with JobFailedError, which has jobId, errorMessage, and results. The timeout is not a wall-clock deadline. pollJob adds pollInterval to a counter after each status call and stops when the counter reaches timeout, so slow status calls make the real wait longer. A status call that never returns blocks the loop, and with a SpatialFlow client call it is bounded only by the client's request timeout (30 seconds by default). When the counter reaches the limit first, the call rejects with JobTimeoutError, which extends TimeoutError and has jobId, timeoutMs, and lastStatus.