7.2.261-stable

std > runtime > Source

@permission("public", "default, associated with anonymous users");
@permission("admin", "allows to administrate anything on the server");
@permission("api", "allows access to exposed functions and webroot files");
@permission("debug", "allows access to low-level graph manipulation functions");
@permission("files", "allows access to files under /files/* or webroot according to ACL");

@role("public", "public");
@role("admin", "public", "admin", "api", "debug", "files");
@role("user", "public", "api", "files");

/// Unit of access control, attached to functions
private type Permission {
    name: String;
    description: String;

    @expose
    @permission("admin")
    static native fn all(): Array<Permission>;
}

/// Aggregation of permissions to be associated to a user
private type Role {
    name: String;
    permissions: Array<String>;

    @expose
    @permission("admin")
    static native fn all(): Array<Role>;
}

/// Unit of computation executed in parallel awaited by a parent Task
type Job<T> {
    function: core::function;
    arguments: Array<any?>?;
    native fn result(): T;
}

/// The strategy applies to merge node updates from job to task or task to the main graph.
enum MergeStrategy {
    /// All or nothing. Every node update must be free of conflicts with concurrent changes; otherwise, an exception is thrown.
    /// This should be considered the default mode, as it offers the strongest guarantee of consistency.
    strict;
    /// Partial strategy making merge not crash on concurrent conflicts.
    ///All node updates are applied and conflicts are resolved using the previously inserted values in a graph.
    first_wins;
    /// Partial strategy making merge not crash on concurrent conflicts.
    /// All node updates are applied and conflicts are resolved by overriding previously inserted values by current ones.
    last_wins;
}

native fn await(jobs: Array<Job>, strategy: MergeStrategy);

/// log levels used in log files
enum LogLevel {
    error;
    warn;
    info;
    perf;
    trace;
}

/// log structure useful for parsing
@volatile
type Log {
    level: LogLevel;
    time: time;
    user_id: int?;
    id: int?;
    id2: int?;
    src: function?;
    data: any?;
}

@volatile
type LogDataUsage {
    read_bytes: int;
    read_hits: int;
    read_wasted: int;
    write_bytes: int;
    write_hits: int;
    cache_bytes: int;
    cache_hits: int;
}

@volatile
type RuntimeInfo {
    version: String;
    program_version: String?;
    arch: String;
    timezone: TimeZone;
    license: License;
    io_threads: int;
    bg_threads: int;
    fg_threads: int;
    mem_total: int;
    mem_worker: int;
    disk_data_bytes: int;
}

type Runtime {
    @expose
    @permission("debug")
    static native fn info(): RuntimeInfo;

    @expose
    @reserved
    @permission("api")
    static native fn abi();

    @expose
    @permission("api")
    static native fn openapi(): any;

    @expose
    @permission("debug")
    static native fn root(): any;

    /// Puts the current thread to sleep for at least the given duration
    static native fn sleep(d: duration);

    /// Perform full backup even if incremental delta are present in backup directory
    static native fn backup_full();

    /// Perform incremental backup based on delta present in backup directory
    static native fn backup_delta();

    /// Trigger a defrag process
    static native fn defrag();

}

// type ChildProcess {
//   pid: int;
// }

type System {
    /// Executes the given command as a subprocess.
    /// Returns the content of stdout.
    /// If an error occurs the exception will contain the content of stderr.
    static native fn exec(path: String, params: Array<String>): String;
    /// Spawns the given command as a subprocess and yields its pid.
    ///
    /// Contrary to `System::exec` this method does not actively wait for the process to finish.
     // static native fn spawn(path: String, params: Array<String>): ChildProcess;
    /// get local configured TimeZone
    static native fn tz(): TimeZone;
    static native fn getEnv(key: String): String?;
}

enum TaskStatus {
    empty;
    waiting;
    running;
    await;
    cancelled;
    error;
    ended;
    ended_with_errors;
}

type Task {
    user_id: int;
    task_id: int;
    mod: String?;
    type: String?;
    fun: String?;
    creation: time;
    start: time?;
    duration: duration?;
    status: TaskStatus;
    progress: float?;

    /// set globally the progress for parent task, accepted value are between 0 and 1.
    static native fn progress(progress: float);
    static native fn parentId(): int;
    static native fn id(): int;

    @expose
    @reserved
    static native fn running(): Array<Task>;
    @expose
    @reserved
    static native fn history(offset: int, max: int): Array<Task>;
    @expose
    @reserved
    static native fn cancel(task_id: int): bool;
    @expose
    @reserved
    static native fn is_running(task_id: int): bool;
}

type SecurityFields {
    email: String?;
    name: String?;
    first_name: String?;
    last_name: String?;
    roles: Map<String, String>?;
    groups: Map<String, String>?;

    @expose
    @permission("admin")
    static native fn set(f: SecurityFields);

    @expose
    @permission("admin")
    static native fn get(): SecurityFields?;
}

type SecurityPolicy {
    entities: Array<SecurityEntity>?;
    credentials: Map<String, UserCredential>?;
    fields: SecurityFields?;
    keys: Map<String, String>?;
    keys_last_refresh: time?;
}

abstract type SecurityEntity {
    id: int;
    name: String;
    activated: bool;

    @expose
    @reserved
    @permission("admin")
    static native fn all(): Array<SecurityEntity>;

    @expose
    @permission("admin")
    static native fn set(entity: SecurityEntity): int?;
}

type UserGroup extends SecurityEntity {}

enum UserGroupPolicyType {
    read;
    write;
    execute;
}

type UserGroupPolicy {
    group_id: int;
    type: UserGroupPolicyType;
}

type OpenIDConnect {
    url: String;
    clientId: String;

    /// get current configuration to enable OpenID connect capability
    @reserved
    @expose
    @permission("public")
    static native fn config(): OpenIDConnect?;
}

type User extends SecurityEntity {
    full_name: String?;
    email: String?;
    role: String?;
    groups: Array<UserGroupPolicy>?;
    groups_flags: int?;
    external: bool;

    /// If the given `credentials` are valid, returns a session `token`.
    ///
    /// If `use_cookie` is `true`, the HTTP Response Headers will contain
    /// a `Set-Cookie: greycat=<TOKEN> (...)`
    ///
    /// This token can then be used by HTTP clients:
    /// - as a bearer: `Authorization: <TOKEN>` _(note that 'bearer' is not specified)_
    /// - as a cookie: `Cookie: greycat=<TOKEN>`
    @expose
    @reserved
    @permission("public")
    static native fn login(credentials: String, use_cookie: bool): String;

    /// If the given JWT `token` is valid (signed with the public key provided), returns a Greycat session `token`.
    ///
    /// If `use_cookie` is `true`, the HTTP Response Headers will contain
    /// a `Set-Cookie: greycat=<TOKEN> (...)`
    ///
    /// This token can then be used by HTTP clients:
    /// - as a bearer: `Authorization: <TOKEN>` _(note that 'bearer' is not specified)_
    /// - as a cookie: `Cookie: greycat=<TOKEN>`
    @expose
    @reserved
    @permission("public")
    static native fn tokenLogin(token: String, use_cookie: bool): String;

    /// logout cookie
    @expose
    @reserved
    @permission("public")
    static native fn logout();

    /// renew cookie
    @expose
    @reserved
    @permission("api")
    static native fn renew(use_cookie: bool): String;

    /// Returns the currently logged-in user id.
    @expose
    @reserved
    @permission("public")
    static native fn current(): int;

    /// Returns the currently logged-in user.
    @expose
    @reserved
    @permission("public")
    static native fn me(): User;

    /// Returns the list of permissions of the currently logged-in user.
    @expose
    @reserved
    @permission("public")
    static native fn permissions(): Array<String>;

    /// Returns `true` if the current connected user has the permission associated to the name passed as parameter, false otherwise.
    static native fn hasPermission(permission: String): bool;

    @expose
    @permission("admin")
    /// Updates the password of the user `name`. If the user does not exist, `false` is returned.
    static native fn setPassword(name: String, pass: String): bool;

    static native fn getByName(name: String): User?;

    static native fn get(id: int): User?;

    /// Validates the password of the user `name`, if the user does not exist or the password does not match, `false` is returned.
    static native fn checkPassword(name: String, pass: String): bool;
}

private type UserCredential {
    offset: int;
    pass: String?;
}

enum LicenseType {
    community;
    enterprise;
    testing;
}

type License {
    /// Associated username
    name: String?;
    /// Start of license validity
    start: time;
    /// End of license validity
    end: time;
    /// Associated company name
    company: String?;
    /// Maximum allowed memory in MB
    max_memory: int;
    extra_1: int?;
    extra_2: int?;
    /// type of license
    type: LicenseType?;
}

/// Checkpoint frame variable, named by program origin name if any
private type Variable {
    name: String?;
    value: any?;
}

/// Checkpoint stack frame, representing nested function call
private type Frame {
    module: String?;
    type: String?;
    function: String?;
    src: String?;
    line: int;
    column: int;
    scope: Array<Variable>;
}

/// Checkpoint snapshots, containing frames themselves containing variables
private type Debug {
    id: int;
    frames: Array<Frame>;
    root: any;

    @expose
    @permission("debug")
    @reserved
    native static fn all(): Array<int>;

    @expose
    @permission("debug")
    @reserved
    native static fn get(id: int): Debug;

    @expose
    @permission("debug")
    @reserved
    native static fn resume(id: int);
}

/// A global manager of periodic tasks.
/// 
/// The scheduler maintains a registry of functions and their associated periodic execution rules.
/// Each function can only have one scheduled task at a time - adding a new task with the same
/// function will replace any existing task.
type Scheduler {
    /// Schedules a function to be executed as a task periodically.
    ///
    /// If a task with the same `function` already exists, it will be replaced with the new
    /// configuration. The scheduler uses function pointer equality for task identification.
    ///
    /// Examples:
    /// ```gcl
    /// // Schedule a backup every day at 2 AM
    /// Scheduler::add(
    ///     backup_database,
    ///     DailyPeriodicity { hour: 2 },
    ///     null,
    /// );
    /// 
    /// // Schedule health checks every 5 minutes, starting in 1 hour
    /// Scheduler::add(
    ///     health_check,
    ///     FixedPeriodicity { every: 5min },
    ///     PeriodicOptions { 
    ///         start: time::now() + 1hour,
    ///         max_duration: 30s
    ///     }
    /// );
    /// ```
    @expose
    @permission("admin")
    static native fn add(function: function, periodicity: Periodicity, options: PeriodicOptions?);

    /// Returns the current list of all scheduled tasks.
    /// 
    /// The returned array includes both active and inactive tasks.
    /// Use `PeriodicTask.is_active` to check individual task status.
    @expose
    @permission("admin")
    static native fn list(): Array<PeriodicTask>;

    /// Looks for a task that matches the given `function`.
    /// 
    /// Returns `null` if no matching task is found.
    /// Uses function pointer equality for matching.
    @expose
    @permission("admin")
    static native fn find(function: function): PeriodicTask?;

    /// Tries to find a task that matches `function` and activates it.
    /// 
    /// Activating a task means it will be eligible for execution according to its periodicity.
    /// If the task was previously deactivated, it will resume from its next scheduled time.
    /// 
    /// Returns `true` if a matching task was found and activated, `false` otherwise.
    @expose
    @permission("admin")
    static native fn activate(function: function): bool;

    /// Tries to find a task that matches `function` and deactivates it.
    /// 
    /// Deactivating a task prevents it from being executed, but keeps the task configuration
    /// in the scheduler. The task can be reactivated later with `activate()`.
    /// 
    /// Returns `true` if a matching task was found and deactivated, `false` otherwise.
    @expose
    @permission("admin")
    static native fn deactivate(function: function): bool;

    // /// Removes a task completely from the scheduler.
    // /// 
    // /// Unlike `deactivate()`, this permanently removes the task configuration.
    // /// The function will no longer be scheduled for execution.
    // /// 
    // /// Returns `true` if a matching task was found and removed, `false` otherwise.
    // @expose
    // @permission("admin")
    // static native fn remove(function: function): bool;
}

/// Represents a scheduled periodic task in the system.
type PeriodicTask {
    /// The function that will be executed
    function: function;
    /// The periodicity configuration for this task
    periodicity: Periodicity;
    /// Current options applied to this task
    options: PeriodicOptions;
    /// Whether the task is currently active
    is_active: bool;
    /// Next scheduled execution time
    next_execution: time;
    /// Total number of times this task has been executed
    execution_count: int;
}

/// Configuration options for periodic tasks.
type PeriodicOptions {
    /// Whether or not the task can be executed.
    /// Defaults to `true` if not specified.
    activated: bool?;
    /// Will start the task lifecycle at that time.
    ///
    /// By default `time::now()` is used.
    /// If set to a future time, the first execution will be delayed accordingly.
    start: time?;
    /// The maximum duration a task should take before being forcefully cancelled.
    ///
    /// By default this is `null` meaning the task can run endlessly.
    /// 
    /// *Note that the timer starts as soon as a task is queued for execution.*
    /// *Note: a negative duration will be replaced by `null`*
    max_duration: duration?;
}

/// Base type for all periodicity definitions.
///
/// Cannot be instantiated directly - use one of the concrete implementations.
abstract type Periodicity {}

/// Defines tasks that repeat at fixed intervals.
///
/// Examples:
/// - Every 30 minutes: `FixedPeriodicity { every: 30min }`
/// - Every 2 hours: `FixedPeriodicity { every: 2hour }`
/// - Every day: `FixedPeriodicity { every: 24hour }`
type FixedPeriodicity extends Periodicity {
    /// The fixed interval between task executions
    every: duration;
}

/// Defines tasks daily execution parameters with specific time targeting.
/// All time fields default to 0 if not specified, resulting in midnight execution.
///
/// Examples:
/// - Run at 2:30 PM: `DailyPeriodicity { hour: 14, minute: 30 }`
/// - Run at midnight: `DailyPeriodicity {}` (all defaults)
/// - Run at 9 AM Europe/Luxembourg: `DailyPeriodicity { hour: 9, timezone: TimeZone::"Europe/Luxembourg" }`
type DailyPeriodicity extends Periodicity {
    /// Hour of execution (0-23). Defaults to midnight if not specified
    hour: int?;
    /// Minute of execution (0-59). Defaults to 0 if not specified
    minute: int?;
    /// Second of execution (0-59). Defaults to 0 if not specified
    second: int?;
    /// Timezone for time calculation. Uses the host timezone if not specified
    timezone: TimeZone?;
}

/// Defines tasks that run on specific days of the week.
/// 
/// Examples:
/// - Every Monday and Friday at 9 AM:
///   ```gcl
///   WeeklyPeriodicity {
///     days: [DayOfWeek::Mon, DayOfWeek::Fri],
///     dayly: DailyPeriodicity { hour: 9 }
///   }
///   ```
/// - Every weekday at default time:
///   ```gcl
///   WeeklyPeriodicity {
///     days: [DayOfWeek::Mon, DayOfWeek::Tue, DayOfWeek::Wed, DayOfWeek::Thu, DayOfWeek::Fri]
///   }
///   ```
type WeeklyPeriodicity extends Periodicity {
    /// Array of weekdays when the task should run
    days: Array<DayOfWeek>;
    /// Optional daily periodicity. Defaults to midnight if not provided.
    daily: DailyPeriodicity?;
}

/// Defines tasks that run monthly on specific days.
///
/// Examples:
/// - 15th of every month at 2 PM:
///   ```gcl
///   MonthlyPeriodicity {
///     days: [15],
///     daily: DailyPeriodicity { hour: 14 }
///   }
///   ```
/// - Every first day and last day of the month at midnight:
///   ```gcl
///   MonthlyPeriodicity {
///     days: [1, -1]
///   }
///   ```
/// - Three days a month at 9:30 PM:
///   ```gcl
///   MonthlyPeriodicity {
///     days: [1, 15, -1],
///     daily: DailyPeriodicity { hour: 9, minute: 30 }
///   }
///   ```
type MonthlyPeriodicity extends Periodicity {
    /// Array of days in the month when the task should run.
    /// Positive values (1-31) count from start of month.
    /// Negative values (-1 to -31) count from end of month (-1 = last day).
    /// Invalid days for shorter months are skipped (e.g., day 31 in February).
    days: Array<int>;
    /// Optional daily timing specification. Defaults to midnight if not provided.
    daily: DailyPeriodicity?;
}

/// Defines tasks that run on specific calendar dates each year.
/// 
/// Examples:
/// - New Year's Day and Christmas:
///   ```gcl
///   YearlyPeriodicity {
///     dates: [
///       DateTuple { day: 1, month: Jan },
///       DateTuple { day: 25, month: Dec }
///     ]
///   }
///   ```
/// - Quarterly reports (1st of each quarter):
///   ```gcl
///   YearlyPeriodicity {
///     dates: [
///       DateTuple { day: 1, month: Jan },
///       DateTuple { day: 1, month: Apr },
///       DateTuple { day: 1, month: Jul },
///       DateTuple { day: 1, month: Oct }
///     ]
///   }
///   ```
type YearlyPeriodicity extends Periodicity {
    /// Array of specific dates (day + month) when the task should run
    dates: Array<DateTuple>;
    /// Timezone for date calculation. Uses the host timezone if not specified
    timezone: TimeZone?;
}

enum DayOfWeek {
    Mon(0),
    Tue(1),
    Wed(2),
    Thu(3),
    Fri(4),
    Sat(5),
    Sun(6);
}

enum Month {
    Jan(0),
    Feb(1),
    Mar(2),
    Apr(3),
    May(4),
    Jun(5),
    Jul(6),
    Aug(7),
    Sep(8),
    Oct(9),
    Nov(10),
    Dec(11);
}

/// Represents a specific date within a year.
/// The day field must be valid for the specified month (e.g., February 30th is invalid).
/// Leap year handling is automatic for February dates.
type DateTuple {
    /// Day of the month (1-31). Must be valid for the specified month
    day: int;
    /// Month of the year
    month: Month;
}