mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 14:13:43 +01:00
525 lines
14 KiB
JavaScript
525 lines
14 KiB
JavaScript
'use strict'
|
|
|
|
const { z, zz } = require('@overleaf/validation-tools')
|
|
const Blob = require('overleaf-editor-core').Blob
|
|
const {
|
|
rawSnapshot,
|
|
rawChange,
|
|
rawBlobHash,
|
|
rawFileMetadata,
|
|
} = require('overleaf-editor-core/lib/schemas')
|
|
|
|
const hexHashPattern = new RegExp(Blob.HEX_HASH_RX_STRING)
|
|
|
|
// Rollout-temporary fallback building blocks (main's pre-refinement shapes
|
|
// for imported snapshots/changes, before they were validated against
|
|
// overleaf-editor-core's raw* schemas); delete alongside the
|
|
// importSnapshotFallbackSchema/importChangesFallbackSchema opts below when
|
|
// this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
const fallbackFileSchema = z
|
|
.object({
|
|
hash: z.string().optional(),
|
|
rangesHash: z.string().optional(),
|
|
byteLength: z.number().int().nullable().optional(),
|
|
stringLength: z.number().int().nullable().optional(),
|
|
metadata: z.object({}).passthrough().optional(),
|
|
})
|
|
.passthrough()
|
|
|
|
const fallbackV2DocVersionsSchema = z.object({
|
|
pathname: z.string().optional(),
|
|
v: z.number().int().optional(),
|
|
})
|
|
|
|
const fallbackSnapshotSchema = z.object({
|
|
files: z.record(z.string(), fallbackFileSchema),
|
|
projectVersion: z.string().optional(),
|
|
v2DocVersions: z
|
|
.record(z.string(), fallbackV2DocVersionsSchema)
|
|
.nullable()
|
|
.optional(),
|
|
timestamp: z.string().optional(),
|
|
})
|
|
|
|
const fallbackOperationSchema = z
|
|
.object({
|
|
pathname: z.string().optional(),
|
|
newPathname: z.string().optional(),
|
|
blob: z
|
|
.object({
|
|
hash: z.string(),
|
|
})
|
|
.optional(),
|
|
textOperation: z.array(z.any()).optional(),
|
|
file: fallbackFileSchema.optional(),
|
|
contentHash: z.string().optional(),
|
|
})
|
|
.passthrough()
|
|
|
|
const fallbackOriginSchema = z
|
|
.object({
|
|
kind: z.string().optional(),
|
|
})
|
|
.passthrough()
|
|
|
|
const fallbackChangeSchema = z
|
|
.object({
|
|
timestamp: z.string(),
|
|
operations: z.array(fallbackOperationSchema),
|
|
authors: z.array(z.number().int().nullable()).optional(),
|
|
v2Authors: z.array(z.string().nullable()).optional(),
|
|
origin: fallbackOriginSchema.optional(),
|
|
projectVersion: z.string().optional(),
|
|
v2DocVersions: z.record(z.string(), fallbackV2DocVersionsSchema).optional(),
|
|
})
|
|
.passthrough()
|
|
|
|
const setContentBodyBase = z.object({
|
|
pathname: z.string().min(1),
|
|
source: z.string(),
|
|
userId: zz.objectId().optional(),
|
|
timestamp: zz.datetime(),
|
|
metadata: rawFileMetadata.optional(),
|
|
trackChanges: z.boolean().optional(),
|
|
})
|
|
|
|
const schemas = {
|
|
projectId: z.object({
|
|
params: z
|
|
.object({
|
|
project_id: zz.projectHistoryId().optional(),
|
|
})
|
|
.optional(),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
projectIdFallbackSchema: z.object({
|
|
params: z
|
|
.object({
|
|
project_id: z.string().optional(),
|
|
})
|
|
.optional(),
|
|
}),
|
|
|
|
initializeProject: z.object({
|
|
body: z
|
|
.strictObject({
|
|
projectId: zz.projectHistoryId().optional(),
|
|
})
|
|
.optional(),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
initializeProjectFallbackSchema: z.object({
|
|
body: z
|
|
.object({
|
|
projectId: z.string().optional(),
|
|
})
|
|
.optional(),
|
|
}),
|
|
|
|
cloneProject: z.object({
|
|
body: z.strictObject({
|
|
targetProjectId: zz.projectHistoryId(),
|
|
}),
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
cloneProjectFallbackSchema: z.object({
|
|
body: z.object({
|
|
targetProjectId: z.string(),
|
|
}),
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
}),
|
|
}),
|
|
|
|
getProjectBlobsStats: z.object({
|
|
body: z.strictObject({
|
|
projectIds: z.array(zz.projectHistoryId()),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
getProjectBlobsStatsFallbackSchema: z.object({
|
|
body: z.object({
|
|
projectIds: z.array(z.string()),
|
|
}),
|
|
}),
|
|
|
|
getBlobStats: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
}),
|
|
body: z.strictObject({
|
|
blobHashes: z.array(rawBlobHash),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
getBlobStatsFallbackSchema: 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: zz.projectHistoryId(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
deleteProjectFallbackSchema: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
}),
|
|
}),
|
|
|
|
getProjectBlob: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
hash: z.string().regex(hexHashPattern),
|
|
}),
|
|
headers: z.object({
|
|
range: z.string().optional(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
getProjectBlobFallbackSchema: 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: zz.projectHistoryId(),
|
|
hash: z.string().regex(hexHashPattern),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
headProjectBlobFallbackSchema: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
hash: z.string().regex(hexHashPattern),
|
|
}),
|
|
}),
|
|
|
|
createProjectBlob: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
hash: z.string().regex(hexHashPattern),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
createProjectBlobFallbackSchema: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
hash: z.string().regex(hexHashPattern),
|
|
}),
|
|
}),
|
|
|
|
copyProjectBlob: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
hash: z.string().regex(hexHashPattern),
|
|
}),
|
|
query: z.object({
|
|
copyFrom: zz.projectHistoryId(),
|
|
sizeLimit: z.coerce.number().optional(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
copyProjectBlobFallbackSchema: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
hash: z.string().regex(hexHashPattern),
|
|
}),
|
|
query: z.object({
|
|
copyFrom: z.string(),
|
|
sizeLimit: z.coerce.number().optional(),
|
|
}),
|
|
}),
|
|
|
|
getLatestContent: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
getLatestContentFallbackSchema: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
}),
|
|
}),
|
|
|
|
getLatestHashedContent: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
getLatestHashedContentFallbackSchema: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
}),
|
|
}),
|
|
|
|
getLatestHistory: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
getLatestHistoryFallbackSchema: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
}),
|
|
}),
|
|
|
|
getLatestHistoryRaw: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
}),
|
|
query: z.object({
|
|
readOnly: z.coerce.boolean().optional(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
getLatestHistoryRawFallbackSchema: 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: zz.projectHistoryId(),
|
|
}),
|
|
}),
|
|
|
|
getHistory: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
version: z.coerce.number(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
getHistoryFallbackSchema: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
version: z.coerce.number(),
|
|
}),
|
|
}),
|
|
|
|
getContentAtVersion: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
version: z.coerce.number(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
getContentAtVersionFallbackSchema: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
version: z.coerce.number(),
|
|
}),
|
|
}),
|
|
|
|
getHistoryBefore: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
timestamp: zz.datetime(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
getHistoryBeforeFallbackSchema: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
timestamp: zz.datetime(),
|
|
}),
|
|
}),
|
|
|
|
getLatestZip: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
getLatestZipFallbackSchema: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
}),
|
|
}),
|
|
|
|
getZip: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
version: z.coerce.number(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
getZipFallbackSchema: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
version: z.coerce.number(),
|
|
}),
|
|
}),
|
|
|
|
createZip: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
version: z.coerce.number(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
createZipFallbackSchema: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
version: z.coerce.number(),
|
|
}),
|
|
}),
|
|
|
|
getChanges: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
}),
|
|
query: z.object({
|
|
since: z.coerce.number().optional(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
getChangesFallbackSchema: 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: zz.projectHistoryId(),
|
|
}),
|
|
body: rawSnapshot,
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main, before
|
|
// imported snapshots were validated against overleaf-editor-core's
|
|
// rawSnapshot); delete when this route's REQ_VALIDATION_MODE
|
|
// instrumentation is removed.
|
|
importSnapshotFallbackSchema: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
}),
|
|
body: fallbackSnapshotSchema,
|
|
}),
|
|
|
|
importChanges: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
}),
|
|
query: z.object({
|
|
end_version: z.coerce.number(),
|
|
return_snapshot: z.enum(['hashed', 'none']).optional(),
|
|
}),
|
|
body: z.array(rawChange),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main, before
|
|
// imported changes were validated against overleaf-editor-core's
|
|
// rawChange); delete when this route's REQ_VALIDATION_MODE
|
|
// instrumentation is removed.
|
|
importChangesFallbackSchema: 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(fallbackChangeSchema),
|
|
}),
|
|
|
|
setContent: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
}),
|
|
// strict() rejects unknown keys, so a mixed payload with both content and
|
|
// blobHash fails both union members and is rejected.
|
|
body: z
|
|
.union([
|
|
setContentBodyBase.extend({ content: z.string() }).strict(),
|
|
setContentBodyBase
|
|
.extend({ blobHash: z.string().regex(hexHashPattern) })
|
|
.strict(),
|
|
])
|
|
.refine(
|
|
body => {
|
|
if (body.trackChanges && !body.userId) return false
|
|
return true
|
|
},
|
|
{
|
|
message: '"userId" is required when trackChanges is set',
|
|
path: ['userId'],
|
|
}
|
|
),
|
|
}),
|
|
|
|
flushChanges: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
flushChangesFallbackSchema: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
}),
|
|
}),
|
|
|
|
expireProject: z.object({
|
|
params: z.object({
|
|
project_id: zz.projectHistoryId(),
|
|
}),
|
|
}),
|
|
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
|
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
|
expireProjectFallbackSchema: z.object({
|
|
params: z.object({
|
|
project_id: z.string(),
|
|
}),
|
|
}),
|
|
}
|
|
|
|
module.exports = schemas
|