Files
overleaf-cep/services/history-v1/api/schema.js
Jakob Ackermann 5a6c066847 [web] allow admins to clone projects with ranges and entire history (#32739)
* [web] add consistent aria-label to editing/reviewing toggle

* [docstore] add endpoint for getting all docs with ranges

* [history-v1] fix schema of chunkId when deleting old history chunk

* [web] skip duplicate project lookup for resolving rootDocPath

* [web] ignore new limits for root doc path when making debug copy

* [web] allow admins to clone projects with ranges and entire history

* [web] fix tests

* [history-v1] re-order params for cloning project

* [web] fix duplicate import of logger after merge

* [project-history] re-order params for cloning project history metadata

GitOrigin-RevId: 7fa35b4f90885dd453150a348d491ba0ec8de412
2026-04-15 08:05:49 +00:00

255 lines
5.0 KiB
JavaScript

'use strict'
const { z, zz } = require('@overleaf/validation-tools')
const Blob = require('overleaf-editor-core').Blob
const hexHashPattern = new RegExp(Blob.HEX_HASH_RX_STRING)
const fileSchema = z
.object({
hash: z.string().optional(),
byteLength: z.number().int().nullable().optional(),
stringLength: z.number().int().nullable().optional(),
metadata: z.object({}).passthrough().optional(),
})
.passthrough()
const snapshotSchema = z.object({
files: z.record(z.string(), fileSchema),
})
const v2DocVersionsSchema = z.object({
pathname: z.string().optional(),
v: z.number().int().optional(),
})
const operationSchema = z
.object({
pathname: z.string().optional(),
newPathname: z.string().optional(),
blob: z
.object({
hash: z.string(),
})
.optional(),
textOperation: z.array(z.any()).optional(),
file: fileSchema.optional(),
contentHash: z.string().optional(),
})
.passthrough()
const originSchema = z
.object({
kind: z.string().optional(),
})
.passthrough()
const changeSchema = z
.object({
timestamp: z.string(),
operations: z.array(operationSchema),
authors: z.array(z.number().int().nullable()).optional(),
v2Authors: z.array(z.string().nullable()).optional(),
origin: originSchema.optional(),
projectVersion: z.string().optional(),
v2DocVersions: z.record(z.string(), v2DocVersionsSchema).optional(),
})
.passthrough()
const schemas = {
projectId: z.object({
params: z
.object({
project_id: z.string().optional(),
})
.optional(),
}),
initializeProject: z.object({
body: z
.object({
projectId: z.string().optional(),
})
.optional(),
}),
cloneProject: z.object({
body: z.object({
targetProjectId: z.string(),
}),
params: z.object({
project_id: z.string(),
}),
}),
getProjectBlobsStats: z.object({
body: z.object({
projectIds: z.array(z.string()),
}),
}),
getBlobStats: z.object({
params: z.object({
project_id: z.string(),
}),
body: z.object({
blobHashes: z.array(z.string()),
}),
}),
deleteProject: z.object({
params: z.object({
project_id: z.string(),
}),
body: z.any().optional(),
}),
getProjectBlob: z.object({
params: z.object({
project_id: z.string(),
hash: z.string().regex(hexHashPattern),
}),
headers: z.object({
range: z.string().optional(),
}),
}),
headProjectBlob: z.object({
params: z.object({
project_id: z.string(),
hash: z.string().regex(hexHashPattern),
}),
}),
createProjectBlob: z.object({
params: z.object({
project_id: z.string(),
hash: z.string().regex(hexHashPattern),
}),
body: z.any().optional(),
}),
copyProjectBlob: z.object({
params: z.object({
project_id: z.string(),
hash: z.string().regex(hexHashPattern),
}),
query: z.object({
copyFrom: z.string(),
}),
body: z.any().optional(),
}),
getLatestContent: z.object({
params: z.object({
project_id: z.string(),
}),
}),
getLatestHashedContent: z.object({
params: z.object({
project_id: z.string(),
}),
}),
getLatestHistory: z.object({
params: z.object({
project_id: z.string(),
}),
}),
getLatestHistoryRaw: z.object({
params: z.object({
project_id: z.string(),
}),
query: z.object({
readOnly: z.coerce.boolean().optional(),
}),
}),
getLatestPersistedHistory: z.object({
params: z.object({
project_id: z.string(),
}),
}),
getHistory: z.object({
params: z.object({
project_id: z.string(),
version: z.coerce.number(),
}),
}),
getContentAtVersion: z.object({
params: z.object({
project_id: z.string(),
version: z.coerce.number(),
}),
}),
getHistoryBefore: z.object({
params: z.object({
project_id: z.string(),
timestamp: zz.datetime(),
}),
}),
getZip: z.object({
params: z.object({
project_id: z.string(),
version: z.coerce.number(),
}),
}),
createZip: z.object({
params: z.object({
project_id: z.string(),
version: z.coerce.number(),
}),
body: z.any().optional(),
}),
getChanges: z.object({
params: z.object({
project_id: z.string(),
}),
query: z.object({
since: z.coerce.number().optional(),
}),
}),
importSnapshot: z.object({
params: z.object({
project_id: z.string(),
}),
body: snapshotSchema,
}),
importChanges: z.object({
params: z.object({
project_id: z.string(),
}),
query: z.object({
end_version: z.coerce.number(),
return_snapshot: z.enum(['hashed', 'none']).optional(),
}),
body: z.array(changeSchema),
}),
flushChanges: z.object({
params: z.object({
project_id: z.string(),
}),
body: z.any().optional(),
}),
expireProject: z.object({
params: z.object({
project_id: z.string(),
}),
body: z.any().optional(),
}),
}
module.exports = schemas