diff --git a/drizzle/project/0002_absent_molecule_man.sql b/drizzle/project/0002_absent_molecule_man.sql new file mode 100644 index 00000000..76d89ca3 --- /dev/null +++ b/drizzle/project/0002_absent_molecule_man.sql @@ -0,0 +1 @@ +ALTER TABLE observation ADD `migrationMetadata` text; \ No newline at end of file diff --git a/drizzle/project/meta/0002_snapshot.json b/drizzle/project/meta/0002_snapshot.json new file mode 100644 index 00000000..ba318004 --- /dev/null +++ b/drizzle/project/meta/0002_snapshot.json @@ -0,0 +1,1274 @@ +{ + "version": "5", + "dialect": "sqlite", + "id": "99c15281-e7ee-4015-b53b-4891cce6bdc5", + "prevId": "fd9449b2-3a8e-440e-ba57-62c2db1dc39f", + "tables": { + "coreOwnership_backlink": { + "name": "coreOwnership_backlink", + "columns": { + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "coreOwnership": { + "name": "coreOwnership", + "columns": { + "docId": { + "name": "docId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "originalVersionId": { + "name": "originalVersionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schemaName": { + "name": "schemaName", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "links": { + "name": "links", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted": { + "name": "deleted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "authCoreId": { + "name": "authCoreId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "configCoreId": { + "name": "configCoreId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dataCoreId": { + "name": "dataCoreId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "blobCoreId": { + "name": "blobCoreId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "blobIndexCoreId": { + "name": "blobIndexCoreId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "forks": { + "name": "forks", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "cores": { + "name": "cores", + "columns": { + "publicKey": { + "name": "publicKey", + "type": "blob", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "namespace": { + "name": "namespace", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "deviceInfo_backlink": { + "name": "deviceInfo_backlink", + "columns": { + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "deviceInfo": { + "name": "deviceInfo", + "columns": { + "docId": { + "name": "docId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "originalVersionId": { + "name": "originalVersionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schemaName": { + "name": "schemaName", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "links": { + "name": "links", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted": { + "name": "deleted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deviceType": { + "name": "deviceType", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "selfHostedServerDetails": { + "name": "selfHostedServerDetails", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "forks": { + "name": "forks", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "field_backlink": { + "name": "field_backlink", + "columns": { + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "field": { + "name": "field", + "columns": { + "docId": { + "name": "docId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "originalVersionId": { + "name": "originalVersionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schemaName": { + "name": "schemaName", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "links": { + "name": "links", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted": { + "name": "deleted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "tagKey": { + "name": "tagKey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "appearance": { + "name": "appearance", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "snakeCase": { + "name": "snakeCase", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "universal": { + "name": "universal", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "placeholder": { + "name": "placeholder", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "helperText": { + "name": "helperText", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "forks": { + "name": "forks", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "icon_backlink": { + "name": "icon_backlink", + "columns": { + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "icon": { + "name": "icon", + "columns": { + "docId": { + "name": "docId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "originalVersionId": { + "name": "originalVersionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schemaName": { + "name": "schemaName", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "links": { + "name": "links", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted": { + "name": "deleted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "variants": { + "name": "variants", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "forks": { + "name": "forks", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "observation_backlink": { + "name": "observation_backlink", + "columns": { + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "observation": { + "name": "observation", + "columns": { + "docId": { + "name": "docId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "originalVersionId": { + "name": "originalVersionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schemaName": { + "name": "schemaName", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "links": { + "name": "links", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted": { + "name": "deleted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "lat": { + "name": "lat", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "lon": { + "name": "lon", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "attachments": { + "name": "attachments", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "tags": { + "name": "tags", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "presetRef": { + "name": "presetRef", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "migrationMetadata": { + "name": "migrationMetadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "forks": { + "name": "forks", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "preset_backlink": { + "name": "preset_backlink", + "columns": { + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "preset": { + "name": "preset", + "columns": { + "docId": { + "name": "docId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "originalVersionId": { + "name": "originalVersionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schemaName": { + "name": "schemaName", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "links": { + "name": "links", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted": { + "name": "deleted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "geometry": { + "name": "geometry", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "tags": { + "name": "tags", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "addTags": { + "name": "addTags", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "removeTags": { + "name": "removeTags", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fieldRefs": { + "name": "fieldRefs", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "iconRef": { + "name": "iconRef", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "terms": { + "name": "terms", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "forks": { + "name": "forks", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "remoteDetectionAlert_backlink": { + "name": "remoteDetectionAlert_backlink", + "columns": { + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "remoteDetectionAlert": { + "name": "remoteDetectionAlert", + "columns": { + "docId": { + "name": "docId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "originalVersionId": { + "name": "originalVersionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schemaName": { + "name": "schemaName", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "links": { + "name": "links", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted": { + "name": "deleted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "detectionDateStart": { + "name": "detectionDateStart", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "detectionDateEnd": { + "name": "detectionDateEnd", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sourceId": { + "name": "sourceId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "geometry": { + "name": "geometry", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "forks": { + "name": "forks", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "role_backlink": { + "name": "role_backlink", + "columns": { + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "role": { + "name": "role", + "columns": { + "docId": { + "name": "docId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "originalVersionId": { + "name": "originalVersionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schemaName": { + "name": "schemaName", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "links": { + "name": "links", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted": { + "name": "deleted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "roleId": { + "name": "roleId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fromIndex": { + "name": "fromIndex", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "forks": { + "name": "forks", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "track_backlink": { + "name": "track_backlink", + "columns": { + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "track": { + "name": "track", + "columns": { + "docId": { + "name": "docId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "originalVersionId": { + "name": "originalVersionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schemaName": { + "name": "schemaName", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "links": { + "name": "links", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted": { + "name": "deleted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "locations": { + "name": "locations", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "observationRefs": { + "name": "observationRefs", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "tags": { + "name": "tags", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "forks": { + "name": "forks", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "translation_backlink": { + "name": "translation_backlink", + "columns": { + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "translation": { + "name": "translation", + "columns": { + "docId": { + "name": "docId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "originalVersionId": { + "name": "originalVersionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schemaName": { + "name": "schemaName", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "links": { + "name": "links", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted": { + "name": "deleted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "docRef": { + "name": "docRef", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "docRefType": { + "name": "docRefType", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "propertyRef": { + "name": "propertyRef", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "languageCode": { + "name": "languageCode", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "regionCode": { + "name": "regionCode", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "forks": { + "name": "forks", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/drizzle/project/meta/_journal.json b/drizzle/project/meta/_journal.json index 20711e23..24473635 100644 --- a/drizzle/project/meta/_journal.json +++ b/drizzle/project/meta/_journal.json @@ -15,6 +15,13 @@ "when": 1729783892753, "tag": "0001_medical_wendell_rand", "breakpoints": true + }, + { + "idx": 2, + "version": "5", + "when": 1734465937942, + "tag": "0002_absent_molecule_man", + "breakpoints": true } ] } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index efaa0f51..dd5c7f05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,12 +10,13 @@ "license": "MIT", "dependencies": { "@comapeo/fallback-smp": "^1.0.0", - "@comapeo/schema": "1.3.0", + "@comapeo/schema": "file:../comapeo-schema/comapeo-schema-1.3.0.tgz", "@digidem/types": "^2.3.0", "@fastify/error": "^3.4.1", "@fastify/type-provider-typebox": "^4.1.0", "@hyperswarm/secret-stream": "^6.6.3", "@mapeo/crypto": "1.0.0-alpha.10", + "@mapeo/legacy-export-format": "file:../mapeo-legacy-export-format/mapeo-legacy-export-format-0.2.0.tgz", "@mapeo/sqlite-indexer": "1.0.0-alpha.9", "@sinclair/typebox": "^0.33.17", "@sindresorhus/merge-streams": "^4.0.0", @@ -444,8 +445,8 @@ }, "node_modules/@comapeo/schema": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@comapeo/schema/-/schema-1.3.0.tgz", - "integrity": "sha512-+rDgfKahCbUk5bU6BBcCQ3aMSRJfenkbYET0PdN4sg2c+G3BOELaTI5+s5n+oZQEEOxYXp3UDkT61PlA2nUPQw==", + "resolved": "file:../comapeo-schema/comapeo-schema-1.3.0.tgz", + "integrity": "sha512-Px5kZ8AhPag0YEfai+TVBy5iH/ychSfKfqpSLVEgdgPbHR3eyhSHPhhvEawzE1chkYtg4CKQG5PA1y1Y+bGiBw==", "license": "MIT", "dependencies": { "@comapeo/geometry": "^1.1.0", @@ -947,6 +948,142 @@ "integrity": "sha512-SNUUxN0UI0i/g5XshUKuLY1O3SWClzwgM3qiiBDW3Dw+AcHK+jdONFK6KjvwYK13cwdQadTzIJbEKWmLP+0UWA==", "dev": true }, + "node_modules/@mapeo/legacy-export-format": { + "version": "0.2.0", + "resolved": "file:../mapeo-legacy-export-format/mapeo-legacy-export-format-0.2.0.tgz", + "integrity": "sha512-ETtzK4gbbobHkszET3i7sd/uoTtCogPz8yxJXg2+Es/SpzALopDdw1SptqrfaE7aZcP8ogzBPgd9az0jHUC74w==", + "license": "MIT", + "dependencies": { + "archiver": "^7.0.1", + "hypercore": "^7.7.1", + "hypercore-crypto": "^3.4.2", + "multifeed": "^4.3.0", + "p-event": "^6.0.1", + "valibot": "^1.0.0-beta.9", + "yauzl-promise": "^4.0.0" + }, + "engines": { + "engineStrict": true, + "node": "^18.20.0" + } + }, + "node_modules/@mapeo/legacy-export-format/node_modules/codecs": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/codecs/-/codecs-2.2.0.tgz", + "integrity": "sha512-+xi2ENsvchtUNa8oBUU58gHgmyN6BEEeZ8NIEgeQ0XnC+AoyihivgZYe+OOiNi+fLy/NUowugwV5gP8XWYDm0Q==", + "license": "MIT" + }, + "node_modules/@mapeo/legacy-export-format/node_modules/hypercore": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/hypercore/-/hypercore-7.7.1.tgz", + "integrity": "sha512-boEiPCK848pNGACW1j111tJApu530e/UPpwbHytJZlrVf3YdgUIP1KL3aSi5xJFLUnuO8GLGl4lIsSeH8TaQQA==", + "license": "MIT", + "dependencies": { + "array-lru": "^1.1.0", + "atomic-batcher": "^1.0.2", + "bitfield-rle": "^2.2.1", + "bulk-write-stream": "^1.1.3", + "codecs": "^2.0.0", + "fast-bitfield": "^1.2.2", + "flat-tree": "^1.6.0", + "from2": "^2.3.0", + "hypercore-crypto": "^1.0.0", + "hypercore-protocol": "^6.5.0", + "inherits": "^2.0.3", + "inspect-custom-symbol": "^1.1.0", + "last-one-wins": "^1.0.4", + "memory-pager": "^1.0.2", + "merkle-tree-stream": "^3.0.3", + "nanoguard": "^1.2.0", + "pretty-hash": "^1.0.1", + "random-access-file": "^2.1.0", + "sodium-universal": "^2.0.0", + "sparse-bitfield": "^3.0.0", + "thunky": "^1.0.1", + "uint64be": "^2.0.1", + "unordered-array-remove": "^1.0.2", + "unordered-set": "^2.0.0" + }, + "optionalDependencies": { + "fd-lock": "^1.0.2" + } + }, + "node_modules/@mapeo/legacy-export-format/node_modules/hypercore/node_modules/hypercore-crypto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hypercore-crypto/-/hypercore-crypto-1.0.0.tgz", + "integrity": "sha512-xFwOnNlOt8L+SovC7dTNchKaNYJb5l8rKZZwpWQnCme1r7CU4Hlhp1RDqPES6b0OpS7DkTo9iU0GltQGkpsjMw==", + "license": "MIT", + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-from": "^1.1.0", + "sodium-universal": "^2.0.0", + "uint64be": "^2.0.2" + } + }, + "node_modules/@mapeo/legacy-export-format/node_modules/nanoassert": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-1.1.0.tgz", + "integrity": "sha512-C40jQ3NzfkP53NsO8kEOFd79p4b9kDXQMwgiY1z8ZwrDZgUyom0AHwGegF4Dm99L+YoYhuaB0ceerUcXmqr1rQ==", + "license": "ISC" + }, + "node_modules/@mapeo/legacy-export-format/node_modules/random-access-file": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/random-access-file/-/random-access-file-2.2.1.tgz", + "integrity": "sha512-RGU0xmDqdOyEiynob1KYSeh8+9c9Td1MJ74GT1viMEYAn8SJ9oBtWCXLsYZukCF46yududHOdM449uRYbzBrZQ==", + "license": "MIT", + "dependencies": { + "mkdirp-classic": "^0.5.2", + "random-access-storage": "^1.1.1" + } + }, + "node_modules/@mapeo/legacy-export-format/node_modules/random-access-storage": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/random-access-storage/-/random-access-storage-1.4.3.tgz", + "integrity": "sha512-D5e2iIC5dNENWyBxsjhEnNOMCwZZ64TARK6dyMN+3g4OTC4MJxyjh9hKLjTGoNhDOPrgjI+YlFEHFnrp/cSnzQ==", + "license": "MIT", + "dependencies": { + "events": "^3.3.0", + "inherits": "^2.0.3", + "queue-tick": "^1.0.0" + } + }, + "node_modules/@mapeo/legacy-export-format/node_modules/sodium-javascript": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/sodium-javascript/-/sodium-javascript-0.5.6.tgz", + "integrity": "sha512-Uk+JpqHEbzsEmiMxwL7TB/ndhMEpc52KdReYXXSIX2oRFPaI7ZDlDImF8KbkFWbYl9BJRtc82AZ/kNf4/0n9KA==", + "license": "MIT", + "dependencies": { + "blake2b": "^2.1.1", + "nanoassert": "^1.0.0", + "siphash24": "^1.0.1", + "xsalsa20": "^1.0.0" + } + }, + "node_modules/@mapeo/legacy-export-format/node_modules/sodium-native": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-2.4.9.tgz", + "integrity": "sha512-mbkiyA2clyfwAyOFIzMvsV6ny2KrKEIhFVASJxWfsmgfUEymgLIS2MLHHcGIQMkrcKhPErRaMR5Dzv0EEn+BWg==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ini": "^1.3.5", + "nan": "^2.14.0", + "node-gyp-build": "^4.1.0" + } + }, + "node_modules/@mapeo/legacy-export-format/node_modules/sodium-universal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sodium-universal/-/sodium-universal-2.0.0.tgz", + "integrity": "sha512-csdVyakzHJRyCevY4aZC2Eacda8paf+4nmRGF2N7KxCLKY2Ajn72JsExaQlJQ2BiXJncp44p3T+b80cU+2TTsg==", + "license": "MIT", + "dependencies": { + "sodium-javascript": "~0.5.0" + }, + "optionalDependencies": { + "sodium-native": "^2.0.0" + } + }, "node_modules/@mapeo/mock-data": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@mapeo/mock-data/-/mock-data-2.1.1.tgz", @@ -1859,6 +1996,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array-lru": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-lru/-/array-lru-1.1.1.tgz", + "integrity": "sha512-DgyrnKyaWLX2YfWtjGcLXJU2/MAf2iYL8kgszqkfgnZvTW3iXfSohkP/ExAVgHRVWDwzdblCF/7Mpl51jUcyxQ==", + "license": "MIT" + }, "node_modules/arraybuffer.prototype.slice": { "version": "1.0.1", "dev": true, @@ -1891,6 +2034,12 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" }, + "node_modules/atomic-batcher": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/atomic-batcher/-/atomic-batcher-1.0.2.tgz", + "integrity": "sha512-EFGCRj4kLX1dHv1cDzTk+xbjBFj1GnJDpui52YmEcxxHHEWjYyT6l51U7n6WQ28osZH4S9gSybxe56Vm7vB61Q==", + "license": "MIT" + }, "node_modules/atomic-sleep": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", @@ -2057,6 +2206,22 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/bitfield-rle": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bitfield-rle/-/bitfield-rle-2.2.1.tgz", + "integrity": "sha512-wrDhHe7LUkqaytxgbsFXoemzHRv6e8FrVNWWsQCgUfmuVYW6ke44hoGc9VdpjgfIsJ/ejmCFA8wDtDqACNAvyw==", + "license": "MIT", + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "varint": "^4.0.0" + } + }, + "node_modules/bitfield-rle/node_modules/varint": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/varint/-/varint-4.0.1.tgz", + "integrity": "sha512-vu4cpCqZHA4u77jWdOZlXtXHJofIIyq51DtzstbrvI9e1I1ELseAJLxYr47N/DdLPFGfYMLY1HqAURSTKKJ6ww==", + "license": "MIT" + }, "node_modules/bl": { "version": "4.1.0", "license": "MIT", @@ -2069,8 +2234,6 @@ "node_modules/blake2b": { "version": "2.1.4", "license": "ISC", - "optional": true, - "peer": true, "dependencies": { "blake2b-wasm": "^2.4.0", "nanoassert": "^2.0.0" @@ -2079,8 +2242,6 @@ "node_modules/blake2b-wasm": { "version": "2.4.0", "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "b4a": "^1.0.1", "nanoassert": "^2.0.0" @@ -2137,6 +2298,22 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "license": "MIT", + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "node_modules/buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "license": "MIT" + }, "node_modules/buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", @@ -2146,9 +2323,14 @@ "node": "*" } }, + "node_modules/buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", + "license": "MIT" + }, "node_modules/buffer-from": { "version": "1.1.2", - "dev": true, "license": "MIT" }, "node_modules/buffer-peek-stream": { @@ -2156,6 +2338,53 @@ "resolved": "https://registry.npmjs.org/buffer-peek-stream/-/buffer-peek-stream-1.1.0.tgz", "integrity": "sha512-b3MXlJ52rPOL5xCAQsiCOy/tY9WXOP/hwATporJriUDxnT3MjJgVppDzTFegpg2Nw7NMS28MKC6IKvaXLnGr+Q==" }, + "node_modules/bulk-write-stream": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bulk-write-stream/-/bulk-write-stream-1.1.4.tgz", + "integrity": "sha512-GtKwd/4etuk1hNeprXoESBO1RSeRYJMXKf+O0qHmWdUomLT8ysNEfX/4bZFXr3BK6eukpHiEnhY2uMtEHDM2ng==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.1.4" + } + }, + "node_modules/bulk-write-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/bulk-write-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/bulk-write-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/bulk-write-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/bundle-name": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", @@ -2684,6 +2913,12 @@ "xache": "^1.1.0" } }, + "node_modules/count-trailing-zeros": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/count-trailing-zeros/-/count-trailing-zeros-1.0.1.tgz", + "integrity": "sha512-ZnX7MMZDpu7R1aMwQRe0P1RGvfnXHibhTE+Oe/BHOCAZ/Mrp0Nv8VwaZ3G5cfFHMl5RrZ9s3HxnYoaVNB2gzgA==", + "license": "MIT" + }, "node_modules/cp-file": { "version": "10.0.0", "dev": true, @@ -3996,6 +4231,15 @@ "node": ">=0.10.0" } }, + "node_modules/fast-bitfield": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/fast-bitfield/-/fast-bitfield-1.2.2.tgz", + "integrity": "sha512-t8HYqkuE3YEqNcyWlAfh55479aTxO+GpYwvQvJppYqyBfSmRdNIhzY2m09FKN/MENTzq4wH6heHOIvsPyMAwvQ==", + "license": "MIT", + "dependencies": { + "count-trailing-zeros": "^1.0.1" + } + }, "node_modules/fast-content-type-parse": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz", @@ -4211,6 +4455,18 @@ "reusify": "^1.0.4" } }, + "node_modules/fd-lock": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fd-lock/-/fd-lock-1.2.0.tgz", + "integrity": "sha512-Lk/pKH2DldLpG4Yh/sOOY84k5VqNzxHPffGwf1+yYI+/qMXzTPp9KJMX+Wh6n4xqGSA1Mu7JPmaDArfJGw2O/A==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "napi-macros": "^2.0.0", + "node-gyp-build": "^4.2.2" + } + }, "node_modules/figures": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", @@ -4393,6 +4649,52 @@ "node": ">= 0.6" } }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/from2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/from2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/from2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/from2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "license": "MIT" @@ -4942,6 +5244,107 @@ "version": "1.0.0", "license": "Apache-2.0" }, + "node_modules/hypercore-protocol": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/hypercore-protocol/-/hypercore-protocol-6.12.0.tgz", + "integrity": "sha512-T3oy9/7QFejqJX2RGcCUU1944e5/eKbLlSz9JPTNN1QbYFJgat/r7eTyOO8SMSLUimUmQx6YBMKhgYbdKzp7Bw==", + "license": "MIT", + "dependencies": { + "buffer-alloc-unsafe": "^1.0.0", + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "protocol-buffers-encodings": "^1.1.0", + "readable-stream": "^2.2.6", + "sodium-universal": "^2.0.0", + "sorted-indexof": "^1.0.0", + "varint": "^5.0.0" + } + }, + "node_modules/hypercore-protocol/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/hypercore-protocol/node_modules/nanoassert": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-1.1.0.tgz", + "integrity": "sha512-C40jQ3NzfkP53NsO8kEOFd79p4b9kDXQMwgiY1z8ZwrDZgUyom0AHwGegF4Dm99L+YoYhuaB0ceerUcXmqr1rQ==", + "license": "ISC" + }, + "node_modules/hypercore-protocol/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hypercore-protocol/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/hypercore-protocol/node_modules/sodium-javascript": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/sodium-javascript/-/sodium-javascript-0.5.6.tgz", + "integrity": "sha512-Uk+JpqHEbzsEmiMxwL7TB/ndhMEpc52KdReYXXSIX2oRFPaI7ZDlDImF8KbkFWbYl9BJRtc82AZ/kNf4/0n9KA==", + "license": "MIT", + "dependencies": { + "blake2b": "^2.1.1", + "nanoassert": "^1.0.0", + "siphash24": "^1.0.1", + "xsalsa20": "^1.0.0" + } + }, + "node_modules/hypercore-protocol/node_modules/sodium-native": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-2.4.9.tgz", + "integrity": "sha512-mbkiyA2clyfwAyOFIzMvsV6ny2KrKEIhFVASJxWfsmgfUEymgLIS2MLHHcGIQMkrcKhPErRaMR5Dzv0EEn+BWg==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ini": "^1.3.5", + "nan": "^2.14.0", + "node-gyp-build": "^4.1.0" + } + }, + "node_modules/hypercore-protocol/node_modules/sodium-universal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sodium-universal/-/sodium-universal-2.0.0.tgz", + "integrity": "sha512-csdVyakzHJRyCevY4aZC2Eacda8paf+4nmRGF2N7KxCLKY2Ajn72JsExaQlJQ2BiXJncp44p3T+b80cU+2TTsg==", + "license": "MIT", + "dependencies": { + "sodium-javascript": "~0.5.0" + }, + "optionalDependencies": { + "sodium-native": "^2.0.0" + } + }, + "node_modules/hypercore-protocol/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/hypercore-protocol/node_modules/varint": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==", + "license": "MIT" + }, "node_modules/hyperdrive": { "version": "11.5.3", "license": "Apache-2.0", @@ -5036,6 +5439,12 @@ "version": "1.3.8", "license": "ISC" }, + "node_modules/inspect-custom-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/inspect-custom-symbol/-/inspect-custom-symbol-1.1.1.tgz", + "integrity": "sha512-GOucsp9EcdlLdhPUyOTvQDnbFJtp2WBWZV1Jqe+mVnkJQBL3w96+fB84C+JL+EKXOspMdB0eMDQPDp5w9fkfZA==", + "license": "MIT" + }, "node_modules/internal-slot": { "version": "1.0.5", "dev": true, @@ -5670,6 +6079,12 @@ "url": "https://github.com/sindresorhus/ky?sponsor=1" } }, + "node_modules/last-one-wins": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/last-one-wins/-/last-one-wins-1.0.4.tgz", + "integrity": "sha512-t+KLJFkHPQk8lfN6WBOiGkiUXoub+gnb2XTYI2P3aiISL+94xgZ1vgz1SXN/N4hthuOoLXarXfBZPUruyjQtfA==", + "license": "MIT" + }, "node_modules/lazystream": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", @@ -6328,6 +6743,12 @@ "timers-ext": "^0.1.7" } }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "license": "MIT" + }, "node_modules/memorystream": { "version": "0.3.1", "dev": true, @@ -6394,6 +6815,52 @@ "node": ">= 8" } }, + "node_modules/merkle-tree-stream": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/merkle-tree-stream/-/merkle-tree-stream-3.0.3.tgz", + "integrity": "sha512-cylD/HcPXjeSVEPj4menLP0mndi6gvqmTlDq3QF4Vptn1tgc6ilgK7rdcAUA4X3RTkymXRwLuZpNncIfq1q1AA==", + "license": "MIT", + "dependencies": { + "flat-tree": "^1.3.0", + "readable-stream": "^2.0.5" + } + }, + "node_modules/merkle-tree-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/merkle-tree-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/merkle-tree-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/merkle-tree-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/micromark-util-character": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", @@ -6651,6 +7118,64 @@ "tiny-typed-emitter": "^2.1.0" } }, + "node_modules/multifeed": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/multifeed/-/multifeed-4.3.0.tgz", + "integrity": "sha512-7RLBHilfBA9FTdTw98YbFv/UEg/44dIEefLRn/ALDnB1MMjB7gxGcgXqE01AH63oW8/uS30mndoFCBx/GyC7fg==", + "license": "ISC", + "dependencies": { + "debug": "^4.1.0", + "hypercore-protocol": "^6.8.0", + "inherits": "^2.0.3", + "mutexify": "^1.2.0", + "once": "^1.4.0", + "random-access-file": "^2.0.1", + "random-access-memory": "^3.1.1", + "through2": "^3.0.0" + } + }, + "node_modules/multifeed/node_modules/random-access-file": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/random-access-file/-/random-access-file-2.2.1.tgz", + "integrity": "sha512-RGU0xmDqdOyEiynob1KYSeh8+9c9Td1MJ74GT1viMEYAn8SJ9oBtWCXLsYZukCF46yududHOdM449uRYbzBrZQ==", + "license": "MIT", + "dependencies": { + "mkdirp-classic": "^0.5.2", + "random-access-storage": "^1.1.1" + } + }, + "node_modules/multifeed/node_modules/random-access-memory": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/random-access-memory/-/random-access-memory-3.1.4.tgz", + "integrity": "sha512-rqgqd/8ec65gbpKaYHnDOW391OR39d+eXn8NI87G+f3sUKrtGib9jC+/5/9MBFBwwHAZIS8RLJ8yyB4etzbYTA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-options": "^1.0.1", + "random-access-storage": "^1.1.1" + } + }, + "node_modules/multifeed/node_modules/random-access-storage": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/random-access-storage/-/random-access-storage-1.4.3.tgz", + "integrity": "sha512-D5e2iIC5dNENWyBxsjhEnNOMCwZZ64TARK6dyMN+3g4OTC4MJxyjh9hKLjTGoNhDOPrgjI+YlFEHFnrp/cSnzQ==", + "license": "MIT", + "dependencies": { + "events": "^3.3.0", + "inherits": "^2.0.3", + "queue-tick": "^1.0.0" + } + }, + "node_modules/multifeed/node_modules/through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } + }, "node_modules/mutexify": { "version": "1.4.0", "license": "MIT", @@ -6658,6 +7183,13 @@ "queue-tick": "^1.0.0" } }, + "node_modules/nan": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz", + "integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==", + "license": "MIT", + "optional": true + }, "node_modules/nanoassert": { "version": "2.0.0", "license": "ISC" @@ -6688,6 +7220,12 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/nanoguard": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/nanoguard/-/nanoguard-1.3.0.tgz", + "integrity": "sha512-K/ON5wyflyPyZskdeT3m7Y2gJVkm3QLdKykMCquAbK8A2erstyMpZUc3NG8Nz5jKdfatiYndONrlmLF8+pGl+A==", + "license": "MIT" + }, "node_modules/napi-build-utils": { "version": "1.0.2", "license": "MIT" @@ -7686,6 +8224,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pretty-hash": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pretty-hash/-/pretty-hash-1.0.1.tgz", + "integrity": "sha512-2jybsj3Vz6wLSyOtlRWgbUmQ/K4ROta4iR4voYeC3tgJekeWTn9NcwTVFlhqVVPB2qvVOtLTvUF6yMtG3SUIZA==", + "license": "MIT" + }, "node_modules/pretty-hrtime": { "version": "1.0.3", "dev": true, @@ -8792,8 +9336,6 @@ "node_modules/siphash24": { "version": "1.3.1", "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "nanoassert": "^2.0.0" } @@ -8942,6 +9484,12 @@ "node": ">=0.10.0" } }, + "node_modules/sorted-indexof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/sorted-indexof/-/sorted-indexof-1.0.0.tgz", + "integrity": "sha512-N9bptDwgg6V4b9DexkX1Zmj2raV4jRPdVfE3Tri8DvtocNhdl52z+eekD/8mlFDMe9G0uqd95U5YFjHQuA1tGA==", + "license": "MIT" + }, "node_modules/source-map": { "version": "0.6.1", "dev": true, @@ -8969,6 +9517,15 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, "node_modules/spdx-correct": { "version": "3.2.0", "dev": true, @@ -9555,6 +10112,12 @@ "readable-stream": "3" } }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "license": "MIT" + }, "node_modules/timeout-refresh": { "version": "2.0.1", "license": "MIT" @@ -9854,7 +10417,7 @@ "version": "5.6.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", - "dev": true, + "devOptional": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9882,6 +10445,15 @@ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", "dev": true }, + "node_modules/uint64be": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uint64be/-/uint64be-2.0.2.tgz", + "integrity": "sha512-9QqdvpGQTXgxthP+lY4e/gIBy+RuqcBaC6JVwT5I3bDLgT/btL6twZMR0pI3/Fgah9G/pdwzIprE5gL6v9UvyQ==", + "license": "MIT", + "dependencies": { + "buffer-alloc": "^1.1.0" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "dev": true, @@ -10022,6 +10594,18 @@ "version": "1.0.2", "license": "MIT" }, + "node_modules/unordered-array-remove": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unordered-array-remove/-/unordered-array-remove-1.0.2.tgz", + "integrity": "sha512-45YsfD6svkgaCBNyvD+dFHm4qFX9g3wRSIVgWVPtm2OCnphvPxzJoe20ATsiNpNJrmzHifnxm+BN5F7gFT/4gw==", + "license": "MIT" + }, + "node_modules/unordered-set": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz", + "integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==", + "license": "MIT" + }, "node_modules/uri-js": { "version": "4.4.1", "license": "BSD-2-Clause", @@ -10033,6 +10617,20 @@ "version": "1.0.2", "license": "MIT" }, + "node_modules/valibot": { + "version": "1.0.0-beta.9", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.0.0-beta.9.tgz", + "integrity": "sha512-yEX8gMAZ2R1yI2uwOO4NCtVnJQx36zn3vD0omzzj9FhcoblvPukENIiRZXKZwCnqSeV80bMm8wNiGhQ0S8fiww==", + "license": "MIT", + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "dev": true, @@ -10216,9 +10814,7 @@ }, "node_modules/xsalsa20": { "version": "1.2.0", - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/yallist": { "version": "4.0.0", diff --git a/package.json b/package.json index 8230fbc8..fa23c3e2 100644 --- a/package.json +++ b/package.json @@ -159,12 +159,13 @@ }, "dependencies": { "@comapeo/fallback-smp": "^1.0.0", - "@comapeo/schema": "1.3.0", + "@comapeo/schema": "file:../comapeo-schema/comapeo-schema-1.3.0.tgz", "@digidem/types": "^2.3.0", "@fastify/error": "^3.4.1", "@fastify/type-provider-typebox": "^4.1.0", "@hyperswarm/secret-stream": "^6.6.3", "@mapeo/crypto": "1.0.0-alpha.10", + "@mapeo/legacy-export-format": "file:../mapeo-legacy-export-format/mapeo-legacy-export-format-0.2.0.tgz", "@mapeo/sqlite-indexer": "1.0.0-alpha.9", "@sinclair/typebox": "^0.33.17", "@sindresorhus/merge-streams": "^4.0.0", diff --git a/src/import-legacy-mapeo-data.js b/src/import-legacy-mapeo-data.js new file mode 100644 index 00000000..ff732f20 --- /dev/null +++ b/src/import-legacy-mapeo-data.js @@ -0,0 +1,309 @@ +import * as mlef from '@mapeo/legacy-export-format' +import * as fs from 'node:fs/promises' +import pProps from 'p-props' +import { temporaryWrite } from 'tempy' +import { Type as T } from '@sinclair/typebox' +import { Value } from '@sinclair/typebox/value' +import { deNullify } from './utils.js' +/** @import { MapeoProject } from './mapeo-project.js' */ +/** @import { Observation, ObservationValue } from '@comapeo/schema' */ +/** @import { Document, DocumentVersion } from '@mapeo/legacy-export-format' */ + +/** + * @internal + * @typedef {object} ParsedOldObservation + * @prop {string} version + * @prop {string[]} links + * @prop {ObservationValue} value + * @prop {OldAttachment[]} attachments + */ + +/** + * @internal + * @typedef {object} OldAttachment + * @prop {string} id + * @prop {string} type + * @prop {Record} variants + */ + +const OldPositionSchema = T.Object({ + coords: T.Object({ + latitude: T.Number(), + longitude: T.Number(), + altitude: T.Union([T.Null(), T.Number()]), + accuracy: T.Union([T.Null(), T.Number()]), + altitudeAccuracy: T.Union([T.Null(), T.Number()]), + heading: T.Union([T.Null(), T.Number()]), + speed: T.Union([T.Null(), T.Number()]), + }), + timestamp: T.Number(), +}) + +const OldProviderSchema = T.Object({ + backgroundModeEnabled: T.Boolean(), + gpsAvailable: T.Optional(T.Boolean()), + passiveAvailable: T.Optional(T.Boolean()), + locationServicesEnabled: T.Boolean(), + networkAvailable: T.Optional(T.Boolean()), +}) + +const OldTagsSchema = T.Record( + T.String(), + T.Union([ + T.Boolean(), + T.Number(), + T.String(), + T.Null(), + T.Array(T.Union([T.Boolean(), T.Number(), T.String(), T.Null()])), + ]) +) + +// Lifted from +// with unnecessary fields removed. +const OldDocumentSchema = T.Object({ + attachments: T.Optional( + T.Array( + T.Object({ + id: T.String(), + type: T.Optional(T.String()), + }) + ) + ), + lat: T.Optional(T.Union([T.Null(), T.Undefined(), T.Number()])), + links: T.Optional(T.Union([T.Null(), T.Undefined(), T.Array(T.String())])), + lon: T.Optional(T.Union([T.Null(), T.Undefined(), T.Number()])), + metadata: T.Optional( + T.Object({ + location: T.Optional( + T.Object({ + position: T.Optional(OldPositionSchema), + provider: T.Optional(OldProviderSchema), + }) + ), + manualLocation: T.Optional(T.Boolean()), + }) + ), + schemaVersion: T.Literal(3), + tags: T.Optional(OldTagsSchema), + type: T.Literal('observation'), +}) + +/** + * @param {Awaited>} reader + * @param {DocumentVersion} documentVersion + * @returns {Promise} + */ +async function parseOldObservation(reader, documentVersion) { + const oldDocument = documentVersion.document + + if (!Value.Check(OldDocumentSchema, oldDocument)) return null + + const links = oldDocument.links || [] + + const oldMetadataLocation = oldDocument.metadata?.location + const oldMetadataPosition = oldMetadataLocation?.position + const oldMetadataProvider = oldMetadataLocation?.provider + + /** @type {NonNullable} */ + const metadata = { + manualLocation: oldDocument.metadata?.manualLocation, + position: oldMetadataPosition + ? { + timestamp: new Date(oldMetadataPosition.timestamp).toISOString(), + coords: deNullify(oldMetadataPosition.coords), + } + : undefined, + positionProvider: oldMetadataProvider, + } + const hasAnyMetadata = Object.values(metadata).some( + (value) => value !== undefined && value !== null + ) + + /** @type {ObservationValue} */ + const value = { + schemaName: 'observation', + attachments: [], + tags: oldDocument.tags || {}, + lat: oldDocument.lat ?? undefined, + lon: oldDocument.lon ?? undefined, + metadata: hasAnyMetadata ? metadata : undefined, + migrationMetadata: { + originalDocument: Buffer.from( + JSON.stringify(oldDocument), + 'utf8' + ).toString('hex'), + hypercore: documentVersion.hypercoreMetadata, + }, + } + + const attachments = await Promise.all( + (oldDocument.attachments || []).map(async (attachment) => { + /** @type {OldAttachment} */ + const result = { + id: attachment.id, + type: attachment.type || 'image/jpeg', + variants: {}, + } + for await (const media of reader.getMediaById(attachment.id)) { + result.variants[media.variant] = media.data + } + return result + }) + ) + + return { version: documentVersion.version, links, value, attachments } +} + +/** + * @param {object} options + * @param {MapeoProject} options.project + * @param {OldAttachment} options.oldAttachment + * @returns {Promise} + */ +async function createAttachment({ project, oldAttachment }) { + const originalData = oldAttachment.variants.original + if (!originalData) return null + + /** @type {string[]} */ + const pathsToCleanUp = [] + + /** + * @param {Uint8Array} data + * @returns {Promise} + */ + const writeToTemporaryFile = async (data) => { + const result = await temporaryWrite(data) + pathsToCleanUp.push(result) + return result + } + + const result = await project.$blobs.create( + await pProps({ + original: writeToTemporaryFile(originalData), + preview: + oldAttachment.variants.preview && + writeToTemporaryFile(oldAttachment.variants.preview), + thumbnail: + oldAttachment.variants.thumbnail && + writeToTemporaryFile(oldAttachment.variants.thumbnail), + }), + { + mimeType: oldAttachment.type, + timestamp: Date.now(), + } + ) + + await Promise.all( + pathsToCleanUp.map((path) => fs.rm(path, { maxRetries: 2 })) + ) + + return { + driveDiscoveryId: result.driveId, + ...result, + } +} + +/** + * @param {object} options + * @param {MapeoProject} options.project + * @param {Awaited>} options.reader + * @param {Document} options.document + * @returns {Promise} + */ +async function importObservation({ project, reader, document }) { + /** @type {Map} */ + const attachmentsCreated = new Map() + + /** @type {Map} */ + const oldVersionToNewVersion = new Map() + + /** + * @param {string[]} oldLinks + * @returns {null | string[]} + */ + const getNewVersions = (oldLinks) => { + /** @type {string[]} */ const result = [] + for (const oldLink of oldLinks) { + const newLink = oldVersionToNewVersion.get(oldLink) + if (!newLink) return null + result.push(newLink) + } + return result + } + + /** @type {ParsedOldObservation[]} */ + let remainingVersions = [] + await Promise.all( + document.versions.map(async (documentVersion) => { + const parsedOldObservation = await parseOldObservation( + reader, + documentVersion + ) + if (parsedOldObservation) { + remainingVersions.push(parsedOldObservation) + } + }) + ) + + while (remainingVersions.length) { + /** @type {Set} */ + const oldVersionsMigrated = new Set() + + for (const oldVersion of remainingVersions) { + const { version, links, value, attachments } = oldVersion + + const linksToUpdate = getNewVersions(links) + if (!linksToUpdate) continue + + /** @type {ObservationValue['attachments']} */ + const newAttachments = [] + await Promise.all( + attachments.map(async (oldAttachment) => { + const existingAttachment = attachmentsCreated.get(oldAttachment.id) + if (existingAttachment) return existingAttachment + const attachment = await createAttachment({ project, oldAttachment }) + if (attachment) { + newAttachments.push(attachment) + attachmentsCreated.set(oldAttachment.id, attachment) + } + return attachment + }) + ) + + const toCreateOrUpdate = { ...value, attachments: newAttachments } + + /** @type {Observation} */ + let observation + if (linksToUpdate.length) { + observation = await project.observation.update( + linksToUpdate, + toCreateOrUpdate + ) + } else { + observation = await project.observation.create(toCreateOrUpdate) + } + + oldVersionToNewVersion.set(version, observation.versionId) + oldVersionsMigrated.add(version) + } + + if (!oldVersionsMigrated.size) { + throw new Error('No versions migrated. Do documents have proper links?') + } + remainingVersions = remainingVersions.filter( + (version) => !oldVersionsMigrated.has(version.version) + ) + } +} + +/** + * @param {MapeoProject} project + * @param {string} mlefPath + * @returns {Promise} + */ +export async function importLegacyMapeoData(project, mlefPath) { + const reader = await mlef.reader(mlefPath) + for await (const document of reader.documents()) { + await importObservation({ project, reader, document }) + } +} diff --git a/src/mapeo-project.js b/src/mapeo-project.js index f81e386f..cd5d63cd 100644 --- a/src/mapeo-project.js +++ b/src/mapeo-project.js @@ -57,6 +57,7 @@ import { } from './sync/sync-api.js' import { Logger } from './logger.js' import { IconApi } from './icon-api.js' +import { importLegacyMapeoData } from './import-legacy-mapeo-data.js' import { readConfig } from './config-import.js' import TranslationApi from './translation-api.js' import { NotFoundError, nullIfNotFound } from './errors.js' @@ -1053,6 +1054,14 @@ export class MapeoProject extends TypedEmitter { return /** @type Error[] */ [] } } + + /** + * @param {string} mlefPath + * @returns {Promise} + */ + $importLegacyMapeoData(mlefPath) { + return importLegacyMapeoData(this, mlefPath) + } } /** diff --git a/test-e2e/cross-version-sync.js b/test-e2e/cross-version-sync.js index 0646dc6b..28952915 100644 --- a/test-e2e/cross-version-sync.js +++ b/test-e2e/cross-version-sync.js @@ -38,6 +38,7 @@ test('syncing @comapeo/core@2.0.1 with the current version', async (t) => { ) const projectId = await oldManager.createProject({ name: 'foo bar' }) + const oldProject = await oldManager.getProject(projectId) await invite({ projectId, @@ -45,28 +46,23 @@ test('syncing @comapeo/core@2.0.1 with the current version', async (t) => { invitees: [newManager], }) - const projects = await Promise.all( - managers.map((manager) => manager.getProject(projectId)) - ) - const [oldProject, newProject] = projects + const newProject = await newManager.getProject(projectId) + assert.equal( (await newProject.$getProjectSettings()).name, 'foo bar', 'new manager sees the project' ) - oldProject.$sync.start() - newProject.$sync.start() + const [oldObservation, newObservation] = await Promise.all([ + oldProject.observation.create(generateObservationThatWorksInOldVersion()), + newProject.observation.create(valueOf(generate('observation')[0])), + ]) - const [oldObservation, newObservation] = await Promise.all( - projects.map((project) => - project.observation.create(valueOf(generate('observation')[0])) - ) - ) - - await Promise.all( - projects.map((project) => project.$sync.waitForSync('full')) - ) + await Promise.all([ + oldProject.$sync.waitForSync('full'), + newProject.$sync.waitForSync('full'), + ]) assert( await oldProject.observation.getByDocId(newObservation.docId), @@ -77,3 +73,30 @@ test('syncing @comapeo/core@2.0.1 with the current version', async (t) => { 'new project gets observation from old project' ) }) + +function generateObservationThatWorksInOldVersion() { + const observation = generate('observation')[0] + return pick(observation, [ + 'schemaName', + 'lat', + 'lon', + 'attachments', + 'tags', + 'metadata', + 'presetRef', + ]) +} + +/** + * @template T + * @template {keyof T} K + * @param {T} obj + * @param {ReadonlyArray} keys + * @returns {Pick} + */ +function pick(obj, keys) { + /** @type {Partial} */ + const result = {} + for (const key of keys) result[key] = obj[key] + return /** @type {Pick} */ (result) +} diff --git a/test-e2e/import-legacy-mapeo-data.js b/test-e2e/import-legacy-mapeo-data.js new file mode 100644 index 00000000..14fc1589 --- /dev/null +++ b/test-e2e/import-legacy-mapeo-data.js @@ -0,0 +1,184 @@ +import Fastify from 'fastify' +import assert from 'node:assert/strict' +import test from 'node:test' +import { fileURLToPath } from 'node:url' +import { request } from 'undici' +import { createManager } from './utils.js' + +const FIXTURE_PATH = fileURLToPath( + new URL('../test/fixtures/legacy-mapeo-data.mlef', import.meta.url) +) + +/** + * @param {Array} a + * @param {Array} b + * @returns {boolean} + */ +const arraysMatch = (a, b) => + a.length === b.length && + a.every((value, index) => valuesMatch(value, b[index])) + +/** + * @param {unknown} value + * @returns {value is Record} + */ +const isRecord = (value) => + typeof value === 'object' && value !== null && !Array.isArray(value) + +/** + * @param {unknown} a + * @param {unknown} b + * @returns {boolean} + */ +const valuesMatch = (a, b) => + a === b || + (Array.isArray(a) && Array.isArray(b) && arraysMatch(a, b)) || + (isRecord(a) && isRecord(b) && objectsMatch(a, b)) + +/** + * @param {Record} a + * @param {Record} b + * @returns {boolean} + */ +const objectsMatch = (a, b) => + Object.entries(b).every(([key, bValue]) => valuesMatch(a[key], bValue)) + +test('imports legacy Mapeo data', async (t) => { + const fastify = Fastify() + const mapeoManager = createManager('test', t, { fastify }) + + await fastify.listen() + t.after(() => fastify.close()) + + const projectId = await mapeoManager.createProject({ name: 'test project' }) + const project = await mapeoManager.getProject(projectId) + t.after(() => project.close()) + + await project.$importLegacyMapeoData(FIXTURE_PATH) + + const observations = await project.observation.getMany() + + assert.strictEqual( + observations.length, + 4, + 'expected 4 observations to be imported' + ) + + for (const observation of observations) { + assert( + observation.migrationMetadata?.originalDocument, + 'expected original doc to be saved' + ) + assert( + observation.migrationMetadata?.hypercore, + 'expected hypercore data be saved' + ) + } + + const observationWithAttachments = observations.find((observation) => + objectsMatch(observation, { + lat: -34.5819587, + lon: -58.5067392, + tags: { + place: 'village', + categoryId: 'community', + }, + metadata: { + position: { + timestamp: new Date(1718823274077).toISOString(), + coords: { + altitude: 34.4, + heading: 0, + altitudeAccuracy: 20.899999618530273, + latitude: -34.5819587, + speed: 0.001650038524530828, + longitude: -58.5067392, + accuracy: 3.9000000953674316, + }, + }, + positionProvider: { + gpsAvailable: true, + passiveAvailable: true, + locationServicesEnabled: true, + networkAvailable: true, + }, + }, + }) + ) + assert(observationWithAttachments, 'expected village observation to be found') + assert.equal( + observationWithAttachments.attachments.length, + 1, + 'expected 1 attachment' + ) + const [attachment] = observationWithAttachments.attachments + assert(attachment) + const attachmentUrl = await project.$blobs.getUrl({ + ...attachment, + driveId: attachment.driveDiscoveryId, + type: 'photo', + variant: 'original', + }) + const attachmentResponse = await request(attachmentUrl, { reset: true }) + assert.equal(attachmentResponse.statusCode, 200) + + const versionedObservation = observations.find((observation) => + objectsMatch(observation, { + lon: -58.5067235, + lat: -34.5819385, + attachments: [], + tags: { + type: 'craft', + craft: 'clay', + categoryId: 'clay', + notes: 'Nada de verdas posta, pero esta vez de verdas', + }, + metadata: { + position: { + timestamp: new Date(1718822620160).toISOString(), + coords: { + altitude: 42.80000305175781, + heading: 220.94805908203125, + altitudeAccuracy: 2.857691764831543, + latitude: -34.5819385, + speed: 0.4037386178970337, + longitude: -58.5067235, + accuracy: 5.980000019073486, + }, + }, + positionProvider: { + gpsAvailable: true, + passiveAvailable: true, + locationServicesEnabled: true, + networkAvailable: true, + }, + }, + }) + ) + assert(versionedObservation, 'expected versioned observation to be found') + + assert.equal( + versionedObservation.links.length, + 1, + 'expected versioned observation to have 1 parent' + ) + const [previousVersionId1] = versionedObservation.links + assert(previousVersionId1) + const previousVersion1 = await project.observation.getByVersionId( + previousVersionId1 + ) + assert.equal(previousVersion1.tags.notes, 'Nada de verdas posta') + + assert.equal( + previousVersion1.links.length, + 1, + 'expected versioned observation to have 1 grandparent' + ) + const [previousVersionId2] = previousVersion1.links + assert(previousVersionId2) + const previousVersion2 = await project.observation.getByVersionId( + previousVersionId2 + ) + assert.equal(previousVersion2.tags.notes, 'Nada') + assert.equal(previousVersion2.links.length, 0, 'has no great-grandparents') +}) diff --git a/test-e2e/ipc-basic.js b/test-e2e/ipc-basic.js index 2407ad1e..18263e65 100644 --- a/test-e2e/ipc-basic.js +++ b/test-e2e/ipc-basic.js @@ -1,8 +1,9 @@ import test from 'node:test' import assert from 'node:assert/strict' -import { createIpcManager } from './utils.js' -import { valueOf } from '@comapeo/schema' -import { generate } from '@mapeo/mock-data' +import { + createIpcManager, + generateObservationThatWorksInOldVersion, +} from './utils.js' test('basic functionality of a manager in a separate process', async (t) => { const manager = await createIpcManager('manager', t) @@ -12,7 +13,12 @@ test('basic functionality of a manager in a separate process', async (t) => { const project = await manager.getProject(projectId) const { docId } = await project.observation.create( - valueOf(generate('observation')[0]) + // We need to do this to satisfy TypeScript. + // + // Though `@comapeo/ipc`, used by this test, depends on the development + // version of `@comapeo/core` in this repo, the types do not. That means + // we can't use new observation fields in this test. + generateObservationThatWorksInOldVersion() ) assert( diff --git a/test-e2e/utils.js b/test-e2e/utils.js index aac0c73e..2ef51262 100644 --- a/test-e2e/utils.js +++ b/test-e2e/utils.js @@ -614,6 +614,31 @@ async function seedProjectDatabase( return Promise.all(promises) } +export const generateObservationThatWorksInOldVersion = () => + pick(generate('observation')[0], [ + 'schemaName', + 'lat', + 'lon', + 'attachments', + 'tags', + 'metadata', + 'presetRef', + ]) + +/** + * @template T + * @template {keyof T} K + * @param {T} obj + * @param {ReadonlyArray} keys + * @returns {Pick} + */ +function pick(obj, keys) { + /** @type {Partial} */ + const result = {} + for (const key of keys) result[key] = obj[key] + return /** @type {Pick} */ (result) +} + /** * If the path is a regular file, return its size in bytes. * diff --git a/test/fixtures/legacy-mapeo-data.mlef b/test/fixtures/legacy-mapeo-data.mlef new file mode 100644 index 00000000..8124224d Binary files /dev/null and b/test/fixtures/legacy-mapeo-data.mlef differ