From eb9d227a644d72f3eb403e803b37992d2893a7a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Ciccola?= Date: Mon, 2 Sep 2024 14:26:44 -0300 Subject: [PATCH 1/7] add `remoteDetectionAlert` doc type --- proto/geometry/v1.proto | 4 ++ proto/remoteDetectionAlert/v1.proto | 22 ++++++++ schema/remoteDetectionAlert/v1.json | 81 ++++++++++++++++++++++++++++ scripts/lib/parse-config.js | 2 +- src/decode.ts | 3 ++ src/encode.ts | 7 +++ src/lib/decode-conversions.ts | 21 ++++++++ src/lib/encode-conversions.ts | 11 ++++ src/types.ts | 1 + test/fixtures/bad-docs.js | 14 +++++ test/fixtures/good-docs-completed.js | 18 +++++++ test/fixtures/good-docs-minimal.js | 18 +++++++ 12 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 proto/geometry/v1.proto create mode 100644 proto/remoteDetectionAlert/v1.proto create mode 100644 schema/remoteDetectionAlert/v1.json diff --git a/proto/geometry/v1.proto b/proto/geometry/v1.proto new file mode 100644 index 0000000..4386782 --- /dev/null +++ b/proto/geometry/v1.proto @@ -0,0 +1,4 @@ +syntax = "proto3"; +package mapeo; + +message Geometry_1 {} diff --git a/proto/remoteDetectionAlert/v1.proto b/proto/remoteDetectionAlert/v1.proto new file mode 100644 index 0000000..290a455 --- /dev/null +++ b/proto/remoteDetectionAlert/v1.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; +package mapeo; + +import "common/v1.proto"; +import "geometry/v1.proto"; +import "google/protobuf/timestamp.proto"; +import "options.proto"; +import "tags/v1.proto"; + +message RemoteDetectionAlert_1 { + // **DO NOT CHANGE dataTypeId** generated with `openssl rand -hex 6` + option (dataTypeId) = "33a966ee6c90"; + option (schemaName) = "remoteDetectionAlert"; + + Common_1 common = 1; + + google.protobuf.Timestamp detectionDateStart = 2; + google.protobuf.Timestamp detectionDateEnd = 3; + string sourceId = 4; + Geometry_1 geometry = 5; + map metadata = 6; +} diff --git a/schema/remoteDetectionAlert/v1.json b/schema/remoteDetectionAlert/v1.json new file mode 100644 index 0000000..372f507 --- /dev/null +++ b/schema/remoteDetectionAlert/v1.json @@ -0,0 +1,81 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://mapeo.world/schemas/remoteDetectionAlert/v1.json", + "title": "RemoteDetectionAlert", + "description": "A remote detection alert is a type of element in the map that relates to an alert (regarding an urgent event that happened on the territory)", + "type": "object", + "properties": { + "schemaName": { + "description": "Must be `remoteDetectionAlert`", + "type": "string", + "const": "remoteDetectionAlert" + }, + "detectionDateStart": { + "type": "string", + "format": "date-time", + "description": "Timestamp of when the detected alert started" + }, + "detectionDateEnd": { + "type": "string", + "format": "date-time", + "description": "Timestamp of when the detected alert ended" + }, + "sourceId": { + "type": "string", + "description": "unique string identifiying this alert, different from the `docId`" + }, + "metadata": { + "type": "object", + "description": "Additional metadata related to this alert. It is a map from a string to any element (including lists)", + "properties": {}, + "additionalProperties": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "null" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "null" + } + ] + } + } + ] + } + }, + "geometry": { + "type": "object", + "properties": {} + } + }, + "required": [ + "schemaName", + "detectionDateStart", + "detectionDateEnd", + "sourceId", + "metadata", + "geometry" + ], + "additionalProperties": false +} diff --git a/scripts/lib/parse-config.js b/scripts/lib/parse-config.js index a909cf7..2a7da67 100644 --- a/scripts/lib/parse-config.js +++ b/scripts/lib/parse-config.js @@ -6,7 +6,7 @@ import schema from 'protocol-buffers-schema' import { capitalize, PROJECT_ROOT } from './utils.js' // These messages are embedded in others and do not define Mapeo data types -const EMBEDDED_MESSAGES = ['tags', 'common', 'versionId'] +const EMBEDDED_MESSAGES = ['tags', 'common', 'versionId', 'geometry'] // We avoid creating data type IDs that match these, since blobs (e.g. icons) // can be stored in Mapeo hypercores, and we want to avoid trying to parse a diff --git a/src/decode.ts b/src/decode.ts index 198bfdf..06e4162 100644 --- a/src/decode.ts +++ b/src/decode.ts @@ -20,6 +20,7 @@ import { convertIcon, convertTranslation, convertTrack, + convertRemoteDetectionAlert, } from './lib/decode-conversions.js' // @ts-ignore import * as cenc from 'compact-encoding' @@ -81,6 +82,8 @@ export function decode( return convertTranslation(message, versionObj) case 'track': return convertTrack(message, versionObj) + case 'remoteDetectionAlert': + return convertRemoteDetectionAlert(message, versionObj) default: throw new ExhaustivenessError(message) } diff --git a/src/encode.ts b/src/encode.ts index 7294c08..3ce50b7 100644 --- a/src/encode.ts +++ b/src/encode.ts @@ -20,6 +20,7 @@ import { convertIcon, convertTranslation, convertTrack, + convertRemoteDetectionAlert, } from './lib/encode-conversions.js' import { CoreOwnership } from './index.js' import { ExhaustivenessError } from './lib/utils.js' @@ -89,6 +90,12 @@ export function encode(mapeoDoc: MapeoDocEncode): Buffer { protobuf = Encode[mapeoDoc.schemaName](message).finish() break } + case 'remoteDetectionAlert': { + const message = convertRemoteDetectionAlert(mapeoDoc) + protobuf = Encode[mapeoDoc.schemaName](message).finish() + break + } + default: throw new ExhaustivenessError(mapeoDoc) } diff --git a/src/lib/decode-conversions.ts b/src/lib/decode-conversions.ts index 6787545..89ab9e8 100644 --- a/src/lib/decode-conversions.ts +++ b/src/lib/decode-conversions.ts @@ -286,6 +286,27 @@ export const convertTrack: ConvertFunction<'track'> = (message, versionObj) => { } } +export const convertRemoteDetectionAlert: ConvertFunction< + 'remoteDetectionAlert' +> = (message, versionObj) => { + const { common, schemaVersion, ...rest } = message + const jsonSchemaCommon = convertCommon(common, versionObj) + if (!rest.detectionDateStart) { + throw new Error('missing required detectionDateStart') + } + if (!rest.detectionDateEnd) { + throw new Error('missing required detectionDateEnd') + } + return { + ...jsonSchemaCommon, + ...rest, + detectionDateStart: rest.detectionDateStart, + detectionDateEnd: rest.detectionDateEnd, + metadata: convertTags(rest.metadata), + geometry: rest.geometry || {}, + } +} + function convertIconVariant(variant: Icon_1_IconVariant) { if (variant.variant?.$case === 'pngIcon') { const { pixelDensity } = variant.variant.pngIcon diff --git a/src/lib/encode-conversions.ts b/src/lib/encode-conversions.ts index 5ddf86e..ee2ea4a 100644 --- a/src/lib/encode-conversions.ts +++ b/src/lib/encode-conversions.ts @@ -237,6 +237,17 @@ export const convertTrack: ConvertFunction<'track'> = (mapeoDoc) => { return track } +export const convertRemoteDetectionAlert: ConvertFunction< + 'remoteDetectionAlert' +> = (mapeoDoc) => { + // TODO: should we add a check for sourceId? (so that it complies with the id format we expect?) + return { + common: convertCommon(mapeoDoc), + ...mapeoDoc, + metadata: convertTags(mapeoDoc.metadata), + } +} + function convertCommon( common: SetOptional ): ProtoTypesWithSchemaInfo['common'] { diff --git a/src/types.ts b/src/types.ts index 90b649c..4b0fc2c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -20,6 +20,7 @@ type SupportedSchemaNames = | 'coreOwnership' | 'translation' | 'track' + | 'remoteDetectionAlert' export type SchemaName = Extract export type SchemaNameAll = keyof typeof dataTypeIds diff --git a/test/fixtures/bad-docs.js b/test/fixtures/bad-docs.js index 4e37aaf..24a749b 100644 --- a/test/fixtures/bad-docs.js +++ b/test/fixtures/bad-docs.js @@ -104,4 +104,18 @@ export const badDocs = [ color: '#ff00g1', }, }, + { + text: 'remoteDetectionAlert with missing elements', + doc: { + docId: cachedValues.docId, + versionId: cachedValues.versionId, + originalVersionId: cachedValues.versionId, + schemaName: 'remoteDetectionAlert', + createdAt: cachedValues.createdAt, + updatedAt: cachedValues.updatedAt, + links: [], + deleted: false, + sourceId: '', + }, + }, ] diff --git a/test/fixtures/good-docs-completed.js b/test/fixtures/good-docs-completed.js index 51123ae..6f35c96 100644 --- a/test/fixtures/good-docs-completed.js +++ b/test/fixtures/good-docs-completed.js @@ -333,4 +333,22 @@ export const goodDocsCompleted = [ }, expected: {}, }, + { + doc: { + docId: cachedValues.docId, + versionId: cachedValues.versionId, + originalVersionId: cachedValues.originalVersionId, + schemaName: 'remoteDetectionAlert', + createdAt: cachedValues.createdAt, + updatedAt: cachedValues.updatedAt, + links: [], + deleted: false, + sourceId: cachedValues.docId, + detectionDateStart: cachedValues.createdAt, + detectionDateEnd: cachedValues.updatedAt, + geometry: {}, + metadata: {}, + }, + expected: {}, + }, ] diff --git a/test/fixtures/good-docs-minimal.js b/test/fixtures/good-docs-minimal.js index d0ef98b..c9c6ad7 100644 --- a/test/fixtures/good-docs-minimal.js +++ b/test/fixtures/good-docs-minimal.js @@ -207,4 +207,22 @@ export const goodDocsMinimal = [ }, expected: {}, }, + { + doc: { + docId: cachedValues.docId, + versionId: cachedValues.versionId, + originalVersionId: cachedValues.originalVersionId, + schemaName: 'remoteDetectionAlert', + createdAt: cachedValues.createdAt, + updatedAt: cachedValues.updatedAt, + links: [], + deleted: false, + sourceId: '', + detectionDateStart: cachedValues.createdAt, + detectionDateEnd: cachedValues.updatedAt, + geometry: {}, + metadata: {}, + }, + expected: {}, + }, ] From c6ee77478b466aeb11edee22b4935c1d5489126c Mon Sep 17 00:00:00 2001 From: Gregor MacLennan Date: Wed, 4 Sep 2024 11:27:18 +0100 Subject: [PATCH 2/7] WIP: 7b5de70 add failing test --- test/fixtures/bad-docs.js | 1 - test/index.test.js | 70 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/test/fixtures/bad-docs.js b/test/fixtures/bad-docs.js index 4e37aaf..88e6190 100644 --- a/test/fixtures/bad-docs.js +++ b/test/fixtures/bad-docs.js @@ -39,7 +39,6 @@ export const badDocs = [ index: 123, }), ], - refs: [], attachments: [], tags: {}, metadata: {}, diff --git a/test/index.test.js b/test/index.test.js index 0ea13aa..7418bac 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -19,6 +19,7 @@ import { goodDocsCompleted, badDocs, } from './fixtures/index.js' +import { cachedValues } from './fixtures/cached.js' test('Bad docs throw when encoding', () => { for (const { text, doc } of badDocs) { @@ -225,6 +226,75 @@ test(`test encoding of wrongly formatted header`, async () => { }) }) +/** @type {import('../dist/index.js').Observation} */ +const minimalObservation = { + docId: cachedValues.docId, + versionId: cachedValues.versionId, + originalVersionId: cachedValues.originalVersionId, + schemaName: 'observation', + createdAt: cachedValues.createdAt, + updatedAt: cachedValues.updatedAt, + links: [], + lat: 24.0424, + lon: 21.0214, + attachments: [], + tags: {}, + metadata: {}, + deleted: false, +} + +test(`encoding observation with missing position metadata`, async () => { + /** @type {import('../dist/index.js').Observation} */ + const doc = { + ...minimalObservation, + metadata: { + position: /** @type {any} */ ({ coords: {} }), + }, + } + const buf = encode(doc) + const decodedDoc = decode(buf, parseVersionId(doc.versionId)) + assert.equal(decodedDoc.schemaName, 'observation') + // a previous bug meant that protobuf defaults of 0 were being set for lat/lon + assert.equal( + typeof decodedDoc.metadata?.position?.coords?.longitude, + 'undefined' + ) + assert.equal( + typeof decodedDoc.metadata?.position?.coords?.latitude, + 'undefined' + ) +}) + +test(`decoding observation with missing position provider props`, async () => { + /** @type {import('../dist/index.js').Observation} */ + const doc = { + ...minimalObservation, + metadata: { + positionProvider: { + locationServicesEnabled: true, + }, + }, + } + const buf = encode(doc) + const decodedDoc = decode(buf, parseVersionId(doc.versionId)) + assert.equal(decodedDoc.schemaName, 'observation') + assert.equal( + typeof decodedDoc.metadata?.positionProvider?.gpsAvailable, + 'undefined', + 'optional gpsAvailable prop should be undefined' + ) + assert.equal( + typeof decodedDoc.metadata?.positionProvider?.networkAvailable, + 'undefined', + 'optional networkAvailable prop should be undefined' + ) + assert.equal( + typeof decodedDoc.metadata?.positionProvider?.passiveAvailable, + 'undefined', + 'optional passiveAvailable prop should be undefined' + ) +}) + /** * Remove undefined properties (deeply) from an object, by round-tripping to * JSON. Also handles Buffers via JSON.parse reviver From 747289d0f5645c401f9dd63677d73806f49ca7e0 Mon Sep 17 00:00:00 2001 From: Gregor MacLennan Date: Wed, 4 Sep 2024 12:39:40 +0100 Subject: [PATCH 3/7] fix: observation metadata types and encoding defaults --- proto/observation/v1.proto | 8 +++---- schema/observation/v1.json | 2 ++ src/lib/decode-conversions.ts | 44 ++++++++++++++++++++++++++++++++--- src/lib/encode-conversions.ts | 4 ---- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/proto/observation/v1.proto b/proto/observation/v1.proto index d2d4bc0..447d891 100644 --- a/proto/observation/v1.proto +++ b/proto/observation/v1.proto @@ -38,7 +38,7 @@ message Observation_1 { // METADATA message Metadata { - bool manualLocation = 1; + optional bool manualLocation = 1; message Position { google.protobuf.Timestamp timestamp = 1; @@ -57,10 +57,10 @@ message Observation_1 { } message PositionProvider { - bool gpsAvailable = 1; - bool passiveAvailable = 2; + optional bool gpsAvailable = 1; + optional bool passiveAvailable = 2; bool locationServicesEnabled = 3; - bool networkAvailable = 4; + optional bool networkAvailable = 4; } optional Position position = 3; diff --git a/schema/observation/v1.json b/schema/observation/v1.json index a1fc651..fe29cb3 100644 --- a/schema/observation/v1.json +++ b/schema/observation/v1.json @@ -7,6 +7,7 @@ "position": { "description": "Position details", "type": "object", + "required": ["timestamp", "coords"], "properties": { "timestamp": { "description": "Timestamp of when the current position was obtained", @@ -162,6 +163,7 @@ "positionProvider": { "description": "Details of the location providers that were available on the device when the observation was recorded", "type": "object", + "required": ["locationServicesEnabled"], "properties": { "gpsAvailable": { "description": "Whether the user has enabled GPS for device location (this is not the same as whether location is turned on or off, this is a device setting whether to use just wifi and bluetooth or use GPS for location)", diff --git a/src/lib/decode-conversions.ts b/src/lib/decode-conversions.ts index 9e3d6a6..1a1c21c 100644 --- a/src/lib/decode-conversions.ts +++ b/src/lib/decode-conversions.ts @@ -22,10 +22,15 @@ import { } from '../types.js' import { ExhaustivenessError, VersionIdObject, getVersionId } from './utils.js' import type { Observation, Track } from '../index.js' -import type { Observation_1_Attachment } from '../proto/observation/v1.js' +import type { + Observation_1_Attachment, + Observation_1_Metadata, + Observation_1_Metadata_Position, +} from '../proto/observation/v1.js' import type { Track_1_Position } from '../proto/track/v1.js' import { ProjectSettings_1_ConfigMetadata } from '../proto/projectSettings/v1.js' import { ProjectSettings } from '../schema/projectSettings.js' +import type { Position } from '../schema/observation.js' /** Function type for converting a protobuf type of any version for a particular * schema name, and returning the most recent JSONSchema type */ @@ -76,7 +81,7 @@ export const convertObservation: ConvertFunction<'observation'> = ( message, versionObj ) => { - const { common, schemaVersion, ...rest } = message + const { common, metadata, schemaVersion, ...rest } = message const jsonSchemaCommon = convertCommon(common, versionObj) let presetRef @@ -95,7 +100,8 @@ export const convertObservation: ConvertFunction<'observation'> = ( ...rest, attachments: message.attachments.map(convertAttachment), tags: convertTags(message.tags), - metadata: message.metadata, + // Remove invalid position metadata if it's missing required fields + metadata: metadata ? removeInvalidPositionMetadata(metadata) : {}, presetRef, } return obs @@ -453,3 +459,35 @@ function convertTrackPosition( timestamp: position.timestamp, } } + +/** + * Because of the way protobuf works, it's possible that a protobuf message is + * missing required fields. In this case `timestamp` and the `latitude` and + * `longitude` fields on `coords`. We shouldn't have any observations with these + * fields missing, but if we do, rather than throwing (and not indexing the + * observation at all), we remove the position metadata, since it is not useful + * without this metadata. + */ +function removeInvalidPositionMetadata( + metadata: Observation_1_Metadata +): Observation['metadata'] { + const { position, lastSavedPosition, ...rest } = metadata + return { + ...rest, + position: position && removeInvalidPosition(position), + lastSavedPosition: + lastSavedPosition && removeInvalidPosition(lastSavedPosition), + } +} + +function removeInvalidPosition( + position: Observation_1_Metadata_Position +): Position | undefined { + if ( + typeof position.coords === 'undefined' || + typeof position.timestamp === 'undefined' + ) { + return undefined + } + return position as Position +} diff --git a/src/lib/encode-conversions.ts b/src/lib/encode-conversions.ts index 74afc8f..a2cd415 100644 --- a/src/lib/encode-conversions.ts +++ b/src/lib/encode-conversions.ts @@ -95,9 +95,6 @@ export const convertObservation: ConvertFunction<'observation'> = ( mapeoDoc ) => { const attachments = mapeoDoc.attachments.map(convertAttachment) - const metadata: Observation_1_Metadata | undefined = mapeoDoc.metadata && { - ...Observation_1_Metadata.fromPartial(mapeoDoc.metadata), - } let presetRef if (mapeoDoc.presetRef) { presetRef = { @@ -111,7 +108,6 @@ export const convertObservation: ConvertFunction<'observation'> = ( ...mapeoDoc, attachments, tags: convertTags(mapeoDoc.tags), - metadata, presetRef, } } From 17b344eb378f2e8e1d26a61ad25faeaac2d42035 Mon Sep 17 00:00:00 2001 From: Gregor MacLennan Date: Wed, 4 Sep 2024 12:41:08 +0100 Subject: [PATCH 4/7] fix: don't generate partial and json methods (unused) --- buf.gen.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/buf.gen.yaml b/buf.gen.yaml index 7bc6513..a3c0343 100644 --- a/buf.gen.yaml +++ b/buf.gen.yaml @@ -7,6 +7,8 @@ plugins: opt: - esModuleInterop=true - importSuffix=.js + - outputJsonMethods=false + - outputPartialMethods=false - env=node - snakeToCamel=false - useDate=string From 7733276587d1d57109e502e635f914a7c9a896cc Mon Sep 17 00:00:00 2001 From: Gregor MacLennan Date: Wed, 4 Sep 2024 14:57:56 +0100 Subject: [PATCH 5/7] Add geometry property --- buf.gen.yaml | 1 + package-lock.json | 427 ++++----------------- package.json | 3 +- proto/geometry/v1.proto | 5 +- proto/remoteDetectionAlert/v1.proto | 2 +- schema/remoteDetectionAlert/v1.json | 3 +- scripts/lib/generate-jsonschema-exports.js | 10 +- scripts/lib/generate-jsonschema-ts.js | 23 ++ scripts/lib/generate-validations.js | 6 +- src/lib/decode-conversions.ts | 5 +- test/fixtures/good-docs-completed.js | 5 +- test/fixtures/good-docs-minimal.js | 34 +- 12 files changed, 154 insertions(+), 370 deletions(-) diff --git a/buf.gen.yaml b/buf.gen.yaml index a3c0343..538ddad 100644 --- a/buf.gen.yaml +++ b/buf.gen.yaml @@ -17,3 +17,4 @@ plugins: - enumsAsLiterals=true # - outputIndex=true - oneof=unions + - Mgeometry/v1.proto=@comapeo/geometry diff --git a/package-lock.json b/package-lock.json index 903b71e..6847381 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "3.0.0-next.26", "license": "MIT", "dependencies": { + "@comapeo/geometry": "^1.0.1", "compact-encoding": "^2.12.0", "protobufjs": "^7.2.5", "type-fest": "^4.26.0" @@ -23,7 +24,7 @@ "eslint": "^8.46.0", "glob": "^10.3.3", "hypercore": "^10.4.1", - "json-schema-to-typescript": "^13.0.2", + "json-schema-to-typescript": "^15.0.2", "mkdirp": "^3.0.1", "npm-run-all": "^4.1.5", "prettier": "^3.0.0", @@ -45,6 +46,24 @@ "node": ">=0.10.0" } }, + "node_modules/@apidevtools/json-schema-ref-parser": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.0.tgz", + "integrity": "sha512-pRrmXMCwnmrkS3MLgAIW5dXRzeTv6GLjkjb4HmxNnvAKXN1Nfzp4KmGADBQvlVUcqi+a5D+hfGDLLnd5NnYxog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.15", + "js-yaml": "^4.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/philsturgeon" + } + }, "node_modules/@babel/code-frame": { "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", @@ -151,24 +170,6 @@ "node": ">=4" } }, - "node_modules/@bcherny/json-schema-ref-parser": { - "version": "10.0.5-fork", - "resolved": "https://registry.npmjs.org/@bcherny/json-schema-ref-parser/-/json-schema-ref-parser-10.0.5-fork.tgz", - "integrity": "sha512-E/jKbPoca1tfUPj3iSbitDZTGnq6FUFjkH6L8U2oDwSuwK1WhnnVtCG7oFOTg/DDnyoXbQYUiUiGOibHqaGVnw==", - "dev": true, - "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.6", - "call-me-maybe": "^1.0.1", - "js-yaml": "^4.1.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/philsturgeon" - } - }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", @@ -294,6 +295,15 @@ "node": ">=12" } }, + "node_modules/@comapeo/geometry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@comapeo/geometry/-/geometry-1.0.1.tgz", + "integrity": "sha512-ZH9akj8k/awYUm8GVGyGSs99xNGJotWoo3czCS3Ds3/RgewiSxHbe1JU6PnJ/M2sT6GqbTatAGgNky9g5pK6Vg==", + "license": "MIT", + "dependencies": { + "protobufjs": "^7.4.0" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -562,7 +572,8 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@json-schema-spec/json-pointer": { "version": "0.1.2", @@ -711,16 +722,6 @@ "@types/hast": "^3.0.4" } }, - "node_modules/@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", - "dev": true, - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, "node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", @@ -738,22 +739,18 @@ "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", - "dev": true + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/lodash": { - "version": "4.14.196", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.196.tgz", - "integrity": "sha512-22y3o88f4a94mKljsZcanlNWPzO0uBsBdzLAngf2tp533LzZcQzb6+eZPJ+vCTt+bqF2XnvT9gejTLsAcJAJyQ==", - "dev": true - }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true + "version": "4.17.7", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz", + "integrity": "sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/minimist": { "version": "1.2.2", @@ -772,12 +769,6 @@ "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", "dev": true }, - "node_modules/@types/prettier": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", - "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", - "dev": true - }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -862,12 +853,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1038,12 +1023,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/call-me-maybe": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", - "dev": true - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1159,22 +1138,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-color": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.3.tgz", - "integrity": "sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==", - "dev": true, - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.61", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.15", - "timers-ext": "^0.1.7" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -1308,16 +1271,6 @@ "node": ">= 8" } }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, - "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1543,54 +1496,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es5-ext": { - "version": "0.10.62", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", - "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dev": true, - "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -1775,16 +1680,6 @@ "node": ">=0.10.0" } }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -1794,21 +1689,6 @@ "node": ">=0.8.x" } }, - "node_modules/ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "dev": true, - "dependencies": { - "type": "^2.7.2" - } - }, - "node_modules/ext/node_modules/type": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", - "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", - "dev": true - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2066,18 +1946,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/get-symbol-description": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", @@ -2606,12 +2474,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -2782,97 +2644,27 @@ "dev": true }, "node_modules/json-schema-to-typescript": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-13.0.2.tgz", - "integrity": "sha512-TCaEVW4aI2FmMQe7f98mvr3/oiVmXEC1xZjkTZ9L/BSoTXFlC7p64mD5AD2d8XWycNBQZUnHwXL5iVXt1HWwNQ==", - "dev": true, - "dependencies": { - "@bcherny/json-schema-ref-parser": "10.0.5-fork", - "@types/json-schema": "^7.0.11", - "@types/lodash": "^4.14.182", - "@types/prettier": "^2.6.1", - "cli-color": "^2.0.2", - "get-stdin": "^8.0.0", - "glob": "^7.1.6", - "glob-promise": "^4.2.2", + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-15.0.2.tgz", + "integrity": "sha512-+cRBw+bBJ3k783mZroDIgz1pLNPB4hvj6nnbHTWwEVl0dkW8qdZ+M9jWhBb+Y0FAdHvNsXACga3lewGO8lktrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "^11.5.5", + "@types/json-schema": "^7.0.15", + "@types/lodash": "^4.17.7", + "glob": "^10.3.12", "is-glob": "^4.0.3", + "js-yaml": "^4.1.0", "lodash": "^4.17.21", - "minimist": "^1.2.6", - "mkdirp": "^1.0.4", - "mz": "^2.7.0", - "prettier": "^2.6.2" + "minimist": "^1.2.8", + "prettier": "^3.2.5" }, "bin": { "json2ts": "dist/src/cli.js" }, "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/json-schema-to-typescript/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/json-schema-to-typescript/node_modules/glob-promise": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/glob-promise/-/glob-promise-4.2.2.tgz", - "integrity": "sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw==", - "dev": true, - "dependencies": { - "@types/glob": "^7.1.3" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "individual", - "url": "https://github.com/sponsors/ahmadnassri" - }, - "peerDependencies": { - "glob": "^7.1.6" - } - }, - "node_modules/json-schema-to-typescript/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/json-schema-to-typescript/node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "node": ">=16.0.0" } }, "node_modules/json-schema-traverse": { @@ -2976,15 +2768,6 @@ "dev": true, "license": "ISC" }, - "node_modules/lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", - "dev": true, - "dependencies": { - "es5-ext": "~0.10.2" - } - }, "node_modules/lunr": { "version": "2.3.9", "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", @@ -3043,22 +2826,6 @@ "dev": true, "license": "MIT" }, - "node_modules/memoizee": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", - "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", - "dev": true, - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - } - }, "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -3222,10 +2989,11 @@ } }, "node_modules/minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3284,17 +3052,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, "node_modules/nanoassert": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz", @@ -3320,12 +3077,6 @@ "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==", "dev": true }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", - "dev": true - }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -3571,15 +3322,6 @@ "which": "bin/which" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-inspect": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", @@ -3878,10 +3620,11 @@ } }, "node_modules/prettier": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz", - "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, + "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, @@ -3893,10 +3636,11 @@ } }, "node_modules/protobufjs": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", - "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", + "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", "hasInstallScript": true, + "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -4888,43 +4632,12 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/timeout-refresh": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/timeout-refresh/-/timeout-refresh-2.0.1.tgz", "integrity": "sha512-SVqEcMZBsZF9mA78rjzCrYrUs37LMJk3ShZ851ygZYW1cMeIjs9mL57KO6Iv5mmjSQnOe/29/VAfGXo+oRCiVw==", "dev": true }, - "node_modules/timers-ext": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", - "dev": true, - "dependencies": { - "es5-ext": "~0.10.46", - "next-tick": "1" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -4990,12 +4703,6 @@ "protobufjs": "^7.2.4" } }, - "node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", - "dev": true - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index 40dbda7..af5beae 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "eslint": "^8.46.0", "glob": "^10.3.3", "hypercore": "^10.4.1", - "json-schema-to-typescript": "^13.0.2", + "json-schema-to-typescript": "^15.0.2", "mkdirp": "^3.0.1", "npm-run-all": "^4.1.5", "prettier": "^3.0.0", @@ -60,6 +60,7 @@ "typescript": "^5.5.4" }, "dependencies": { + "@comapeo/geometry": "^1.0.1", "compact-encoding": "^2.12.0", "protobufjs": "^7.2.5", "type-fest": "^4.26.0" diff --git a/proto/geometry/v1.proto b/proto/geometry/v1.proto index 4386782..23800ba 100644 --- a/proto/geometry/v1.proto +++ b/proto/geometry/v1.proto @@ -1,4 +1,7 @@ syntax = "proto3"; package mapeo; -message Geometry_1 {} +// stub to keep buf happy. ts-proto replaces this with +// the decoder/encoder from @comapeo/geometry + +message Geometry {} diff --git a/proto/remoteDetectionAlert/v1.proto b/proto/remoteDetectionAlert/v1.proto index 290a455..9354a12 100644 --- a/proto/remoteDetectionAlert/v1.proto +++ b/proto/remoteDetectionAlert/v1.proto @@ -17,6 +17,6 @@ message RemoteDetectionAlert_1 { google.protobuf.Timestamp detectionDateStart = 2; google.protobuf.Timestamp detectionDateEnd = 3; string sourceId = 4; - Geometry_1 geometry = 5; + Geometry geometry = 5; map metadata = 6; } diff --git a/schema/remoteDetectionAlert/v1.json b/schema/remoteDetectionAlert/v1.json index 372f507..0f487da 100644 --- a/schema/remoteDetectionAlert/v1.json +++ b/schema/remoteDetectionAlert/v1.json @@ -65,8 +65,7 @@ } }, "geometry": { - "type": "object", - "properties": {} + "$ref": "http://comapeo.app/schemas/shared/geometry.json" } }, "required": [ diff --git a/scripts/lib/generate-jsonschema-exports.js b/scripts/lib/generate-jsonschema-exports.js index 2fa8fd0..96255d4 100644 --- a/scripts/lib/generate-jsonschema-exports.js +++ b/scripts/lib/generate-jsonschema-exports.js @@ -1,5 +1,8 @@ // @ts-check import { default as _ } from '@json-schema-tools/dereferencer' +import { createRequire } from 'module' +const require = createRequire(import.meta.url) +const GeometryJSONSchema = require('@comapeo/geometry/json/geometry.json') // Dereferencer's exports are all wrong for ESM imports /** @type {any} */ @@ -28,7 +31,12 @@ export async function generateJSONSchemaExports(jsonSchemas) { const dereferencer = new JsonSchemaDereferencer( // Need to create a deep clone to avoid issue described in https://github.com/digidem/mapeo-schema/issues/109 JSON.parse(JSON.stringify(jsonSchema)), - { mutate: false } + { + mutate: false, + refCache: { + [GeometryJSONSchema.$id]: GeometryJSONSchema, + }, + } ) dereferencedDocSchemas[schemaName] = await dereferencer.resolve() } diff --git a/scripts/lib/generate-jsonschema-ts.js b/scripts/lib/generate-jsonschema-ts.js index 1c1e3e1..ed6fcb6 100644 --- a/scripts/lib/generate-jsonschema-ts.js +++ b/scripts/lib/generate-jsonschema-ts.js @@ -1,6 +1,12 @@ // @ts-check import { compile } from 'json-schema-to-typescript' import { capitalize } from './utils.js' +import { createRequire } from 'module' + +const require = createRequire(import.meta.url) +const GeometryJSONSchema = require('@comapeo/geometry/json/geometry.json') + +/** @import { ResolverOptions, JSONSchema } from '@apidevtools/json-schema-ref-parser' */ /** * Returns generated typescript definitions for JSONSchemas @@ -16,6 +22,12 @@ export async function generateJSONSchemaTS(config, jsonSchemas) { const ts = await compile(jsonSchema, capitalize(schemaName), { additionalProperties: false, unknownAny: false, + $refOptions: { + resolve: { + http: false, + geometry: geometryResolver, + }, + }, }) typescriptDefs[schemaName] = ts } @@ -84,3 +96,14 @@ function getValueName(schemaName) { ? 'MapeoCommon' : capitalize(schemaName) + 'Value' } + +/** @type {ResolverOptions} */ +const geometryResolver = { + order: 1, + canRead(file) { + return file.url === GeometryJSONSchema.$id + }, + read() { + return GeometryJSONSchema + }, +} diff --git a/scripts/lib/generate-validations.js b/scripts/lib/generate-validations.js index 09bef59..baa84a1 100644 --- a/scripts/lib/generate-validations.js +++ b/scripts/lib/generate-validations.js @@ -1,6 +1,10 @@ // @ts-check import Ajv from 'ajv' import standaloneCode from 'ajv/dist/standalone/index.js' +import { createRequire } from 'module' + +const require = createRequire(import.meta.url) +const GeometryJSONSchema = require('@comapeo/geometry/json/geometry.json') /** * Returns generated code for validation functions @@ -23,7 +27,7 @@ export function generateValidations(config, jsonSchemas) { code: { source: true, esm: true }, formats: { 'date-time': true }, }) - ajv.addKeyword('meta:enum') + ajv.addKeyword('meta:enum').addSchema(GeometryJSONSchema) // generate validation code return '// @ts-nocheck\n' + standaloneCode(ajv, schemaExports) diff --git a/src/lib/decode-conversions.ts b/src/lib/decode-conversions.ts index c8bba46..201c870 100644 --- a/src/lib/decode-conversions.ts +++ b/src/lib/decode-conversions.ts @@ -302,13 +302,16 @@ export const convertRemoteDetectionAlert: ConvertFunction< if (!rest.detectionDateEnd) { throw new Error('missing required detectionDateEnd') } + if (!rest.geometry) { + throw new Error('missing required geometry') + } return { ...jsonSchemaCommon, ...rest, detectionDateStart: rest.detectionDateStart, detectionDateEnd: rest.detectionDateEnd, metadata: convertTags(rest.metadata), - geometry: rest.geometry || {}, + geometry: rest.geometry, } } diff --git a/test/fixtures/good-docs-completed.js b/test/fixtures/good-docs-completed.js index d90a73b..727ebf9 100644 --- a/test/fixtures/good-docs-completed.js +++ b/test/fixtures/good-docs-completed.js @@ -346,7 +346,10 @@ export const goodDocsCompleted = [ sourceId: cachedValues.docId, detectionDateStart: cachedValues.createdAt, detectionDateEnd: cachedValues.updatedAt, - geometry: {}, + geometry: { + type: 'Point', + coordinates: [100, 101], + }, metadata: {}, }, expected: {}, diff --git a/test/fixtures/good-docs-minimal.js b/test/fixtures/good-docs-minimal.js index 56f0dd7..b12e00a 100644 --- a/test/fixtures/good-docs-minimal.js +++ b/test/fixtures/good-docs-minimal.js @@ -220,7 +220,39 @@ export const goodDocsMinimal = [ sourceId: '', detectionDateStart: cachedValues.createdAt, detectionDateEnd: cachedValues.updatedAt, - geometry: {}, + geometry: { + type: 'Point', + coordinates: [100, 101], + }, + metadata: {}, + }, + expected: {}, + }, + { + doc: { + docId: cachedValues.docId, + versionId: cachedValues.versionId, + originalVersionId: cachedValues.originalVersionId, + schemaName: 'remoteDetectionAlert', + createdAt: cachedValues.createdAt, + updatedAt: cachedValues.updatedAt, + links: [], + deleted: false, + sourceId: '', + detectionDateStart: cachedValues.createdAt, + detectionDateEnd: cachedValues.updatedAt, + geometry: { + type: 'Polygon', + coordinates: [ + [ + [100.0, 0.0], + [101.0, 0.0], + [101.0, 1.0], + [100.0, 1.0], + [100.0, 0.0], + ], + ], + }, metadata: {}, }, expected: {}, From 11fbc82c89437d9dfe2fff2a5700848bb97760fc Mon Sep 17 00:00:00 2001 From: Gregor MacLennan Date: Mon, 9 Sep 2024 09:55:57 +0100 Subject: [PATCH 6/7] rename geometry proto stub --- buf.gen.yaml | 2 +- proto/geometry/{v1.proto => stub.proto} | 0 proto/remoteDetectionAlert/v1.proto | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename proto/geometry/{v1.proto => stub.proto} (100%) diff --git a/buf.gen.yaml b/buf.gen.yaml index 538ddad..08e4ecd 100644 --- a/buf.gen.yaml +++ b/buf.gen.yaml @@ -17,4 +17,4 @@ plugins: - enumsAsLiterals=true # - outputIndex=true - oneof=unions - - Mgeometry/v1.proto=@comapeo/geometry + - Mgeometry/stub.proto=@comapeo/geometry diff --git a/proto/geometry/v1.proto b/proto/geometry/stub.proto similarity index 100% rename from proto/geometry/v1.proto rename to proto/geometry/stub.proto diff --git a/proto/remoteDetectionAlert/v1.proto b/proto/remoteDetectionAlert/v1.proto index 9354a12..795c297 100644 --- a/proto/remoteDetectionAlert/v1.proto +++ b/proto/remoteDetectionAlert/v1.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package mapeo; import "common/v1.proto"; -import "geometry/v1.proto"; +import "geometry/stub.proto"; import "google/protobuf/timestamp.proto"; import "options.proto"; import "tags/v1.proto"; From 3184aa93b625cf7f1db728073a5345266896afde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Ciccola?= Date: Mon, 30 Sep 2024 11:20:09 -0300 Subject: [PATCH 7/7] make detectionDate{Start,End} proto required --- proto/remoteDetectionAlert/v1.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proto/remoteDetectionAlert/v1.proto b/proto/remoteDetectionAlert/v1.proto index 795c297..ee2e440 100644 --- a/proto/remoteDetectionAlert/v1.proto +++ b/proto/remoteDetectionAlert/v1.proto @@ -14,8 +14,8 @@ message RemoteDetectionAlert_1 { Common_1 common = 1; - google.protobuf.Timestamp detectionDateStart = 2; - google.protobuf.Timestamp detectionDateEnd = 3; + google.protobuf.Timestamp detectionDateStart = 2 [(required) = true]; + google.protobuf.Timestamp detectionDateEnd = 3 [(required) = true]; string sourceId = 4; Geometry geometry = 5; map metadata = 6;