From b1bc733922f8c2af3a659244726fc086c4e4cbe2 Mon Sep 17 00:00:00 2001 From: Kyle Hensel Date: Sun, 9 Mar 2025 12:03:55 +1100 Subject: [PATCH] v3: several breaking changes for changeset APIs to be consistent with... ...the OSM API's new json endpoints. --- CHANGELOG.md | 8 ++++ src/__tests__/__snapshots__/e2e.test.ts.snap | 43 ++++++++----------- src/api/_rawResponse.d.ts | 21 +-------- .../__tests__/uploadChangeset.test.ts | 4 +- src/api/changesets/getChangesets.ts | 21 ++------- src/api/changesets/uploadChangeset.ts | 4 +- src/types/changesets.ts | 39 +++++++---------- 7 files changed, 52 insertions(+), 88 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77e816b..917dce2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## 3.0.0 (----------) + +- 💥 BREAKING CHANGE: `uploadChangeset` now returns an array of changeset IDs. This is because the function supports chunking uploads into multiple changesets if it exceeds the limit of 10,000 features per changeset. +- 💥 BREAKING CHANGE: The type defintions for `Changeset` have been changed to mark several properties as optional. (see #14) +- 💥 BREAKING CHANGE: `Changeset.created_at`, `Changeset.closed_at`, and `ChangesetComment.date` are now a `string`, not a `Date`. This makes it more consistent with the XML format, and easier to serialise to JSON. +- 💥 BREAKING CHANGE: `ChangesetComment.uid` is now a `number`, not a `string`. This matches the behaviour of OSM's new json API. +- 💥 BREAKING CHANGE: `Changeset.discussion` has been renamed to `Changeset.comments`. This matches the behaviour of OSM's new json API. + ## 2.4.0 (2025-01-16) - Added a method to easily switch users (logout & log back in) diff --git a/src/__tests__/__snapshots__/e2e.test.ts.snap b/src/__tests__/__snapshots__/e2e.test.ts.snap index 891f8fd..c84b1a8 100644 --- a/src/__tests__/__snapshots__/e2e.test.ts.snap +++ b/src/__tests__/__snapshots__/e2e.test.ts.snap @@ -105,10 +105,9 @@ exports[`end to end tests > getCapabilities 1`] = ` exports[`end to end tests > getChangeset (no discussion) 1`] = ` { "changes_count": 10, - "closed_at": 2021-12-16T09:29:15.000Z, + "closed_at": "2021-12-16T09:29:15Z", "comments_count": 2, - "created_at": 2021-12-16T09:29:14.000Z, - "discussion": undefined, + "created_at": "2021-12-16T09:29:14Z", "id": 227200, "max_lat": -36.8801278, "max_lon": 174.7400986, @@ -132,27 +131,27 @@ exports[`end to end tests > getChangeset (no discussion) 1`] = ` exports[`end to end tests > getChangeset (with discussion) 1`] = ` { "changes_count": 10, - "closed_at": 2021-12-16T09:29:15.000Z, - "comments_count": 2, - "created_at": 2021-12-16T09:29:14.000Z, - "discussion": [ + "closed_at": "2021-12-16T09:29:15Z", + "comments": [ { - "date": 2024-06-30T08:59:15.000Z, + "date": "2024-06-30T08:59:15Z", "id": 736, "text": "­", - "uid": "12248", + "uid": 12248, "user": "kylenz_testing", "visible": true, }, { - "date": 2024-06-30T08:59:55.000Z, + "date": "2024-06-30T08:59:55Z", "id": 737, "text": "sup bro", - "uid": "12248", + "uid": 12248, "user": "kylenz_testing", "visible": true, }, ], + "comments_count": 2, + "created_at": "2021-12-16T09:29:14Z", "id": 227200, "max_lat": -36.8801278, "max_lon": 174.7400986, @@ -487,7 +486,7 @@ exports[`end to end tests > getUser 1`] = ` }, }, "changesets": { - "count": 15, + "count": 27, }, "contributor_terms": { "agreed": true, @@ -506,10 +505,9 @@ exports[`end to end tests > listChangesets 1`] = ` [ { "changes_count": 2, - "closed_at": 2022-09-10T11:47:14.000Z, + "closed_at": "2022-09-10T11:47:14Z", "comments_count": 0, - "created_at": 2022-09-10T11:47:13.000Z, - "discussion": undefined, + "created_at": "2022-09-10T11:47:13Z", "id": 243638, "max_lat": -36.8804862, "max_lon": 174.739748, @@ -526,10 +524,9 @@ exports[`end to end tests > listChangesets 1`] = ` }, { "changes_count": 10, - "closed_at": 2022-09-10T11:30:13.000Z, + "closed_at": "2022-09-10T11:30:13Z", "comments_count": 0, - "created_at": 2022-09-10T11:30:12.000Z, - "discussion": undefined, + "created_at": "2022-09-10T11:30:12Z", "id": 243637, "max_lat": -36.8804809, "max_lon": 174.7397571, @@ -549,10 +546,9 @@ exports[`end to end tests > listChangesets 1`] = ` }, { "changes_count": 10, - "closed_at": 2021-12-16T09:29:15.000Z, + "closed_at": "2021-12-16T09:29:15Z", "comments_count": 2, - "created_at": 2021-12-16T09:29:14.000Z, - "discussion": undefined, + "created_at": "2021-12-16T09:29:14Z", "id": 227200, "max_lat": -36.8801278, "max_lon": 174.7400986, @@ -573,10 +569,9 @@ exports[`end to end tests > listChangesets 1`] = ` }, { "changes_count": 5, - "closed_at": 2021-12-16T08:43:07.000Z, + "closed_at": "2021-12-16T08:43:07Z", "comments_count": 0, - "created_at": 2021-12-16T08:43:06.000Z, - "discussion": undefined, + "created_at": "2021-12-16T08:43:06Z", "id": 227184, "max_lat": -36.8804809, "max_lon": 174.7397571, diff --git a/src/api/_rawResponse.d.ts b/src/api/_rawResponse.d.ts index bef8c5d..12bf9b2 100644 --- a/src/api/_rawResponse.d.ts +++ b/src/api/_rawResponse.d.ts @@ -1,24 +1,5 @@ import type { FeatureCollection, Point } from "geojson"; -import type { - Changeset, - ChangesetComment, - OsmFeatureType, - OsmNote, -} from "../types"; - -/** @internal */ -export type RawChangeset = Omit< - Changeset, - "discussion" | "created_at" | "closed_at" -> & { - created_at: string; - closed_at?: string; - comments?: (Omit & { - /** ISO Date */ - date: string; - uid: number; - })[]; -}; +import type { OsmFeatureType, OsmNote } from "../types"; /** @internal */ export type RawNotesSearch = FeatureCollection< diff --git a/src/api/changesets/__tests__/uploadChangeset.test.ts b/src/api/changesets/__tests__/uploadChangeset.test.ts index 48d8e94..24a2a04 100644 --- a/src/api/changesets/__tests__/uploadChangeset.test.ts +++ b/src/api/changesets/__tests__/uploadChangeset.test.ts @@ -69,7 +69,7 @@ describe("uploadChangeset", () => { ); } - expect(output).toBe(1); + expect(output).toStrictEqual([1, 4, 7, 10]); }); it("splits changesets into chunks and suports a custom tag function", async () => { @@ -101,6 +101,6 @@ describe("uploadChangeset", () => { ); } - expect(output).toBe(1); + expect(output).toStrictEqual([1, 4, 7, 10]); }); }); diff --git a/src/api/changesets/getChangesets.ts b/src/api/changesets/getChangesets.ts index 19b7671..8b37c82 100644 --- a/src/api/changesets/getChangesets.ts +++ b/src/api/changesets/getChangesets.ts @@ -1,18 +1,5 @@ import type { BBox, Changeset } from "../../types"; import { osmFetch } from "../_osmFetch"; -import type { RawChangeset } from "../_rawResponse"; - -const mapRawChangeset = ({ comments, ...raw }: RawChangeset): Changeset => ({ - ...raw, - created_at: new Date(raw.created_at), - closed_at: raw.closed_at ? new Date(raw.closed_at) : undefined!, - - discussion: comments?.map((comment) => ({ - ...comment, - date: new Date(comment.date), - uid: `${comment.uid}`, - })), -}); export type ListChangesetOptions = { /** Find changesets within the given bounding box */ @@ -51,7 +38,7 @@ export async function listChangesets( ): Promise { const { only, ...otherOptions } = options; - const raw = await osmFetch<{ changesets: RawChangeset[] }>( + const raw = await osmFetch<{ changesets: Changeset[] }>( "/0.6/changesets.json", { ...(only && { [only]: true }), @@ -59,7 +46,7 @@ export async function listChangesets( } ); - return raw.changesets.map(mapRawChangeset); + return raw.changesets; } /** get a single changeset */ @@ -67,10 +54,10 @@ export async function getChangeset( id: number, includeDiscussion = true ): Promise { - const raw = await osmFetch<{ changeset: RawChangeset }>( + const raw = await osmFetch<{ changeset: Changeset }>( `/0.6/changeset/${id}.json`, includeDiscussion ? { include_discussion: 1 } : {} ); - return mapRawChangeset(raw.changeset); + return raw.changeset; } diff --git a/src/api/changesets/uploadChangeset.ts b/src/api/changesets/uploadChangeset.ts index 99179b7..99e6c16 100644 --- a/src/api/changesets/uploadChangeset.ts +++ b/src/api/changesets/uploadChangeset.ts @@ -32,7 +32,7 @@ export async function uploadChangeset( */ onChunk?(info: UploadChunkInfo): Tags; } -): Promise { +): Promise { const chunks = chunkOsmChange(diff); const csIds: number[] = []; @@ -82,5 +82,5 @@ export async function uploadChangeset( csIds.push(csId); } - return csIds[0]; // TODO:(semver breaking) return an array of IDs + return csIds; } diff --git a/src/types/changesets.ts b/src/types/changesets.ts index 8dece53..b80ad92 100644 --- a/src/types/changesets.ts +++ b/src/types/changesets.ts @@ -4,42 +4,35 @@ export type ChangesetComment = { id: number; visible: boolean; user: string; - // TODO:(semver breaking) change to number - uid: string; - // TODO:(semver breaking) change to string - date: Date; + uid: number; + date: string; text: string; }; export type Changeset = { id: number; - // TODO:(semver breaking) change to string - created_at: Date; + created_at: string; open: boolean; comments_count: number; changes_count: number; - /** property only exists if `open=false` */ - // TODO:(semver breaking) mark as optional - closed_at: Date; - /** property only exists if `open=false` */ - // TODO:(semver breaking) mark as optional - min_lat: number; - /** property only exists if `open=false` */ - // TODO:(semver breaking) mark as optional - min_lon: number; - /** property only exists if `open=false` */ - // TODO:(semver breaking) mark as optional - max_lat: number; - /** property only exists if `open=false` */ - // TODO:(semver breaking) mark as optional - max_lon: number; + /** This property is missing if `open=true` */ + closed_at?: string; + /** This property is missing if `open=true`, or if none of the edited features have geometry data (see #14) */ + min_lat?: number; + /** This property is missing if `open=true`, or if none of the edited features have geometry data (see #14) */ + min_lon?: number; + /** This property is missing if `open=true`, or if none of the edited features have geometry data (see #14) */ + max_lat?: number; + /** This property is missing if `open=true`, or if none of the edited features have geometry data (see #14) */ + max_lon?: number; uid: number; user: string; tags: { [key: string]: string; }; - /** the `discussion` attribute is only included in the `getChangeset` API */ - discussion?: ChangesetComment[]; + + /** the `comments` attribute is only included in the `getChangeset` API */ + comments?: ChangesetComment[]; }; export type OsmChange = {