diff --git a/package-lock.json b/package-lock.json index a4384b5..b741406 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@comapeo/geometry": "^1.0.2", "compact-encoding": "^2.12.0", + "filter-obj": "^6.1.0", "protobufjs": "^7.2.5", "type-fest": "^4.26.0" }, @@ -2083,6 +2084,18 @@ "node": ">=8" } }, + "node_modules/filter-obj": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-6.1.0.tgz", + "integrity": "sha512-xdMtCAODmPloU9qtmPcdBV9Kd27NtMse+4ayThxqIHUES5Z2S6bGpap5PpdmNM56ub7y3i1eyr+vJJIIgWGKmA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", diff --git a/package.json b/package.json index b27081d..44d49cf 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "dependencies": { "@comapeo/geometry": "^1.0.2", "compact-encoding": "^2.12.0", + "filter-obj": "^6.1.0", "protobufjs": "^7.2.5", "type-fest": "^4.26.0" }, diff --git a/scripts/lib/generate-jsonschema-exports.js b/scripts/lib/generate-jsonschema-exports.js index 6bb70b9..3e24c50 100644 --- a/scripts/lib/generate-jsonschema-exports.js +++ b/scripts/lib/generate-jsonschema-exports.js @@ -48,6 +48,7 @@ export async function generateJSONSchemaExports(jsonSchemas) { return `import { type JSONSchema7 } from 'json-schema' import { type SchemaNameAll } from './types.js' +import { type MapeoCommon } from './schema/index.js' import { type ReadonlyDeep } from 'type-fest' declare module 'json-schema' { @@ -58,6 +59,8 @@ declare module 'json-schema' { type SchemaRecord = Record> +export const commonSchema = ${printf(jsonSchemas.values.common)} as const satisfies ReadonlyDeep + export const docSchemas = ${printf(docSchemas)} as const satisfies SchemaRecord export const dereferencedDocSchemas = ${printf( diff --git a/src/index.ts b/src/index.ts index f3ce288..6bb2486 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,6 +6,7 @@ export { getVersionId, parseVersionId, valueOf, + omitServerProps, type VersionIdObject, } from './lib/utils.js' diff --git a/src/lib/utils.ts b/src/lib/utils.ts index a98d175..f93d5a5 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,9 +1,12 @@ +import { excludeKeys } from 'filter-obj' import { type ProtoTypeNames } from '../proto/types.js' import { + type FilterBySchemaName, + type MapeoCommon, type MapeoDoc, type MapeoValue, - type FilterBySchemaName, } from '../types.js' +import { commonSchema } from '../schemas.js' import { omit } from './omit.js' export function getOwn( @@ -79,6 +82,10 @@ export function parseVersionId(versionId: string): VersionIdObject { return { coreDiscoveryKey, index } } +/** + * Get the value of a document, excluding server-managed properties. + * @deprecated Use the more flexible `omitServerProps` instead + */ export function valueOf( doc: TDoc & { forks?: string[] } ): FilterBySchemaName { @@ -93,3 +100,22 @@ export function valueOf( 'deleted', ]) as any } + +// Casting this type because we _know_ that commonSchema.properties does not +// have additional keys, unlike situations described in +// https://stackoverflow.com/a/55012175 +const commonSchemaKeys = Object.keys(commonSchema.properties).filter( + (key) => key !== 'schemaName' +) as Array> + +const keysToExclude = [...commonSchemaKeys, 'forks'] as const + +/** + * Omit server-managed properties from a document, such as `createdBy`, + * `createdAt`, etc. These properties cannot be modified by the client. + */ +export function omitServerProps( + doc: TDoc & { forks?: string[] } +) { + return excludeKeys(doc, keysToExclude) +}