✨ feat(schema): enhance API configuration schemas with new properties and validations
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
- Updated collection.json to include upload defaults, audit logging, query limits, and more. - Enhanced collectionNavigation.json with viewHint configurations. - Added project-wide upload defaults and hook configurations in config.json. - Expanded field.json to support new field types, validations, and properties. - Improved fieldMeta.json with additional widget configurations and properties. - Updated hooks.json to include new bulk operation hooks and audit logging. - Enhanced imageFilter.json with additional image processing options. - Added timeout properties to job.json for better execution control. - Refined permissions.json to allow more granular control over HTTP method permissions and added filter and field visibility options.
This commit is contained in:
770
index.d.ts
vendored
770
index.d.ts
vendored
@@ -6,6 +6,286 @@ declare global {
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a `boolean` value or an object with an `eval` JS expression.
|
||||
* Used for field-level `readonly` and `hidden` configuration.
|
||||
*/
|
||||
export type BoolOrEval = boolean | { eval: string }
|
||||
|
||||
/** Structured field validator as defined in Go CollectionField.Validator */
|
||||
export interface FieldValidator {
|
||||
/** Array of allowed values */
|
||||
in?: any[]
|
||||
/** Whether the field is required */
|
||||
required?: boolean
|
||||
/** Whether zero-values are allowed when required is true */
|
||||
allowZero?: boolean
|
||||
/** JS eval expression for custom validation */
|
||||
eval?: string
|
||||
}
|
||||
|
||||
/** Search configuration for a collection */
|
||||
export interface SearchConfig {
|
||||
/** Search config name (used in query parameter qName) */
|
||||
name: string
|
||||
/** Search mode: text (MongoDB text index), regex, eval (JS), filter, ngram */
|
||||
mode: "text" | "regex" | "eval" | "filter" | "ngram"
|
||||
/** Fields to search in (for text/regex mode) */
|
||||
fields?: string[]
|
||||
/** Meta information */
|
||||
meta?: { [key: string]: any }
|
||||
/** JS eval expression (for eval mode) */
|
||||
eval?: string
|
||||
/** MongoDB filter template (for filter mode) */
|
||||
filter?: { [key: string]: any }
|
||||
}
|
||||
|
||||
/** Query limits configuration for a collection */
|
||||
export interface QueryLimitsConfig {
|
||||
/** Default limit for GET queries (if client doesn't specify) */
|
||||
defaultLimit?: number
|
||||
/** Maximum allowed limit for GET queries */
|
||||
maxLimit?: number
|
||||
}
|
||||
|
||||
/** Bulk operation optimization configuration */
|
||||
export interface BulkOptimizeConfig {
|
||||
/** Optimize bulk create operations */
|
||||
create?: boolean
|
||||
/** Optimize bulk update operations */
|
||||
update?: boolean
|
||||
/** Optimize bulk delete operations */
|
||||
delete?: boolean
|
||||
}
|
||||
|
||||
/** Bulk configuration for a collection */
|
||||
export interface BulkConfig {
|
||||
/** Optimization settings for bulk operations */
|
||||
optimize?: BulkOptimizeConfig
|
||||
}
|
||||
|
||||
/** Collection index definition */
|
||||
export interface CollectionIndex {
|
||||
/** Index name */
|
||||
name?: string
|
||||
/** Index key fields (prefix with - for descending) */
|
||||
key: string[]
|
||||
/** Whether the index enforces uniqueness */
|
||||
unique?: boolean
|
||||
/** Whether to drop duplicate entries */
|
||||
dropDups?: boolean
|
||||
/** Build index in background */
|
||||
background?: boolean
|
||||
/** Only index documents that contain the indexed field */
|
||||
sparse?: boolean
|
||||
/** Default language for text indexes */
|
||||
defaultLanguage?: string
|
||||
/** Field that contains the language override */
|
||||
languageOverride?: string
|
||||
}
|
||||
|
||||
/** Audit configuration for a collection */
|
||||
export interface AuditCollectionConfig {
|
||||
/** Whether audit logging is enabled for this collection */
|
||||
enabled?: boolean
|
||||
/** List of actions to audit: create, update, delete, bulkCreate, bulkUpdate, bulkDelete, get */
|
||||
actions?: string[]
|
||||
}
|
||||
|
||||
/** Image filter parameters — used in both CollectionConfig.imageFilter and ImagePackage.filter() */
|
||||
export interface ImageFilterParams {
|
||||
width?: number
|
||||
height?: number
|
||||
fit?: boolean
|
||||
fill?: boolean
|
||||
resampling?:
|
||||
| "nearestNeighbor"
|
||||
| "hermite"
|
||||
| "linear"
|
||||
| "catmullRom"
|
||||
| "lanczos"
|
||||
| "box"
|
||||
| "mitchellNetravili"
|
||||
| "bSpline"
|
||||
| "gaussian"
|
||||
| "bartlett"
|
||||
| "hann"
|
||||
| "hamming"
|
||||
| "blackman"
|
||||
| "welch"
|
||||
| "cosine"
|
||||
anchor?:
|
||||
| "center"
|
||||
| "topLeft"
|
||||
| "top"
|
||||
| "topRight"
|
||||
| "left"
|
||||
| "right"
|
||||
| "bottomLeft"
|
||||
| "bottom"
|
||||
| "bottomRight"
|
||||
brightness?: number
|
||||
saturation?: number
|
||||
contrast?: number
|
||||
gamma?: number
|
||||
blur?: number
|
||||
sharpen?: number
|
||||
invert?: boolean
|
||||
grayscale?: boolean
|
||||
quality?: number
|
||||
lossless?: boolean
|
||||
skipLargerDimension?: boolean
|
||||
skipLargerFilesize?: boolean
|
||||
outputType?: "jpg" | "jpeg" | "png" | "webp"
|
||||
}
|
||||
|
||||
/** Collection config as returned by context.collection() – JSON-serialized from Go CollectionConfig */
|
||||
export interface CollectionInfo {
|
||||
name: string
|
||||
defaultLanguage?: string
|
||||
permissions?: { [role: string]: PermissionSet }
|
||||
projections?: { [name: string]: ProjectionConfig }
|
||||
meta?: { [key: string]: any }
|
||||
fields?: CollectionFieldInfo[]
|
||||
/** Named image filter presets for file fields */
|
||||
imageFilter?: { [name: string]: ImageFilterParams[] }
|
||||
/** Collection index definitions */
|
||||
indexes?: CollectionIndex[]
|
||||
/** Audit configuration */
|
||||
audit?: AuditCollectionConfig
|
||||
/** Bulk operation configuration */
|
||||
bulk?: BulkConfig
|
||||
/** Query limits for GET requests */
|
||||
queryLimits?: QueryLimitsConfig
|
||||
/** Fields that are read-only at collection level */
|
||||
readonlyFields?: string[]
|
||||
/** Fields that are hidden at collection level */
|
||||
hiddenFields?: string[]
|
||||
/** Search configurations */
|
||||
search?: SearchConfig[]
|
||||
/** Reject unknown fields not defined in the fields array */
|
||||
strictFields?: boolean
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export type MethodPermission = boolean | { allow: boolean; bulk?: boolean }
|
||||
export type SimpleMethodPermission = boolean | { allow: boolean }
|
||||
|
||||
export interface PermissionSet {
|
||||
methods?: {
|
||||
get?: SimpleMethodPermission
|
||||
/** `true` = allow single POST, `{allow: true, bulk: true}` = allow single + bulk POST */
|
||||
post?: MethodPermission
|
||||
/** `true` = allow single PUT, `{allow: true, bulk: true}` = allow single + bulk PUT */
|
||||
put?: MethodPermission
|
||||
/** `true` = allow single DELETE, `{allow: true, bulk: true}` = allow single + bulk DELETE */
|
||||
delete?: MethodPermission
|
||||
}
|
||||
/** MongoDB filter applied to all queries for this permission set */
|
||||
filter?: { [key: string]: any }
|
||||
/** List of projection names this permission set is allowed to use */
|
||||
validProjections?: string[]
|
||||
/** Fields that are read-only for this permission set */
|
||||
readonlyFields?: string[]
|
||||
/** Fields that are hidden for this permission set */
|
||||
hiddenFields?: string[]
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface ProjectionConfig {
|
||||
select?: { [field: string]: 0 | 1 }
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface CollectionFieldInfo {
|
||||
name: string
|
||||
type: string
|
||||
subFields?: CollectionFieldInfo[]
|
||||
index?: string[]
|
||||
validator?: FieldValidator
|
||||
meta?: { [key: string]: any }
|
||||
/** Field-level readonly — boolean or JS eval expression */
|
||||
readonly?: BoolOrEval
|
||||
/** Field-level hidden — boolean or JS eval expression */
|
||||
hidden?: BoolOrEval
|
||||
/** Reject unknown sub-fields not defined in subFields */
|
||||
strictFields?: boolean
|
||||
}
|
||||
|
||||
/** API info as returned by context.api() – JSON-serialized from Go API struct */
|
||||
export interface ApiInfo {
|
||||
isOnline: boolean
|
||||
lastReload: string
|
||||
namespace: string
|
||||
meta?: { [key: string]: any }
|
||||
assets?: { name: string; path: string }[]
|
||||
collections?: CollectionInfo[]
|
||||
jobs?: JobConfig[]
|
||||
errors?: { collection?: string; context?: string; error: any }[]
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
/** Project info as returned by context.project() – JSON-serialized from Go Project struct */
|
||||
export interface ProjectInfo {
|
||||
name: string
|
||||
description?: string
|
||||
namespace?: string
|
||||
users?: string[]
|
||||
configFile?: string
|
||||
api?: ApiInfo
|
||||
yourPermissions?: { [key: string]: any }
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
/** Represents a single audit log entry as received in audit.return hooks */
|
||||
export interface AuditLogEntry {
|
||||
id?: string
|
||||
insertTime?: string
|
||||
updateTime?: string
|
||||
/** ID of the user who performed the action */
|
||||
userId?: string
|
||||
/** Username of the user who performed the action */
|
||||
username?: string
|
||||
/** Role of the user (0=admin, 1=user) */
|
||||
userRole?: number
|
||||
/** Project namespace */
|
||||
projectNamespace?: string
|
||||
/** Project display name */
|
||||
projectName?: string
|
||||
/** Collection name */
|
||||
collection?: string
|
||||
/** Action performed: create, bulkCreate, update, delete, bulkUpdate, bulkDelete, get, login, reload, shutdown */
|
||||
action?: string
|
||||
/** Source information (type, collection, method, step, file, line) */
|
||||
source?: {
|
||||
type?: string
|
||||
collection?: string
|
||||
method?: string
|
||||
step?: string
|
||||
file?: string
|
||||
line?: number
|
||||
}
|
||||
/** Document ID affected */
|
||||
documentId?: string
|
||||
/** Full document snapshot at time of action */
|
||||
snapshot?: { [key: string]: any }
|
||||
/** Changed fields (for updates) */
|
||||
changes?: { [key: string]: any }
|
||||
/** Filter used (for queries/deletes) */
|
||||
filter?: { [key: string]: any }
|
||||
/** Number of affected documents (e.g. deleteMany) */
|
||||
count?: number
|
||||
/** Client IP address */
|
||||
ip?: string
|
||||
/** Authentication method used (e.g. "jwt", "adminToken") */
|
||||
authMethod?: string
|
||||
/** Label of the admin token used (if applicable) */
|
||||
tokenLabel?: string
|
||||
/** Prefix of the admin token used (if applicable) */
|
||||
tokenPrefix?: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface DbReadOptions {
|
||||
filter?: {
|
||||
[key: string]: any
|
||||
@@ -24,13 +304,16 @@ declare global {
|
||||
|
||||
interface GetHookGetOnlyData {
|
||||
/**
|
||||
* true if only one document was requested via /COLLECTION/ID
|
||||
* true if only one document was requested via /COLLECTION/ID.
|
||||
* In audit.return hooks this is always true (entries are processed individually).
|
||||
*/
|
||||
one?: boolean
|
||||
/**
|
||||
* get list of documents (only valid after stage "read" in "get" hook)
|
||||
* Get list of documents.
|
||||
* - In get.return hooks: array of collection documents
|
||||
* - In audit.return hooks: array with a single AuditLogEntry
|
||||
*/
|
||||
results(): CollectionDocument[]
|
||||
results(): CollectionDocument[] | AuditLogEntry[]
|
||||
}
|
||||
|
||||
interface GetHookData {
|
||||
@@ -68,9 +351,30 @@ declare global {
|
||||
|
||||
interface PostHookData {
|
||||
/**
|
||||
* post data only valid in "post" and "put" hooks
|
||||
* post data only valid in "post" and "put" hooks.
|
||||
* For bulk hooks (bulkCreate), this is an array of documents.
|
||||
*/
|
||||
data?: CollectionDocument
|
||||
data?: CollectionDocument | CollectionDocument[]
|
||||
|
||||
/**
|
||||
* Number of created documents — only set in post.bulkReturn hook
|
||||
*/
|
||||
created?: number
|
||||
|
||||
/**
|
||||
* Array of created document IDs — only set in post.bulkReturn hook
|
||||
*/
|
||||
ids?: string[]
|
||||
|
||||
/**
|
||||
* Number of modified documents — only set in put.bulkReturn hook
|
||||
*/
|
||||
modified?: number
|
||||
|
||||
/**
|
||||
* Number of deleted documents — only set in delete.bulkReturn hook
|
||||
*/
|
||||
deleted?: number
|
||||
}
|
||||
|
||||
interface JobConfig {
|
||||
@@ -93,6 +397,11 @@ declare global {
|
||||
* jobs program file
|
||||
*/
|
||||
file?: string
|
||||
|
||||
/**
|
||||
* execution timeout in seconds
|
||||
*/
|
||||
timeout?: number
|
||||
}
|
||||
|
||||
interface JobData {
|
||||
@@ -113,22 +422,58 @@ declare global {
|
||||
* get current project object
|
||||
*
|
||||
*/
|
||||
project(): {
|
||||
[key: string]: any
|
||||
}
|
||||
project(): ProjectInfo
|
||||
|
||||
/**
|
||||
* get server config object
|
||||
* get server config object (sensitive fields like jwtSecret, adminTokens, apiKeys are excluded)
|
||||
*
|
||||
*/
|
||||
server(): {
|
||||
api: {
|
||||
port: number
|
||||
secureCookies?: boolean
|
||||
accessTokenLifetime?: string
|
||||
refreshTokenLifetime?: string
|
||||
}
|
||||
security: {
|
||||
allowAbsolutePaths: boolean
|
||||
allowUpperPaths: boolean
|
||||
}
|
||||
llm?: {
|
||||
providers?: {
|
||||
name: string
|
||||
type: string
|
||||
baseURL: string
|
||||
defaultModel: string
|
||||
models?: string[]
|
||||
maxTokensPerRequest?: number
|
||||
}[]
|
||||
}
|
||||
audit?: {
|
||||
enabled: boolean
|
||||
defaultTTL: string
|
||||
defaultLimit?: number
|
||||
maxLimit?: number
|
||||
}
|
||||
ratelimit?: {
|
||||
enabled?: boolean
|
||||
loginInitialDelay?: string
|
||||
loginMaxDelay?: string
|
||||
loginResetAfter?: string
|
||||
}
|
||||
hook?: {
|
||||
cache: {
|
||||
maxEntries?: number
|
||||
defaultTTL?: string
|
||||
}
|
||||
ratelimit: {
|
||||
backoffInitialDelay?: string
|
||||
backoffMaxDelay?: string
|
||||
backoffResetAfter?: string
|
||||
windowSize?: string
|
||||
windowMaxHits?: number
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,14 +505,25 @@ declare global {
|
||||
/**
|
||||
* update a document in a collection
|
||||
*
|
||||
* Supports field-level operators in data:
|
||||
* - `{ "$inc": value }` — increment by value
|
||||
* - `{ "$mul": value }` — multiply by value
|
||||
* - `{ "$unset": true }` — remove the field
|
||||
* - `{ "$set": value }` — explicit set (same as plain value)
|
||||
*
|
||||
* Operators are converted to native MongoDB operators and executed
|
||||
* atomically in a single DB call.
|
||||
*
|
||||
* @param colName collection name
|
||||
* @param id id of entry
|
||||
* @param data new/changed data
|
||||
* @param data new/changed data (may contain operators)
|
||||
* @param options optional: `{ raw: true }` to pass data as raw MongoDB update document
|
||||
*/
|
||||
update(
|
||||
colName: string,
|
||||
id: string,
|
||||
data: CollectionDocument
|
||||
data: CollectionDocument,
|
||||
options?: { raw?: boolean }
|
||||
): CollectionDocument
|
||||
|
||||
/**
|
||||
@@ -188,6 +544,26 @@ declare global {
|
||||
colName: string,
|
||||
options?: DbReadOptions
|
||||
): { message: "ok"; removed: number }
|
||||
|
||||
/**
|
||||
* update multiple documents matching a filter
|
||||
*
|
||||
* Use `changes` for simple field updates (supports operators like $inc, $mul).
|
||||
* Use `update` for raw MongoDB update documents.
|
||||
*
|
||||
* @param colName collection name
|
||||
* @param options options with filter and changes/update
|
||||
*/
|
||||
updateMany(
|
||||
colName: string,
|
||||
options: {
|
||||
filter?: { [key: string]: any }
|
||||
/** Field updates — may contain operators like { "$inc": 1 } */
|
||||
changes?: { [key: string]: any }
|
||||
/** Raw MongoDB update document (e.g. { "$inc": { stock: -1 } }) */
|
||||
update?: { [key: string]: any }
|
||||
}
|
||||
): { message: "ok"; modified: number }
|
||||
}
|
||||
|
||||
interface SmtpPackage {
|
||||
@@ -305,7 +681,7 @@ declare global {
|
||||
|
||||
interface HttpPackage {
|
||||
/**
|
||||
* http request
|
||||
* http request — reads the entire response body into memory
|
||||
*
|
||||
* @param url url for request
|
||||
* @param options request options
|
||||
@@ -316,7 +692,7 @@ declare global {
|
||||
method?: string
|
||||
headers?: { [key: string]: string }
|
||||
body?: string
|
||||
// timeout in seconds
|
||||
/** timeout in seconds (default 10) */
|
||||
timeout?: number
|
||||
}
|
||||
): {
|
||||
@@ -330,6 +706,35 @@ declare global {
|
||||
json(): any
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* streaming http request — response body is NOT read into memory.
|
||||
* Use body.read() to read line by line (ideal for SSE / newline-delimited
|
||||
* protocols like OpenAI streaming API).
|
||||
*
|
||||
* @param url url for request
|
||||
* @param options request options
|
||||
*/
|
||||
fetchStream(
|
||||
url: string,
|
||||
options?: {
|
||||
method?: string
|
||||
headers?: { [key: string]: string }
|
||||
body?: string
|
||||
/** timeout in seconds (default 0 = no timeout, hook timeout controls duration) */
|
||||
timeout?: number
|
||||
}
|
||||
): {
|
||||
status: number
|
||||
statusText: string
|
||||
headers: { [key: string]: string }
|
||||
body: {
|
||||
/** returns the next line as string, or null at EOF */
|
||||
read(): string | null
|
||||
/** explicitly closes the response body (auto-closed at EOF) */
|
||||
close(): void
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface DebugPackage {
|
||||
@@ -355,12 +760,46 @@ declare global {
|
||||
|
||||
interface ResponsePackage {
|
||||
/**
|
||||
* set response header
|
||||
* set response header (must be called before writeHeader/write)
|
||||
*
|
||||
* @param name header name
|
||||
* @param value value
|
||||
*/
|
||||
header(name: string, value: any): void
|
||||
|
||||
/**
|
||||
* set the HTTP status code — must be called before write().
|
||||
* If not called, the first write() will implicitly send status 200.
|
||||
*
|
||||
* @param status HTTP status code
|
||||
*/
|
||||
writeHeader(status: number): void
|
||||
|
||||
/**
|
||||
* write data directly to the HTTP response body.
|
||||
* Use for streaming responses (e.g. SSE to a chat widget).
|
||||
*
|
||||
* @param data string or byte data to write
|
||||
*/
|
||||
write(data: string | any): void
|
||||
|
||||
/**
|
||||
* flush buffered data to the client immediately.
|
||||
* Essential for streaming / SSE to push chunks without waiting
|
||||
* for the full response to complete.
|
||||
*/
|
||||
flush(): void
|
||||
|
||||
/**
|
||||
* write a Server-Sent Event and flush immediately.
|
||||
* Formats the output as SSE: "event: {event}\ndata: {data}\n\n"
|
||||
* If called with one argument, only "data: {data}\n\n" is written.
|
||||
*
|
||||
* @param event SSE event name (optional if using single-argument form)
|
||||
* @param data SSE data payload
|
||||
*/
|
||||
writeSSE(event: string, data: string): void
|
||||
writeSSE(data: string): void
|
||||
}
|
||||
|
||||
interface UserPackage {
|
||||
@@ -464,41 +903,7 @@ declare global {
|
||||
filter(
|
||||
sourceFile: string,
|
||||
targetFile: string,
|
||||
filters: {
|
||||
width?: number
|
||||
height?: number
|
||||
fit?: boolean
|
||||
fill?: boolean
|
||||
resampling?: "nearestNeighbor"
|
||||
| "hermite"
|
||||
| "linear"
|
||||
| "catmullRom"
|
||||
| "lanczos"
|
||||
| "box"
|
||||
| "mitchellNetravili"
|
||||
| "bSpline"
|
||||
| "gaussian"
|
||||
| "bartlett"
|
||||
| "hann"
|
||||
| "hamming"
|
||||
| "blackman"
|
||||
| "welch"
|
||||
| "cosine"
|
||||
anchor?: "center" | "topLeft" | "top" | "topRight" | "left" | "right" | "bottomLeft" | "bottom" | "bottomRight"
|
||||
brightness?: number
|
||||
saturation?: number
|
||||
contrast?: number
|
||||
gamma?: number
|
||||
blur?: number
|
||||
sharpen?: number
|
||||
invert?: boolean
|
||||
grayscale?: boolean
|
||||
quality?: number
|
||||
lossless?: boolean
|
||||
skipLargerDimensions?: boolean
|
||||
skipLargerFilesize?: boolean
|
||||
outputType?: "jpg" | "jpeg" | "png" | "webp"
|
||||
}[]
|
||||
filters: ImageFilterParams[]
|
||||
): void
|
||||
}
|
||||
|
||||
@@ -509,10 +914,13 @@ declare global {
|
||||
* @param data object or array (map with string keys as nodes (-KEY will be attribute in parent node))
|
||||
* @param options options
|
||||
*/
|
||||
create(data: {[key: string]: any}, options?: {
|
||||
rootElement?: string
|
||||
includeHeader?: boolean
|
||||
}): string
|
||||
create(
|
||||
data: { [key: string]: any },
|
||||
options?: {
|
||||
rootElement?: string
|
||||
includeHeader?: boolean
|
||||
}
|
||||
): string
|
||||
|
||||
/**
|
||||
* parse xml string to json
|
||||
@@ -689,45 +1097,224 @@ declare global {
|
||||
}
|
||||
|
||||
interface ExecPackage {
|
||||
command(cmd: string, options?: {
|
||||
args?: string[]
|
||||
stdin?: string
|
||||
dir?: string
|
||||
env?: string[]
|
||||
timeout?: number
|
||||
returnObject?: boolean
|
||||
combineOutput?: boolean
|
||||
}): string
|
||||
command(
|
||||
cmd: string,
|
||||
options?: {
|
||||
args?: string[]
|
||||
stdin?: string
|
||||
dir?: string
|
||||
env?: string[]
|
||||
timeout?: number
|
||||
returnObject?: boolean
|
||||
combineOutput?: boolean
|
||||
}
|
||||
): string
|
||||
|
||||
command<T extends {
|
||||
args?: string[]
|
||||
stdin?: string
|
||||
dir?: string
|
||||
env?: string[]
|
||||
timeout?: number
|
||||
returnObject?: boolean
|
||||
combineOutput?: boolean
|
||||
}>(cmd: string, options: T):
|
||||
T['returnObject'] extends true
|
||||
? T['combineOutput'] extends true
|
||||
? { output: string; exitCode: number }
|
||||
: { stdout: string; stderr: string; exitCode: number }
|
||||
: string
|
||||
command<
|
||||
T extends {
|
||||
args?: string[]
|
||||
stdin?: string
|
||||
dir?: string
|
||||
env?: string[]
|
||||
timeout?: number
|
||||
returnObject?: boolean
|
||||
combineOutput?: boolean
|
||||
},
|
||||
>(
|
||||
cmd: string,
|
||||
options: T
|
||||
): T["returnObject"] extends true
|
||||
? T["combineOutput"] extends true
|
||||
? { output: string; exitCode: number }
|
||||
: { stdout: string; stderr: string; exitCode: number }
|
||||
: string
|
||||
}
|
||||
|
||||
interface Base64Package {
|
||||
encode(data: string|Int8Array): string
|
||||
encode(data: string | Int8Array): string
|
||||
decode(data: string): string
|
||||
decode(data: string, options: {returnBytes: true}): Int8Array
|
||||
decode(data: string, options: {returnBytes: false}): string
|
||||
decode(data: string, options: {returnBytes?: boolean}): string | Int8Array
|
||||
decode(data: string, options: { returnBytes: true }): Int8Array
|
||||
decode(data: string, options: { returnBytes: false }): string
|
||||
decode(
|
||||
data: string,
|
||||
options: { returnBytes?: boolean }
|
||||
): string | Int8Array
|
||||
}
|
||||
|
||||
/**
|
||||
* Project-scoped in-memory cache.
|
||||
*
|
||||
* Entries survive across requests but are cleared on project reload.
|
||||
* Configured via project config `hook.cache` or server config `hook.cache`.
|
||||
*/
|
||||
interface CachePackage {
|
||||
/**
|
||||
* Store a value in the cache.
|
||||
*
|
||||
* @param key Cache key
|
||||
* @param value Any JSON-serializable value
|
||||
* @param ttlMs Optional time-to-live in milliseconds (overrides defaultTTL)
|
||||
*/
|
||||
set(key: string, value: any, ttlMs?: number): void
|
||||
|
||||
/**
|
||||
* Retrieve a value from the cache.
|
||||
*
|
||||
* @param key Cache key
|
||||
* @returns The cached value, or `null` if not found / expired.
|
||||
*/
|
||||
get(key: string): any | null
|
||||
|
||||
/**
|
||||
* Check whether a key exists (and is not expired) in the cache.
|
||||
*
|
||||
* @param key Cache key
|
||||
*/
|
||||
has(key: string): boolean
|
||||
|
||||
/**
|
||||
* Delete a single key from the cache.
|
||||
*
|
||||
* @param key Cache key
|
||||
* @returns `true` if the key existed, `false` otherwise.
|
||||
*/
|
||||
delete(key: string): boolean
|
||||
|
||||
/**
|
||||
* Remove all entries from the cache.
|
||||
*/
|
||||
clear(): void
|
||||
|
||||
/**
|
||||
* Return the number of entries currently in the cache.
|
||||
*/
|
||||
count(): number
|
||||
}
|
||||
|
||||
/**
|
||||
* Project-scoped rate limiter with two strategies:
|
||||
* - **Backoff**: Exponential back-off per key (e.g. login brute-force protection).
|
||||
* - **Window**: Sliding-window counter per key (e.g. API call quotas).
|
||||
*
|
||||
* Configured via project config `hook.ratelimit` or server config `hook.ratelimit`.
|
||||
*/
|
||||
interface RatelimitPackage {
|
||||
/**
|
||||
* Check whether a key is currently blocked by the exponential back-off strategy.
|
||||
*
|
||||
* @param key Rate-limit key (e.g. IP address or user ID)
|
||||
* @returns `{ blocked, retryAfterMs }` — if blocked, retryAfterMs indicates how long to wait.
|
||||
*/
|
||||
backoffCheck(key: string): { blocked: boolean; retryAfterMs: number }
|
||||
|
||||
/**
|
||||
* Record a failure for the given key, increasing its back-off delay.
|
||||
*
|
||||
* @param key Rate-limit key
|
||||
*/
|
||||
backoffRecord(key: string): void
|
||||
|
||||
/**
|
||||
* Reset the back-off state for a key (e.g. after a successful login).
|
||||
*
|
||||
* @param key Rate-limit key
|
||||
*/
|
||||
backoffReset(key: string): void
|
||||
|
||||
/**
|
||||
* Check the sliding-window strategy for a key.
|
||||
*
|
||||
* @param key Rate-limit key
|
||||
* @returns `{ allowed, retryAfterMs }` — if not allowed, retryAfterMs indicates how long to wait.
|
||||
*/
|
||||
windowCheck(key: string): { allowed: boolean; retryAfterMs: number }
|
||||
|
||||
/**
|
||||
* Reset the sliding-window counter for a key.
|
||||
*
|
||||
* @param key Rate-limit key
|
||||
*/
|
||||
windowReset(key: string): void
|
||||
|
||||
/**
|
||||
* Return the current hit count in the sliding window for a key.
|
||||
*
|
||||
* @param key Rate-limit key
|
||||
*/
|
||||
windowCount(key: string): number
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for channel.subscribe().
|
||||
*/
|
||||
interface ChannelSubscribeOptions {
|
||||
/** Maximum number of buffered messages per subscriber (default: 64). */
|
||||
bufferSize?: number
|
||||
/**
|
||||
* Behaviour when the buffer is full.
|
||||
* - "drop-oldest" (default): discard the oldest message
|
||||
* - "drop-newest": discard the incoming message
|
||||
*/
|
||||
onFull?: "drop-oldest" | "drop-newest"
|
||||
/** Time-to-live per message in milliseconds. Expired messages are skipped on receive. */
|
||||
messageTTL?: number
|
||||
/** Replay the last N messages from the channel's ring-buffer to the new subscriber. */
|
||||
lastN?: number
|
||||
/** Replay only messages younger than maxAge milliseconds. */
|
||||
maxAge?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* A subscription to a real-time channel.
|
||||
* Returned by channel.subscribe().
|
||||
*/
|
||||
interface ChannelSubscription {
|
||||
/**
|
||||
* Blocks until a message arrives, the client disconnects, or the
|
||||
* subscription/channel is closed.
|
||||
*
|
||||
* @returns The message data, or `null` when the client disconnects.
|
||||
* @throws `{error: string, code: "channel_closed"}` when the
|
||||
* subscription or channel is closed (e.g. project reload).
|
||||
*/
|
||||
receive(): any
|
||||
/** Manually close the subscription (idempotent). */
|
||||
close(): void
|
||||
}
|
||||
|
||||
/**
|
||||
* Real-time pub/sub channel package.
|
||||
*
|
||||
* Channels are in-memory, project-scoped, and named freely (not bound
|
||||
* to collections). Every subscriber receives an independent deep-copy
|
||||
* of each message.
|
||||
*/
|
||||
interface ChannelPackage {
|
||||
/**
|
||||
* Subscribe to a named channel. The calling hook will block until
|
||||
* the client disconnects or the subscription is closed.
|
||||
* The execution timeout is automatically disabled for hooks that subscribe.
|
||||
*
|
||||
* @param name Channel name (arbitrary string).
|
||||
* @param options Optional subscribe options.
|
||||
*/
|
||||
subscribe(
|
||||
name: string,
|
||||
options?: ChannelSubscribeOptions
|
||||
): ChannelSubscription
|
||||
/**
|
||||
* Publish data to all current subscribers of a named channel.
|
||||
* This is a fire-and-forget operation; if no one is subscribed, the
|
||||
* message is buffered in the channel's ring-buffer for future replay.
|
||||
*
|
||||
* @param name Channel name.
|
||||
* @param data Arbitrary data (will be deep-copied per subscriber).
|
||||
*/
|
||||
send(name: string, data: any): void
|
||||
}
|
||||
|
||||
export interface HookContext
|
||||
extends GetHookData,
|
||||
GetHookGetOnlyData,
|
||||
PostHookData,
|
||||
JobData {
|
||||
extends GetHookData, GetHookGetOnlyData, PostHookData, JobData {
|
||||
request(): {
|
||||
method: string
|
||||
remoteAddr: string
|
||||
@@ -745,17 +1332,11 @@ declare global {
|
||||
bodyBytes(): string
|
||||
}
|
||||
|
||||
api(): {
|
||||
[key: string]: any
|
||||
}
|
||||
api(): ApiInfo
|
||||
|
||||
project(): {
|
||||
[key: string]: any
|
||||
}
|
||||
project(): ProjectInfo
|
||||
|
||||
collection(): {
|
||||
[key: string]: any
|
||||
}
|
||||
collection(): CollectionInfo
|
||||
|
||||
config: ConfigPackage
|
||||
db: DbPackage
|
||||
@@ -777,6 +1358,9 @@ declare global {
|
||||
json: JsonPackage
|
||||
exec: ExecPackage
|
||||
base64: Base64Package
|
||||
channel: ChannelPackage
|
||||
cache: CachePackage
|
||||
ratelimit: RatelimitPackage
|
||||
}
|
||||
|
||||
export interface HookException {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "JSON Schema tibi-server collection configuration",
|
||||
"description": "tibi-server collection linter",
|
||||
"description": "tibi-server collection configuration",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {
|
||||
@@ -22,14 +22,39 @@
|
||||
"type": "string",
|
||||
"description": "relative to config.yml, path for file uploads"
|
||||
},
|
||||
"upload": {
|
||||
"type": "object",
|
||||
"description": "collection-specific upload defaults and restrictions",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"maxBodySize": {
|
||||
"type": "string",
|
||||
"description": "request body size limit override for this collection (e.g. '10MB')"
|
||||
},
|
||||
"allowedMimeTypes": {
|
||||
"type": "array",
|
||||
"description": "allowed MIME types for file uploads in this collection; empty means all types are allowed",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"oneOf": [
|
||||
{ "$comment": "for include tag", "type": "string" },
|
||||
{
|
||||
"$comment": "for include tag",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"description": "meta object used for admin ui configuration",
|
||||
"additionalProperties": true,
|
||||
"allOf": [{ "$ref": "collectionNavigation.json" }],
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "collectionNavigation.json"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"rowIdentTpl": {
|
||||
"description": "template which evaluates to short string to identify entry in pe. select boxes",
|
||||
@@ -57,6 +82,28 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"pagebuilder": {
|
||||
"type": "object",
|
||||
"description": "Collection-level pagebuilder defaults. These serve as fallbacks when field-level pagebuilder config omits them.",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"blockTypeField": {
|
||||
"type": "string",
|
||||
"description": "Name of the sub-field that holds the block type identifier. Default: 'blockType'. Used as fallback for all pagebuilder fields in this collection."
|
||||
},
|
||||
"blockRegistry": {
|
||||
"type": "object",
|
||||
"description": "Block registry configuration.",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "URL to an ES module that default-exports a BlockRegistry. Used as fallback for all pagebuilder fields in this collection."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,31 +111,54 @@
|
||||
},
|
||||
"projections": {
|
||||
"oneOf": [
|
||||
{ "$comment": "for include tag", "type": "string" },
|
||||
{ "$ref": "projections.json" }
|
||||
{
|
||||
"$comment": "for include tag",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"$ref": "projections.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"oneOf": [
|
||||
{ "$comment": "for include tag", "type": "string" },
|
||||
{ "$ref": "permissions.json" }
|
||||
{
|
||||
"$comment": "for include tag",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"$ref": "permissions.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"hooks": {
|
||||
"oneOf": [
|
||||
{ "$comment": "for include tag", "type": "string" },
|
||||
{ "$ref": "hooks.json" }
|
||||
{
|
||||
"$comment": "for include tag",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"$ref": "hooks.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"imageFilter": {
|
||||
"oneOf": [
|
||||
{ "$comment": "for include tag", "type": "string" },
|
||||
{ "$ref": "imageFilter.json" }
|
||||
{
|
||||
"$comment": "for include tag",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"$ref": "imageFilter.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fields": {
|
||||
"oneOf": [
|
||||
{ "$comment": "for include tag", "type": "string" },
|
||||
{
|
||||
"$comment": "for include tag",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"description": "fields of collection",
|
||||
@@ -108,7 +178,10 @@
|
||||
},
|
||||
"indexes": {
|
||||
"oneOf": [
|
||||
{ "$comment": "for include tag", "type": "string" },
|
||||
{
|
||||
"$comment": "for include tag",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"description": "indexes of collection",
|
||||
@@ -126,6 +199,32 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"bulk": {
|
||||
"type": "object",
|
||||
"description": "bulk operation configuration",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"optimize": {
|
||||
"type": "object",
|
||||
"description": "enable optimised single-DB-call bulk path without requiring a hook file",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"create": {
|
||||
"type": "boolean",
|
||||
"description": "POST with JSON array uses optimised InsertMany path"
|
||||
},
|
||||
"update": {
|
||||
"type": "boolean",
|
||||
"description": "PUT without ID uses optimised path"
|
||||
},
|
||||
"delete": {
|
||||
"type": "boolean",
|
||||
"description": "DELETE without ID uses optimised path"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cors": {
|
||||
"type": "object",
|
||||
"description": "cors configuration",
|
||||
@@ -172,7 +271,119 @@
|
||||
"description": "max age in seconds"
|
||||
}
|
||||
}
|
||||
},
|
||||
"audit": {
|
||||
"type": "object",
|
||||
"description": "audit logging configuration for this collection",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"description": "enable audit logging for this collection"
|
||||
},
|
||||
"actions": {
|
||||
"type": "array",
|
||||
"description": "list of actions to audit (create, update, delete, bulkCreate, bulkUpdate, bulkDelete, get)",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"create",
|
||||
"update",
|
||||
"delete",
|
||||
"bulkCreate",
|
||||
"bulkUpdate",
|
||||
"bulkDelete",
|
||||
"get"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"queryLimits": {
|
||||
"type": "object",
|
||||
"description": "query limit configuration for GET requests",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"defaultLimit": {
|
||||
"type": "integer",
|
||||
"description": "default limit for GET queries if client doesn't specify one"
|
||||
},
|
||||
"maxLimit": {
|
||||
"type": "integer",
|
||||
"description": "maximum allowed limit for GET queries"
|
||||
}
|
||||
}
|
||||
},
|
||||
"readonlyFields": {
|
||||
"type": "array",
|
||||
"description": "fields that are read-only at collection level",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"hiddenFields": {
|
||||
"type": "array",
|
||||
"description": "fields that are hidden at collection level",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"search": {
|
||||
"type": "array",
|
||||
"description": "search configurations for the collection",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "search config name (used in query parameter qName)"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"description": "search mode",
|
||||
"enum": [
|
||||
"text",
|
||||
"regex",
|
||||
"eval",
|
||||
"filter"
|
||||
]
|
||||
},
|
||||
"fields": {
|
||||
"type": "array",
|
||||
"description": "fields to search in (for text/regex mode)",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"type": "object",
|
||||
"description": "meta information",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"eval": {
|
||||
"type": "string",
|
||||
"description": "JS eval expression (for eval mode)"
|
||||
},
|
||||
"filter": {
|
||||
"type": "object",
|
||||
"description": "MongoDB filter template (for filter mode)",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"mode"
|
||||
]
|
||||
}
|
||||
},
|
||||
"strictFields": {
|
||||
"type": "boolean",
|
||||
"description": "reject unknown fields not defined in the fields array"
|
||||
}
|
||||
},
|
||||
"required": ["name", "permissions"]
|
||||
}
|
||||
"required": [
|
||||
"name",
|
||||
"permissions"
|
||||
]
|
||||
}
|
||||
@@ -22,6 +22,61 @@
|
||||
"type": "string",
|
||||
"description": "image filter name used for image previews"
|
||||
},
|
||||
"viewHint": {
|
||||
"description": "default collection view hint or structured special view config",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"table",
|
||||
"cards",
|
||||
"media"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"navigation": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"nodesField": {
|
||||
"type": "string",
|
||||
"description": "root field containing the recursive node array"
|
||||
},
|
||||
"declaredTrees": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"label": {
|
||||
"$ref": "definitions.json#/definitions/i18nString"
|
||||
},
|
||||
"singleton": {
|
||||
"type": "object",
|
||||
"description": "root-level field values that identify one declared tree slot",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"maxLevel": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"singleton"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"navigation"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"muiIcon": {
|
||||
"type": "string",
|
||||
"description": "material ui icon name"
|
||||
|
||||
@@ -35,6 +35,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"upload": {
|
||||
"type": "object",
|
||||
"description": "project-wide upload defaults and restrictions",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"maxBodySize": {
|
||||
"type": "string",
|
||||
"description": "default request body size limit for collections in this project (e.g. '50MB')"
|
||||
},
|
||||
"allowedMimeTypes": {
|
||||
"type": "array",
|
||||
"description": "project-wide allowed MIME types for file uploads; empty means all types are allowed",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"collections": {
|
||||
"type": "array",
|
||||
"description": "list of collections in this project",
|
||||
@@ -150,6 +168,59 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"hook": {
|
||||
"type": "object",
|
||||
"description": "project-level hook configuration (cache and ratelimit)",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"cache": {
|
||||
"type": "object",
|
||||
"description": "hook cache configuration",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"maxEntries": {
|
||||
"type": "integer",
|
||||
"description": "maximum number of cache entries"
|
||||
},
|
||||
"defaultTTL": {
|
||||
"type": "string",
|
||||
"description": "default time-to-live (e.g. '5m', '1h')"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ratelimit": {
|
||||
"type": "object",
|
||||
"description": "hook ratelimit configuration",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"backoffInitialDelay": {
|
||||
"type": "string",
|
||||
"description": "initial backoff delay (e.g. '1s')"
|
||||
},
|
||||
"backoffMaxDelay": {
|
||||
"type": "string",
|
||||
"description": "maximum backoff delay (e.g. '5m')"
|
||||
},
|
||||
"backoffResetAfter": {
|
||||
"type": "string",
|
||||
"description": "reset backoff after this duration of no failures (e.g. '15m')"
|
||||
},
|
||||
"windowSize": {
|
||||
"type": "string",
|
||||
"description": "sliding window size (e.g. '1m')"
|
||||
},
|
||||
"windowMaxHits": {
|
||||
"type": "integer",
|
||||
"description": "maximum hits allowed per window"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strictFields": {
|
||||
"type": "boolean",
|
||||
"description": "reject unknown fields not defined in the fields array (project-wide default)"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"object",
|
||||
"object[]",
|
||||
"file",
|
||||
"file[]",
|
||||
"date",
|
||||
"any"
|
||||
]
|
||||
@@ -32,7 +33,13 @@
|
||||
"index": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"enum": ["single", "unique", "text"]
|
||||
"enum": [
|
||||
"single",
|
||||
"unique",
|
||||
"text",
|
||||
"sparse",
|
||||
"background"
|
||||
]
|
||||
}
|
||||
},
|
||||
"subFields": {
|
||||
@@ -74,12 +81,82 @@
|
||||
"eval": {
|
||||
"type": "string",
|
||||
"description": "javascript validator which failes if evaluates to false or string as error message, with following variables: $this, $parent, $stack, $auth, context"
|
||||
},
|
||||
"minLength": {
|
||||
"type": "number",
|
||||
"description": "minimum string length"
|
||||
},
|
||||
"maxLength": {
|
||||
"type": "number",
|
||||
"description": "maximum string length"
|
||||
},
|
||||
"pattern": {
|
||||
"type": "string",
|
||||
"description": "regex pattern the value must match"
|
||||
},
|
||||
"min": {
|
||||
"type": "number",
|
||||
"description": "minimum value for number fields"
|
||||
},
|
||||
"max": {
|
||||
"type": "number",
|
||||
"description": "maximum value for number fields"
|
||||
},
|
||||
"in": {
|
||||
"type": "array",
|
||||
"description": "array of allowed values"
|
||||
},
|
||||
"maxFileSize": {
|
||||
"type": "string",
|
||||
"description": "maximum decoded file size for file and file[] fields (e.g. '500KB')"
|
||||
},
|
||||
"accept": {
|
||||
"type": "array",
|
||||
"description": "allowed MIME types for file and file[] fields; supports wildcards like 'image/*'",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"readonly": {
|
||||
"description": "field-level readonly — boolean or JS eval expression",
|
||||
"oneOf": [
|
||||
{ "type": "boolean" },
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"eval": { "type": "string", "description": "JS expression that returns boolean" }
|
||||
},
|
||||
"required": ["eval"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"hidden": {
|
||||
"description": "field-level hidden — boolean or JS eval expression",
|
||||
"oneOf": [
|
||||
{ "type": "boolean" },
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"eval": { "type": "string", "description": "JS expression that returns boolean" }
|
||||
},
|
||||
"required": ["eval"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"strictFields": {
|
||||
"type": "boolean",
|
||||
"description": "reject unknown sub-fields not defined in subFields"
|
||||
},
|
||||
"meta": {
|
||||
"$ref": "fieldMeta.json"
|
||||
}
|
||||
},
|
||||
"required": ["name", "type"]
|
||||
}
|
||||
"required": [
|
||||
"name",
|
||||
"type"
|
||||
]
|
||||
}
|
||||
@@ -413,6 +413,171 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/minimum",
|
||||
"patternProperties": {
|
||||
"^x-.*|widget|pagebuilder$": {
|
||||
"$comment": "stub for allOf"
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"properties": {
|
||||
"widget": {
|
||||
"enum": [
|
||||
"pagebuilder",
|
||||
"pageBuilder"
|
||||
]
|
||||
},
|
||||
"pagebuilder": {
|
||||
"type": "object",
|
||||
"description": "Pagebuilder widget configuration. Field-level settings override collection-level fallbacks.",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"overlay",
|
||||
"inline",
|
||||
"both"
|
||||
],
|
||||
"description": "[Planned] Editor mode. Currently only 'overlay' is implemented. 'inline' and 'both' are planned."
|
||||
},
|
||||
"defaultViewport": {
|
||||
"type": "number",
|
||||
"description": "Default viewport width in pixels for the preview. Common presets: 1280 (Desktop), 768 (Tablet), 375 (Phone). Default: 1280. Overrides collection-level fallback."
|
||||
},
|
||||
"blockTypeField": {
|
||||
"type": "string",
|
||||
"description": "Name of the sub-field that holds the block type identifier. Default: 'blockType'. Overrides collection-level fallback."
|
||||
},
|
||||
"blockRegistry": {
|
||||
"type": "object",
|
||||
"description": "Block registry configuration for loading available block definitions.",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "URL to an ES module that default-exports a BlockRegistry (Record<string, BlockDefinition>). Overrides collection-level fallback."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/minimum",
|
||||
"patternProperties": {
|
||||
"^x-.*|widget|pagebuilder$": {
|
||||
"$comment": "stub for allOf"
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"properties": {
|
||||
"widget": {
|
||||
"enum": [
|
||||
"pagebuilder",
|
||||
"pageBuilder"
|
||||
]
|
||||
},
|
||||
"pagebuilder": {
|
||||
"type": "object",
|
||||
"description": "Pagebuilder widget configuration. Field-level settings override collection-level fallbacks.",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"overlay",
|
||||
"inline",
|
||||
"both"
|
||||
],
|
||||
"description": "[Planned] Editor mode. Currently only 'overlay' is implemented. 'inline' and 'both' are planned."
|
||||
},
|
||||
"defaultViewport": {
|
||||
"type": "number",
|
||||
"description": "Default viewport width in pixels for the preview. Common presets: 1280 (Desktop), 768 (Tablet), 375 (Phone). Default: 1280. Overrides collection-level fallback."
|
||||
},
|
||||
"blockTypeField": {
|
||||
"type": "string",
|
||||
"description": "Name of the sub-field that holds the block type identifier. Default: 'blockType'. Overrides collection-level fallback."
|
||||
},
|
||||
"blockRegistry": {
|
||||
"type": "object",
|
||||
"description": "Block registry configuration for loading available block definitions.",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "URL to an ES module that default-exports a BlockRegistry (Record<string, BlockDefinition>). Overrides collection-level fallback."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/minimum",
|
||||
"patternProperties": {
|
||||
"^x-.*|widget|pagebuilder$": {
|
||||
"$comment": "stub for allOf"
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"properties": {
|
||||
"widget": {
|
||||
"enum": [
|
||||
"pagebuilder",
|
||||
"pageBuilder"
|
||||
]
|
||||
},
|
||||
"pagebuilder": {
|
||||
"type": "object",
|
||||
"description": "Pagebuilder widget configuration. Field-level settings override collection-level fallbacks.",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"overlay",
|
||||
"inline",
|
||||
"both"
|
||||
],
|
||||
"description": "[Planned] Editor mode. Currently only 'overlay' is implemented. 'inline' and 'both' are planned."
|
||||
},
|
||||
"defaultViewport": {
|
||||
"type": "number",
|
||||
"description": "Default viewport width in pixels for the preview. Common presets: 1280 (Desktop), 768 (Tablet), 375 (Phone). Default: 1280. Overrides collection-level fallback."
|
||||
},
|
||||
"blockTypeField": {
|
||||
"type": "string",
|
||||
"description": "Name of the sub-field that holds the block type identifier. Default: 'blockType'. Overrides collection-level fallback."
|
||||
},
|
||||
"blockRegistry": {
|
||||
"type": "object",
|
||||
"description": "Block registry configuration for loading available block definitions.",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "URL to an ES module that default-exports a BlockRegistry (Record<string, BlockDefinition>). Overrides collection-level fallback."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"definitions": {
|
||||
@@ -721,18 +886,27 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"size": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"default": {
|
||||
"type": "string"
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "shorthand: single size for all breakpoints (e.g. col-3)"
|
||||
},
|
||||
"small": {
|
||||
"type": "string"
|
||||
},
|
||||
"large": {
|
||||
"type": "string"
|
||||
{
|
||||
"type": "object",
|
||||
"description": "responsive sizes per breakpoint",
|
||||
"properties": {
|
||||
"default": {
|
||||
"type": "string"
|
||||
},
|
||||
"small": {
|
||||
"type": "string"
|
||||
},
|
||||
"large": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -794,6 +968,62 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget": {
|
||||
"type": "string",
|
||||
"description": "widget type for rendering the field in admin UI"
|
||||
},
|
||||
"position": {
|
||||
"type": "string",
|
||||
"description": "field position in the editor layout: 'main' (default), 'sidebar' (default settings card), or 'sidebar:<group>' (named sidebar card, e.g. 'sidebar:SEO')"
|
||||
},
|
||||
"section": {
|
||||
"description": "section grouping for the field in the editor",
|
||||
"$ref": "definitions.json#/definitions/i18nString"
|
||||
},
|
||||
"choices": {
|
||||
"description": "choices for select/chipArray/checkboxArray widgets",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
},
|
||||
"foreign": {
|
||||
"type": "object",
|
||||
"description": "foreign key configuration for foreignKey/foreignFile widgets"
|
||||
},
|
||||
"downscale": {
|
||||
"type": "object",
|
||||
"description": "image downscale configuration for file/image widgets",
|
||||
"properties": {
|
||||
"maxWidth": {
|
||||
"type": "number",
|
||||
"description": "maximum width in pixels"
|
||||
},
|
||||
"maxHeight": {
|
||||
"type": "number",
|
||||
"description": "maximum height in pixels"
|
||||
},
|
||||
"quality": {
|
||||
"type": "number",
|
||||
"description": "JPEG quality (0-100)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"drillDown": {
|
||||
"type": "boolean",
|
||||
"description": "whether object subFields should be rendered inline (false) or as drill-down navigation (true, default)"
|
||||
},
|
||||
"readonly": {
|
||||
"type": "boolean",
|
||||
"description": "if true, the field is displayed as a read-only view (table/card style) instead of an editable widget. Use inputProps for a disabled input instead."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -841,4 +1071,4 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "JSON Schema tibi-server hooks configuration",
|
||||
"description": "tibi-server hooks linter",
|
||||
"description": "tibi-server hooks configuration",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {
|
||||
@@ -22,6 +22,10 @@
|
||||
"return": {
|
||||
"description": "hook before returning entries read from database",
|
||||
"$ref": "#/definitions/hookDef"
|
||||
},
|
||||
"file": {
|
||||
"description": "hook for file download requests (GET /collection/:id/:field/*path)",
|
||||
"$ref": "#/definitions/hookDef"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -45,6 +49,14 @@
|
||||
"return": {
|
||||
"description": "hook before returning result (after database write)",
|
||||
"$ref": "#/definitions/hookDef"
|
||||
},
|
||||
"bulkCreate": {
|
||||
"description": "hook for bulk create (POST with JSON array) — optimised single-DB-call path",
|
||||
"$ref": "#/definitions/hookDef"
|
||||
},
|
||||
"bulkReturn": {
|
||||
"description": "hook before returning bulk create result",
|
||||
"$ref": "#/definitions/hookDef"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -68,6 +80,14 @@
|
||||
"return": {
|
||||
"description": "hook before returning result (after database write)",
|
||||
"$ref": "#/definitions/hookDef"
|
||||
},
|
||||
"bulkUpdate": {
|
||||
"description": "hook for bulk update (PUT without ID) — optimised single-DB-call path",
|
||||
"$ref": "#/definitions/hookDef"
|
||||
},
|
||||
"bulkReturn": {
|
||||
"description": "hook before returning bulk update result",
|
||||
"$ref": "#/definitions/hookDef"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -83,6 +103,25 @@
|
||||
"return": {
|
||||
"description": "hook before returning result (after database write)",
|
||||
"$ref": "#/definitions/hookDef"
|
||||
},
|
||||
"bulkDelete": {
|
||||
"description": "hook for bulk delete (DELETE without ID) — optimised single-DB-call path",
|
||||
"$ref": "#/definitions/hookDef"
|
||||
},
|
||||
"bulkReturn": {
|
||||
"description": "hook before returning bulk delete result",
|
||||
"$ref": "#/definitions/hookDef"
|
||||
}
|
||||
}
|
||||
},
|
||||
"audit": {
|
||||
"type": "object",
|
||||
"description": "hooks for audit log entries",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"return": {
|
||||
"description": "hook before returning audit log entries for this collection, can be used to remove sensitive fields from snapshots",
|
||||
"$ref": "#/definitions/hookDef"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,6 +136,10 @@
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "location of javascript hook file relative to config.yml base"
|
||||
},
|
||||
"timeout": {
|
||||
"type": "integer",
|
||||
"description": "execution timeout in seconds"
|
||||
}
|
||||
},
|
||||
"required": ["type", "file"]
|
||||
|
||||
@@ -52,18 +52,48 @@
|
||||
"enum": [
|
||||
"lanczos",
|
||||
"nearestNeighbor",
|
||||
"hermite",
|
||||
"linear",
|
||||
"catmullRom"
|
||||
"catmullRom",
|
||||
"box",
|
||||
"mitchellNetravili",
|
||||
"bSpline",
|
||||
"gaussian",
|
||||
"bartlett",
|
||||
"hann",
|
||||
"hamming",
|
||||
"blackman",
|
||||
"welch",
|
||||
"cosine"
|
||||
]
|
||||
},
|
||||
"anchor": {
|
||||
"enum": [
|
||||
"center",
|
||||
"topLeft",
|
||||
"top",
|
||||
"topRight",
|
||||
"left",
|
||||
"right",
|
||||
"bottomLeft",
|
||||
"bottom",
|
||||
"bottomRight"
|
||||
]
|
||||
},
|
||||
"quality": {
|
||||
"type": "number"
|
||||
},
|
||||
"lossless": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"skipLargerDimension": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"skipLargerFilesize": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"outputType": {
|
||||
"enum": ["jpg", "jpeg", "png", "webp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "javascript file relative to config.yml"
|
||||
},
|
||||
"timeout": {
|
||||
"type": "integer",
|
||||
"description": "execution timeout in seconds"
|
||||
}
|
||||
},
|
||||
"required": ["type", "file"]
|
||||
|
||||
@@ -38,14 +38,85 @@
|
||||
"description": "permissions for http methods",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"get": { "type": "boolean" },
|
||||
"post": { "type": "boolean" },
|
||||
"put": { "type": "boolean" },
|
||||
"delete": { "type": "boolean" }
|
||||
"get": {
|
||||
"oneOf": [
|
||||
{ "type": "boolean" },
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"allow": { "type": "boolean", "description": "Allow GET." }
|
||||
},
|
||||
"required": ["allow"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"post": {
|
||||
"oneOf": [
|
||||
{ "type": "boolean" },
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"allow": { "type": "boolean", "description": "Allow single-document POST." },
|
||||
"bulk": { "type": "boolean", "description": "Allow bulk POST (JSON array body)." }
|
||||
},
|
||||
"required": ["allow"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"put": {
|
||||
"oneOf": [
|
||||
{ "type": "boolean" },
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"allow": { "type": "boolean", "description": "Allow single-document PUT." },
|
||||
"bulk": { "type": "boolean", "description": "Allow bulk PUT (without ID)." }
|
||||
},
|
||||
"required": ["allow"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"delete": {
|
||||
"oneOf": [
|
||||
{ "type": "boolean" },
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"allow": { "type": "boolean", "description": "Allow single-document DELETE." },
|
||||
"bulk": { "type": "boolean", "description": "Allow bulk DELETE (without ID)." }
|
||||
},
|
||||
"required": ["allow"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"validProjections": {
|
||||
"type": "array",
|
||||
"description": "list of projection names this permission set is allowed to use",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"filter": {
|
||||
"type": "object",
|
||||
"description": "MongoDB filter applied to all queries for this permission set",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"readonlyFields": {
|
||||
"type": "array",
|
||||
"description": "fields that are read-only for this permission set",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"hiddenFields": {
|
||||
"type": "array",
|
||||
"description": "fields that are hidden for this permission set",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user