UNPKG

hackmud-script-manager

Version:

Script manager for game hackmud, with minification, TypeScript support, and player script type definition generation.

1,081 lines (877 loc) 42.3 kB
type Replace<A, B> = Omit<A, keyof B> & B type ErrorScripts = Record<string, () => ScriptFailure> type Subscripts = Record<string, Record<string, (...args: any) => any>> & { accts: ErrorScripts autos: ErrorScripts bbs: ErrorScripts chats: ErrorScripts corps: ErrorScripts escrow: ErrorScripts gui: ErrorScripts kernel: ErrorScripts market: ErrorScripts scripts: ErrorScripts sys: ErrorScripts trust: ErrorScripts users: ErrorScripts } type UpgradeRarityString = "`0noob`" | "`1kiddie`" | "`2h4x0r`" | "`3h4rdc0r3`" | "`4|_|b3|2`" | "`531337`" type UpgradeRarityNumber = 0 | 1 | 2 | 3 | 4 | 5 type UpgradeBase = { name: string type: "lock" | "script_space" | "chat" | "script" | "tool" | "bot_brain" | "glam" up_class?: -1 | 0 | 1 | 2 | 3 tier: 1 | 2 | 3 | 4 rarity: UpgradeRarityNumber i: number loaded: boolean sn: string description: string } type Upgrade = UpgradeBase & Record<string, null | boolean | number | string> type CliUpgrade = Omit<UpgradeBase, `rarity`> & { [k: string]: null | boolean | number | string, rarity: UpgradeRarityString } type UsersTopItem<R> = { rank: R, name: string, last_activity: string, balance: string } type CorpsTopItem<R> = { rank: R, name: string, worth: string } type CorpsTop = [ CorpsTopItem<1>, CorpsTopItem<2>, CorpsTopItem<3>, CorpsTopItem<4>, CorpsTopItem<5>, CorpsTopItem<6>,CorpsTopItem<7>, CorpsTopItem<8>, CorpsTopItem<9>, CorpsTopItem<10> ] type Fullsec = Subscripts & PlayerFullsec & { accts: { /** **FULLSEC** @returns GC balance of script owner. */ balance_of_owner: () => number /** **FULLSEC** */ xfer_gc_to_caller: (args: { amount: number | string, memo?: string | undefined }) => ScriptResponse } bbs: { read: () => { boards: { title: string, slug: string }[] posts: { vote_count: number short_id: string is_sticky: boolean is_locked: boolean is_archived: boolean is_answered: boolean is_implemented: boolean title: string slug: string vote: boolean username: string time: string }[] } r: Fullsec["bbs"]["read"] } chats: { /** **FULLSEC** * @summary Create a new chat channel. * @description This script lets you create a new chat channel. * You cannot create a channel that already exists (including any of the default ports from `0000` to `FFFF`). * If you do not supply a password, anyone can join your channel (but the channel name is not displayed * anywhere, so they would have to discover it in some way first). */ create: ((args: { /** The name of the channel to create. */ name: string /** The password to secure the channel with. */ password?: string }) => ScriptResponse) & ((args: { /** The name of the channel to create. */ c: string /** The password to secure the channel with. */ password?: string }) => ScriptResponse) /** **FULLSEC** * @summary Send a chat message to a channel. * @description This script lets you send a message to the specified channel. * You must have joined the channel, and you will see your own message (unlike chats.tell). */ send: (args: { /** The channel to send the message to. */ channel: string /** The message to send. */ msg: string }) => ScriptResponse /** **FULLSEC** * @summary Send a chat message to a specific user. * @description This script lets you send a message to the specified user directly. * You can message any user, you only need their username. * Note that you will not be able to see your message after it is sent (though many chat scripts based on * chats.tell also send the message to you to work around this limitation). */ tell: (args: { /** The username to send the message to. */ to: string /** The message to send. */ msg: string }) => ScriptResponse } escrow: { /** **FULLSEC** */ charge: (args: { cost: number | string, is_unlim?: boolean }) => null | ScriptFailure confirm: never } gui: { chats: never, quiet: never, size: never, vfx: never, vol: never } market: { /** **FULLSEC** */ browse: { (args: Partial<{ seller: string | MongoQuerySelector<string>, listed_before: number | MongoQuerySelector<number>, listed_after: number, cost: number | MongoQuerySelector<number> | string, rarity: UpgradeRarityNumber | MongoQuerySelector<UpgradeRarityNumber>, name: string | MongoQuerySelector<string> } & Omit<{ [k in keyof CliUpgrade]: CliUpgrade[k] | MongoQuerySelector<CliUpgrade[k]> }, "rarity">> ): { i: string, name: string, rarity: Upgrade["rarity"], cost: number }[] | ScriptFailure <I extends string>(args: { i: I }): { i: I seller: string cost: number count: number description: string upgrade: Upgrade no_notify: boolean } | ScriptFailure <I extends string[]>(args: { i: I }): { i: I seller: string cost: number count: number description: string upgrade: Upgrade no_notify: boolean }[] | ScriptFailure } } scripts: { /** **FULLSEC** */ get_access_level: (args: { name: string }) => { public: boolean, hidden: boolean, trust: boolean } | ScriptFailure /** **FULLSEC** */ get_level: (args: { name: string }) => 0 | 1 | 2 | 3 | 4 | ScriptFailure /** **FULLSEC** */ fullsec: { (): string[], (args: { sector: string }): string[] | ScriptFailure } /** **FULLSEC** */ highsec: Fullsec["scripts"]["fullsec"] /** **FULLSEC** */ lowsec: Fullsec["scripts"]["fullsec"] /** **FULLSEC** */ midsec: Fullsec["scripts"]["fullsec"] /** **FULLSEC** */ nullsec: Fullsec["scripts"]["fullsec"] /** **FULLSEC** */ trust: () => string[] /** FULLSEC * @returns A code library containing useful helper functions you can use in your scripts. */ lib: () => { ok: () => ScriptSuccess not_impl: () => { ok: false, msg: "Not Implemented." } /** Append `message` to the current script run's log. */ log: (message: any) => void /** @returns All messages added using `scripts.lib().log` during this script run. */ get_log: () => string[] /** @returns A random integer in the range [min, max) generated using `rng` (defaults to `Math.random`). */ rand_int: (min: number, max: number, rng?:()=>number) => number /** @returns `floor` if `value` is less than `floor`, `ceil` if `value` is more than `ceil`, otherwise * `value`. */ clamp: (value: number, floor: number, ceil: number) => number /** Linear interpolation function. * @returns A number between `start` and `stop` using `amount` as a percent. */ lerp: (amount: number, start: number, stop: number) => number /** @returns A random element from `array`, selected with a random number generated using `rng` * (defaults to `Math.random`). */ sample: <T>(array: T[], rng?: ()=>number) => T /** @returns Whether two MongoDB `ObjectId`s are equivalent. */ are_ids_eq: (id1: any, id2: any) => boolean /** Convert a MongoDB `ObjectId` to a string. */ id_to_str: (id: string | {$oid: string}) => any /** @returns Whether `value` is a boolean primitive. */ is_bool: (value: any) => value is boolean /** @returns Whether `value` is an object or `null`. */ is_obj: (value: any) => value is Record<string, unknown> | null /** @returns Whether `value` is a string. */ is_str: (value: any) => value is string /** @returns Whether `value` is a number. */ is_num: (value: any) => value is number /** @returns Whether `value` is an integer. */ is_int: (value: any) => value is number /** @returns Whether `value` is a negative number. */ is_neg: (value: any) => value is number /** @returns Whether `value` is an array. */ is_arr: (value: any) => value is unknown[] /** @returns Whether `value` is a function. */ is_func: (value: any) => value is (...args: any[]) => unknown /** @returns Whether `value` is not `undefined`. */ is_def: (value: any) => boolean /** @returns Whether `name` is a valid in-game username. */ is_valid_name: (name: string) => boolean /** @returns The string representation of `value`. */ dump: (value: { toString: () => string }) => string /** @returns A deep clone of `object`. */ clone: <T extends object>(object: T) => T /** Applies all key-value pairs from `obj2` to `obj1`, overwriting if necessary. */ merge: <F extends object, S extends object>(obj1: F, obj2: S) => F & S /** @returns An array of `object`'s values */ get_values: (object: object) => any[] /** @returns A numeric hash of `string`. */ hash_code: (string: string) => number /** @returns A numeric hash of `string`. */ xmur3: (string: string) => number /** @returns Function that generates random floats in the range 0-1 based on the numerical seeds. */ sfc32: (seed1: number, seed2: number, seed3: number, seed4: number) => () => number /** @returns Function that generates random floats in the range 0-1 based on the numerical seed. */ mulberry32: (seed: number) => () => number /** @returns Function that generates random floats in the range 0-1 based on the numerical seeds. */ xoshiro128ss: (seed1: number, seed2: number, seed3: number, seed4: number) => () => number /** @returns Function that generates random floats in the range 0-1 based on the numerical seed. */ JSF: (seed: number) => () => number /** @returns Function that generates random floats in the range 0-1 based on the numerical seed. */ LCG: (seed: number) => () => number /** Converts a number to a GC string of the form `"1M5K20GC"`. */ to_gc_str: (number: number) => string /** Converts a string similar to `"1M5K20GC"` to an equivalent numerical representation. */ to_gc_num: (string: string) => number | ScriptFailure /** @returns A string of the form YYMMDD.HHMM derived from `date`. */ to_game_timestr: (date: Date) => string corruption_chars: "¡¢Á¤Ã¦§¨©ª" /** A list of unique color codes to be used with hackmud's color formatting syntax. * Does not include numeric codes, which are duplicates of some alphabetic codes. */ colors: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" /** Used by `$fs.scripts.lib().corrupt()` to determine the frequency of corruption. */ corruptions: [ 0, 1, 1.5, 2.5, 5 ] /** Adds colored corruption characters to `text`, with frequency determined by `amount`. */ corrupt: (text: string | string[], amount: 0 | 1 | 2 | 3 | 4) => string /** @returns The first `length` characters of `string`, or the original string if it is shorter than * `length`. */ cap_str_len: (string: string, length: number) => string /** Applies `callback` to each element in `array` and returns the original array. */ each: <T>(array: T[], callback: (index: number, value: T) => void) => T[] /** @returns A new array containing the elments of `array` for which `callback` returns `true`. */ select: <T>(array: T[], callback: (index: number, value: T) => boolean) => T[] /** @returns The number of elements in `array` for which `callback` returns `true`. */ count: <T>(array: T[], callback: (index: number, value: T) => boolean) => number /** @returns The first element in `array` for which `callback` returns `true`. */ select_one: <T>(array: T[], callback: (index: number, value: T) => boolean) => T /** @returns A new array composed of the result of applying `callback` to each element of the original array * in order. */ map: <T, U>(array: T[], callback: (index: number, value: T) => U) => U[] /** @returns A new object derived from `obj` with only the keys specified in `keys`. */ pick: <TObj extends object, TKeys extends keyof TObj>(obj: TObj, keys: TKeys[]) => { [K in TKeys]: TObj[K] } /** @returns An array with the elements from `array` in a random order. */ shuffle: <T>(array: T[]) => T[] /** Comparison function for sorting arbitrary values in ascending order using builtin comparison operators. */ sort_asc: (one: any, two: any) => 1 | -1 | 0 /** Comparison function for sorting arbitrary values in descending order using builtin comparison operators. */ sort_desc: (one: any, two: any) => 1 | -1 | 0 /** Comparison function for sorting numbers in ascending order. */ num_sort_asc: (one: number, two: number) => 1 | -1 | 0 /** Comparison function for sorting numbers in descending order. */ num_sort_desc: (one: number, two: number) => 1 | -1 | 0 /** @returns The value and the index of the largest number in `array`. */ max_val_index: (array: number[]) => [ largestValue: number, index: number ] /** @returns A new `Date` equivalent to `date.getTime() + add_ms`. */ add_time: (date: Date, add_ms: number) => Date /** Array of strings representing seclevels. */ security_level_names: [ "NULLSEC", "LOWSEC", "MIDSEC", "HIGHSEC", "FULLSEC" ] /** @returns The string name of a numeric security level. */ get_security_level_name: (security_level: number) => string /** @param result The return value of a call to `$db.i()` or `$db.r()`. * @param nModified The expected value of `result.nModified`. * @returns Whether the database operation failed. */ dbu_result_failed: (result: ReturnType<typeof $db.u | typeof $db.u1 | typeof $db.us>, nModified?: number) => boolean /** @param result The return value of a call to `$db.i()` or `$db.r()`. * @param n The expected value of `result.n`. * @returns Whether the database operation failed. */ dbir_result_failed: (result: ReturnType<typeof $db.i | typeof $db.r>, n?: number) => boolean /** @returns A random string of length `length` using lowercase letters and numbers. */ create_rand_string: (length: number) => string /** @returns The user half `x` of a fully-qualified script name `x.y`. */ get_user_from_script: (script_name: string) => string /** @returns The script half `y` of a fully-qualified script name `x.y`. */ get_scriptname_from_script: (name: string) => string /** Determines whether to treat this run as a subscript, based either on the presence of `calling_script` in * `context`, or the explicit passing of `is_script: true` in `args`. */ is_script: (context: Context, args: any) => boolean /** @returns Whether the script is being called by its owner. */ caller_is_owner: (context: Context) => boolean /** Removes consecutive duplicate elements from an array. * @example * const { uniq } = $fs.scripts.lib() * const arr = [ 1, 2, 2, 3, 2 ] * * $D(uniq(arr)) // [ 1, 2, 3, 2 ] */ uniq: <T>(array: T[]) => T[] /** Sorts an array of numbers or number-coercible strings in descending order. */ u_sort_num_arr_desc: <T>(array: T[]) => T[] /** BUGGED: Creates a new string of length `length` by repeating `pad_char`. */ ljust: (input: string, length: number, pad_char?: string) => string /** Add characters from `pad_char` to the left of `input` until it reaches length `length`. */ rjust: (input: string, length: number, pad_char?: string) => string /** @returns A string with the entries from `strings` split into evenly spaced columns, organized donward * and then rightward, to fit the current user's terminal. */ columnize: (strings: string[]) => string /** Takes two newline-separated strings and formats a new string where they appear in columns, separated by * `space`. * @example * const { side_by_side } = $fs.scripts.lib() * const str1 = "one\ntwo\nthree" * const str2 = "four\nfive\nsix" * * $D(side_by_side(str1, str2, "|")) * // one|four\n * // two|five\n * // three|six */ side_by_side: (str1: string, str2: string, space?: string) => string /** @returns Whether enough time remains in the script execution window to satisfy `time_left`. */ can_continue_execution: (time_left: number) => boolean /** @returns A human-readable error object when not enough time remains in the script execution window to * satisfy `time_left`. */ can_continue_execution_error: (time_left: number, name?: string) => { ok:false, msg: string } /** @returns Current date, equivalent to `new Date()`. */ get_date: () => Date /** @returns time since the epoch, equivalent to `Date.now()`. */ get_date_utcsecs: () => number /** The amount of milliseconds in a single day. */ one_day_ms: 86_400_000 is_not_today: (date: Date) => boolean /** @returns The number of days that have passed between `d2` and `d1` */ utc_day_diff: (d1: Date, d2: Date) => number /** @returns The number of days elapsed since `date` as a string, e.g. "<n> days" */ utc_days_ago_str: (date: Date) => string math: typeof Math array: typeof Array parse_int: typeof parseInt parse_float: typeof parseFloat json: typeof JSON number: typeof Number object: typeof Object date: typeof Date } /** **FULLSEC** */ quine: () => string } sys: { init: never /** **FULLSEC** */ upgrades_of_owner: { <F extends Partial<Upgrade & { loaded: boolean }> = object>(args?: { filter?: F, full?: false }): ( Omit< Pick<UpgradeBase, "tier" | "rarity" | "name" | "type" | "i" | "loaded">, keyof F > & Pick<F, "tier" | "rarity" | "name" | "type" | "i" | "loaded"> )[] | ScriptFailure <F extends Partial<Upgrade & { loaded: boolean }> = object>(args: { filter?: F, full: true }): ( Omit<UpgradeBase, keyof F> & F & Record<string, null | boolean | number | string> )[] | ScriptFailure <I extends number>(args: { i: I }): ( Omit<UpgradeBase, "i"> & { [x: string]: null | boolean | number | string, i: I } ) | ScriptFailure } /** **FULLSEC** */ xfer_upgrade_to_caller: (args: ({ i: number | number[] } | { sn: string | string[] }) & { memo?: string }) => ScriptResponse } users: { /** **FULLSEC** */ active: () => number /** **FULLSEC** */ last_action: (args: { name: string | string[] }) => ({ n: string, t?: Date } | null)[] /** **FULLSEC** */ top: () => [ UsersTopItem<1>, UsersTopItem<2>, UsersTopItem<3>, UsersTopItem<4>, UsersTopItem<5>, UsersTopItem<6>, UsersTopItem<7>, UsersTopItem<8>, UsersTopItem<9>, UsersTopItem<10> ] } } type Highsec = Fullsec & PlayerHighsec & { accts: { /** **HIGHSEC** * @returns GC balance as number if `is_script` is true (default). * @returns GC balance as string if `is_script` is false. */ balance: { (args?: { is_script?: true }): number (args: { is_script: false }): string } /** **HIGHSEC** * @returns Transaction history according to filter. * @returns If `is_script` is true (default), time property as Date object. * @returns Wraps transactions in object with msg, time property as string (game date format e.g. 201028.2147) * if `is_script` is false. */ transactions: { (args?: { count?: number | "all", to?: string, from?: string, script?: string, is_script?: true }): { time: Date amount: number sender: string recipient: string script: string | null memo?: string }[] (args: { count?: number | "all", to?: string, from?: string, script?: string, is_script: false }): { msg: string transactions: { time: string amount: string sender: string recipient: string script: string | null memo?: string }[] } } } scripts: { /** **HIGHSEC** */ sys: () => string | string[] } sys: { /** **HIGHSEC** */ specs: () => string | ScriptFailure /** **HIGHSEC** */ status: () => { hardline: number, tutorial: string, breach: boolean } /** **HIGHSEC** */ upgrade_log: { (args?: { is_script?: true, user?: string, run_id?: string, count?: number, start?: number }): { t: Date, u: string, r: string, msg: string }[] | ScriptFailure (args: { is_script: false, user?: string, run_id?: string, count?: number, start?: number }): string[] | ScriptFailure } /** **HIGHSEC** */ upgrades: { <I extends number>(args: { i: I }): ( Omit<UpgradeBase, "i"> & { [x: string]: null | boolean | number | string, i: I } ) | ScriptFailure <F extends Partial<Upgrade & { loaded: boolean }> = object>(args?: { filter?: F is_script?: true full?: false }): ( Omit<Pick<UpgradeBase, "tier" | "rarity" | "name" | "type" | "i" | "loaded">, keyof F> & F & Record<string, null | boolean | number | string> )[] | ScriptFailure <F extends Partial<Upgrade & { loaded: boolean }> = object>(args?: { filter?: F, is_script?: true, full: true } ): (Omit<UpgradeBase, keyof F> & F & Record<string, null | boolean | number | string>)[] | ScriptFailure (args?: { filter?: Partial<Upgrade & { loaded: boolean }>, is_script: false, full?: false }): { msg: string, upgrades: string[] } | ScriptFailure <F extends Partial<Upgrade & { loaded: boolean }> = object>( args?: { filter?: F, is_script: false, full: true } ): (Omit<UpgradeBase, keyof F | `rarity`> & F & { [x: string]: null | boolean | number | string rarity: UpgradeRarityString })[] | ScriptFailure } } users: { /** **HIGHSEC** */ inspect: { (args: { name: "trust", is_script?: boolean }): number (args: { name: "risk", is_script?: boolean }): string (args: { name: string, is_script?: true }): { username: string avatar: string pronouns: string user_age?: Date bio?: string title?: string is_main: boolean alt_of?: string badges?: string[] } | ScriptFailure (args: { name: string, is_script: false }): string | ScriptFailure } } } type Midsec = Highsec & PlayerMidsec & { accts: { /** **MIDSEC** */ xfer_gc_to: (args: { to: string, amount: number | string, memo?: string }) => ScriptResponse } autos: { /** **MIDSEC** */ reset: () => ScriptSuccess } chats: { /** **MIDSEC** */ channels: () => string[] /** **MIDSEC** */ join: (args: { channel: string, password?: string }) => ScriptResponse /** **MIDSEC** */ leave: (args: { channel: string }) => ScriptResponse /** **MIDSEC** */ users: (args: { channel: string }) => string[] | ScriptFailure } escrow: { /** **MIDSEC** */ stats: () => { scripts: string[], total: string, outstanding: string, open_escrow_count: number } | ScriptFailure } market: { /** **MIDSEC** */ buy: (args: { i: string, count: number, confirm: true }) => ScriptResponse /** **MIDSEC** */ stats: () => ScriptFailure | { total: string, outstanding: string, listed: number, sold: number } } scripts: { /** **MIDSEC** */ user: () => string[] } sys: { /** **MIDSEC** */ manage: { (args: { unload?: number | number[], load?: number | number[] }): ScriptResponse (args: { reorder?: ([ number, number ] | { from: number, to: number })[] | { from: number, to: number } }): string[] | ScriptFailure } } } type Lowsec = Midsec & PlayerLowsec & { kernel: { /** **LOWSEC** */ hardline: () => ScriptResponse } market: { /** **LOWSEC** */ sell: (args: { i: number cost: number | string description?: string count?: number no_notify?: boolean confirm: true }) => ScriptResponse<{ token: string }> } sys: { /** **LOWSEC** */ access_log: { (args?: { user?: string, run_id?: string, is_script?: true, count?: number, start?: number }): { t: Date, u: string | undefined, r: string | undefined, msg: string }[] | ScriptFailure (args: { user?: string, run_id?: string, is_script: false, count?: number, start?: number }): string[] } /** **LOWSEC** */ cull: (args: { i: number | number[], confirm: true }) => ScriptResponse /** **LOWSEC** */ loc: () => string | ScriptFailure /** **LOWSEC** */ xfer_upgrade_to: { (args: { i: number | number[], to: string, memo?: string }): ScriptResponse (args: { sn: string | string[], to: string, memo?: string }): ScriptResponse } /** **LOWSEC** */ expose_access_log: (args: { target: string }) => ScriptResponse /** **LOWSEC** */ xfer_gc_from: (args: { target: string, amount: number | string }) => ScriptResponse /** **LOWSEC** */ expose_balance: (args: { target: string }) => ScriptResponse } } type Nullsec = Lowsec & PlayerNullsec & { corps: { /** **NULLSEC** */ create: (args: { name: string, confirm: true }) => ScriptResponse /** **NULLSEC** */ hire: (args: { name: string }) => ScriptResponse /** **NULLSEC** */ manage: { (args: { command: "list" }): { name: string, is_admin: boolean }[] | ScriptFailure (args: { command: "demote" | "promote", name: string } | { command: "fire", name: string, confirm: true }): ScriptResponse } /** **NULLSEC** */ offers: { (): { offers: string[], msg: string } | ScriptSuccess<{ msg: string, current_corp: string | null }> (args: { accept: string }): ScriptResponse } /** **NULLSEC** */ quit: (args: { confirm: true }) => ScriptResponse /** **NULLSEC** */ top: () => CorpsTop | { top: CorpsTop, active: { name: string, worth: string } } } sys: { /** **NULLSEC** */ breach: (args: { confirm: true }) => ScriptResponse } trust: { /** **NULLSEC** */ me: () => string } users: { /** **NULLSEC** */ config: { (args: { list: false is_script?: true | null avatar?: string | null user_age?: boolean | null account_age?: boolean | null bio?: string | null title?: string | null pronouns?: string | null corp?: boolean | null alt_of?: string | null badges?: string[] | null }): ScriptResponse (args: { list: true is_script?: true avatar?: string | null user_age?: boolean | null account_age?: boolean | null bio?: string | null title?: string | null pronouns?: string | null corp?: boolean | null alt_of?: string | null badges?: string[] | null }): { avatar: string | null user_age?: boolean account_age?: boolean bio: string | null title: string | null pronouns: string corp?: boolean alt_of: string | null badges: string[] } (args: { list: true is_script: false avatar?: string | null user_age?: boolean | null account_age?: boolean | null bio?: string | null title?: string | null pronouns?: string | null corp?: boolean | null alt_of?: string | null badges?: string[] | null }): string } } } // database type MongoPrimitive = null | boolean | number | Date | string type MongoValue = MongoPrimitive | MongoValue[] | MongoObject type MongoObject = { [k: string]: MongoValue } type MongoQueryValue = MongoPrimitive | MongoQueryValue[] | MongoQueryObject type MongoQueryObject = { [k: string]: MongoQueryValue, [k: `$${string}`]: MongoValue } & { $type?: keyof MongoTypeStringsToTypes | (string & {}) } type MongoTypeStringsToTypes = { double: number string: string object: MongoObject array: MongoValue[] objectId: ObjectId bool: boolean date: Date null: null int: number long: number } type MongoTypeString = keyof MongoTypeStringsToTypes type MongoTypeNumber = -1 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 127 type MongoId = Exclude<MongoPrimitive, null | false> | ObjectId | MongoObject type MongoQueryId = Exclude<MongoPrimitive, null | false> | ObjectId | MongoQueryObject type MongoDocument = MongoObject & { _id?: MongoId } type MongoQueryType<TQuery extends MongoQueryObject> = { -readonly [K in keyof TQuery]: TQuery[K] extends MongoPrimitive ? TQuery[K] : TQuery[K] extends { $type: infer TType } ? TType extends keyof MongoTypeStringsToTypes ? MongoTypeStringsToTypes[TType] : unknown : TQuery[K] extends { $in: (infer TIn)[] } ? TIn : keyof TQuery[K] extends `$${string}` ? unknown : TQuery[K] extends { [k: string]: any } ? MongoQueryType<TQuery[K]> : never } type MongoCommandValue = MongoPrimitive | MongoCommandValue[] | { [k: string]: MongoCommandValue } type MongoArraySelectors<T extends MongoValue[] = MongoValue[]> = { $all: T, $elemMatch: T, $size: number } type MongoComparisonSelectors<T extends MongoValue = MongoValue> = { $eq: T, $gt: T, $gte: T, $in: T[], $lt: T, $lte: T, $ne: T, $nin: T[] } type MongoElementSelectors = { $exists: boolean, $type: MongoTypeNumber | MongoTypeString } type MongoQuerySelector<T extends MongoValue> = Partial< T extends [] ? MongoArraySelectors<T> & MongoElementSelectors & MongoComparisonSelectors<T> : MongoElementSelectors & MongoComparisonSelectors<T> > type MongoQuery<T extends MongoObject> = { [K in keyof T]?: T[K] | MongoQuerySelector<T[K]> } & { _id?: MongoId } type MongoUpdateArrayOperatorUniversalModifiers<T> = { $each?: T extends [] ? T : T[] } type MongoUpdateArrayOperatorModifiers<T> = MongoUpdateArrayOperatorUniversalModifiers<T> & { $position?: number, $slice?: number, $sort?: 1 | -1 } type MongoUpdateCommand<T extends MongoObject> = Partial<{ /* Universal operators */ $set: Partial<Record<(string & {}) | keyof T, MongoCommandValue>> $setOnInsert: Partial<Record<(string & {}) | keyof T, MongoCommandValue>> $unset: Partial<Record<(string & {}) | keyof T, "">> $rename: Partial<Record<string, string> & { [key in keyof T]: string }> /* Date & number operators */ $inc: Record<string, number> & { [K in keyof T as T[K] extends number | Date ? K : never]?: T[K] extends number ? number : Date } $mul: Record<string, number> & { [K in keyof T as T[K] extends number ? K : never]?: number } $min: Record<string, number> & { [K in keyof T as T[K] extends number ? K : never]?: number } $max: Record<string, number> & { [K in keyof T as T[K] extends number ? K : never]?: number } /* Array operators */ $pop: Record<string, -1 | 1> & { [K in keyof T as T[K] extends [] ? K : never]?: -1 | 1 } $push: Record<string, MongoCommandValue> & { [K in keyof T as T[K] extends [] ? K : never]?: (T[K] extends (infer U)[] ? U : never) | MongoUpdateArrayOperatorModifiers<T[K]> } $addToSet: Partial<Record<string, MongoCommandValue> & { [K in keyof T as T[K] extends [] ? K : never]: (T[K] extends (infer U)[] ? U : never) | MongoUpdateArrayOperatorUniversalModifiers<T[K]> }> $pull: Partial<Record<string, MongoCommandValue> & { [K in keyof T as T[K] extends [] ? K : never]: (T[K] extends (infer U)[] ? U : never) | MongoQuerySelector<T[K]> }> $pullAll: Record<string, MongoCommandValue> & { [K in keyof T as T[K] extends [] ? K : never]?: T[K] } }> type SortOrder = { [key: string]: 1 | -1 | SortOrder } type Cursor<T> = { /** Returns the first document that satisfies the query. */ first: () => T | null /** Returns an array of documents that satisfy the query. */ array: () => T[] /** Returns the number of documents that match the query. */ count: () => number /** Returns the first document that satisfies the query. Also makes cursor unusable. */ first_and_close: () => T /** Returns an array of documents that satisfy the query. Also makes cursor unusable. */ array_and_close: () => T[] /** Returns the number of documents that match the query. Also makes cursor unusable. */ count_and_close: () => number /** Run `callback` on each document that satisfied the query. */ each: (callback: (document: T) => void) => null /** Returns a new cursor with documents sorted as specified. * A value of 1 sorts the property ascending, and -1 descending. * @param order The way the documents are to be sorted. */ sort: (order?: SortOrder) => Cursor<T> /** Returns a new cursor without the first number of documents. * @param count Number of documents to skip. */ skip: (count: number) => Cursor<T> /** Returns a new cursor limited to a number of documents as specified. * @param count Number of documents. */ limit: (count: number) => Cursor<T> /** @param key The key of the documents. */ distinct: { (key: string): MongoValue[], (key: "_id"): MongoId[] } /** Make cursor unusable. */ close: () => null NumberLong: (number: number) => number // TODO what actually is the type here? ObjectId: () => any } type CliContext = { /** The name of the user who is calling the script. */ caller: string /** The name of this script. */ this_script: string /** The number of columns in the caller’s terminal. */ cols: number /** The number of rows in the caller’s terminal. */ rows: number /** The name of the script that directly called this script, or null if called on the command line or as a * scriptor. */ calling_script: null is_scriptor?: undefined is_brain?: undefined } type SubscriptContext = Replace<CliContext, { /** The name of the script that directly called this script, or null if called on the command line or as a scriptor. */ calling_script: string }> type ScriptorContext = Replace<CliContext, { /** Whether the script is being run as a scriptor. */ is_scriptor: true }> type BrainContext = Replace<CliContext, { /** Whether the script is being run via a bot brain. */ is_brain: true }> // _id is always returned unless _id: false is passed // when anyField: true is given, other fields (except _id) are omitted type MongoProject<TDocument, TProjection> = (TProjection extends { _id: false | 0 } ? {} : { _id: TDocument extends { _id: infer TId } ? TId : MongoId }) & ( true extends (1 extends TProjection[keyof TProjection] ? true : TProjection[keyof TProjection]) ? { [K in keyof TDocument as K extends keyof TProjection ? TProjection[K] extends true | 1 ? K : never : never ]: TDocument[K] } & { -readonly [K in keyof TProjection as TProjection[K] extends true | 1 ? K extends keyof TDocument ? never : K : never ]?: MongoValue } : { [k: string]: MongoValue } & { [K in keyof TDocument as K extends keyof TProjection ? never : K]: TDocument[K] } ) type DeepFreeze<T> = { readonly [P in keyof T]: DeepFreeze<T[P]> } declare global { type ScriptSuccess<T = unknown> = { ok: true } & T type ScriptFailure = { ok: false, msg?: string } type ScriptResponse<T = unknown> = ScriptSuccess<T> | ScriptFailure type Scriptor<TArgs extends any[] = any[]> = { name: string, call: (...args: TArgs) => unknown } type Context = CliContext | SubscriptContext | ScriptorContext | BrainContext type ObjectId = { $oid: string } interface PlayerFullsec {} interface PlayerHighsec {} interface PlayerMidsec {} interface PlayerLowsec {} interface PlayerNullsec {} /** Subscript space that can call FULLSEC scripts. */ const $fs: Fullsec /** Subscript space that can call HIGHSEC and above scripts. Makes your script HIGHSEC (overrides FULLSEC). */ const $hs: Highsec /** Subscript space that can call MIDSEC and above scripts. Makes your script MIDSEC (overrides higher security levels). */ const $ms: Midsec /** Subscript space that can call LOWSEC and above scripts. Makes your script LOWSEC (overrides higher security levels). */ const $ls: Lowsec /** Subscript space that can call any script. Makes your script NULLSEC (overrides higher security levels). */ const $ns: Nullsec /** Subscript space that can call FULLSEC scripts. */ const $4s: typeof $fs /** Subscript space that can call HIGHSEC and above scripts. Makes your script HIGHSEC (overrides FULLSEC). */ const $3s: typeof $hs /** Subscript space that can call MIDSEC and above scripts. Makes your script MIDSEC (overrides higher security levels). */ const $2s: typeof $ms /** Subscript space that can call LOWSEC and above scripts. Makes your script LOWSEC (overrides higher security levels). */ const $1s: typeof $ls /** Subscript space that can call any script. Makes your script NULLSEC (overrides higher security levels). */ const $0s: typeof $ns /** Subscript space that can call any script. Uses seclevel provided in comment before script (defaults to NULLSEC) * @example * // @​seclevel MIDSEC * // note, do NOT copy paste the above line because there is a zero-width space inserted between "@" and "s" * export function script() { * $s.foo.bar() // will be converted to #ms.foo.bar() * } */ const $s: Nullsec const $db: { /** Insert a document or documents into a collection. * @param documents A document or array of documents to insert into the collection. */ i: <T extends MongoDocument>(documents: (T & { _id?: MongoId }) | (T & { _id?: MongoId })[]) => { n: number, opTime: { t: number }, ok: 0 | 1 }[] /** Remove documents from a collection. * @param query Specifies deletion criteria using query operators. */ r: <T extends MongoDocument>(query: MongoQuery<T>) => { n: number, opTime: { t: number }, ok: 0 | 1 }[] /** Find documents in a collection or view and returns a cursor to the selected documents. * @param query Specifies deletion criteria using query operators. * @param projection Specifies the fields to return in the documents that match the query filter. */ f: < const TQuery extends MongoQueryObject & { _id?: MongoQueryId }, const TProjection extends { [k: string]: boolean | 0 | 1 } = {} >(query: TQuery, projection?: TProjection) => Cursor<MongoProject<MongoQueryType<TQuery>, TProjection>> /** Update existing documents in a collection. * @param query Specifies deletion criteria using query operators. * @param command The modifications to apply. * {@link https://docs.mongodb.com/manual/reference/method/db.collection.update/#parameters} */ u: <T extends MongoDocument>(query: MongoQuery<T> | MongoQuery<T>[], command: MongoUpdateCommand<T>) => { n: number, opTime: { t: number }, ok: 0 | 1, nModified: number }[] /** Updates one document within the collection based on the filter. * @param query Specifies deletion criteria using query operators. * @param command The modifications to apply. * {@link https://docs.mongodb.com/manual/reference/method/db.collection.update/#parameters} */ u1: <T extends MongoDocument>(query: MongoQuery<T> | MongoQuery<T>[], command: MongoUpdateCommand<T>) => { n: number, ok: 0 | 1, opTime: { t: number }, nModified: number }[] /** Update or insert document. * Same as Update, but if no documents match the query, one document will be inserted based on the properties in * both the query and the command. * The `$setOnInsert` operator is useful to set defaults. * @param query Specifies deletion criteria using query operators. * @param command The modifications to apply. * {@link https://docs.mongodb.com/manual/reference/method/db.collection.update/#parameters} */ us: <T extends MongoDocument>(query: MongoQuery<T> | MongoQuery<T>[], command: MongoUpdateCommand<T>) => { n: number, ok: 0 | 1, opTime: { t: number }, nModified: number }[] ObjectId: () => ObjectId } /** Debug Log. * * If `$D()` is called in a script you own, the `return` value of the top level script is suppressed and instead an * array of every `$D()`’d entry is printed. * This lets you use `$D()` like `console.log()`. * * `$D()` in scripts not owned by you are not shown but the `return` value always is. * * `$D()` returns the first argument so `$D("Hello, World!") evaluates to `"Hello, World!"` as if the `$D` text wasn't * there. * * `$D()`’d items are returned even if the script times out or errors. */ function $D<T>(args: T): T /** Function Multi-Call Lock. * * This is used by escrow to ensure that it is only used once in script execution. * * The first time (per-script) `$FMCL` is encountered, it returns `undefined`, every other time it `return`s `true`. * * @example * if ($FMCL) * return { ok: false, msg: "This script can only be used once per script execution." } * * // all code here will only run once */ const $FMCL: undefined | true /** Per-script mutable "global" persistent object that is discarded at the end of top level script execution. * * `$G` persists between script calls until the end of the main script run making it useful for caching db entries when * your script is a subscript. * @example * if (!$G.dbCache) * $G.dbCache = $db.f({ whatever: true }).first() */ const $G: Record<string | symbol, any> /** This contains a JS timestamp (not Date) set immediately before your code begins running. * @example * $D(Date.now() - _START) // milliseconds left of run time */ const _START: number /** This contains a JS timestamp (not Date) set immediately before your code begins running. * @example * $D(Date.now() - _ST) // milliseconds left of run time */ const _ST: typeof _START /** JavaScript timestamp for the end of the script run (`_START + _TIMEOUT`). */ const _END: number /** The number of milliseconds a script can run for. Normally `5000` though it has been known to change. */ const _TIMEOUT: number /** The number of milliseconds a script can run for. Normally `5000` though it has been known to change. */ const _TO: typeof _TIMEOUT /** The source code of this script as a string. */ const _SOURCE: string /** A unix timestamp of the date this script was built. */ const _BUILD_DATE: number /** The user this script has been uploaded to. * * Shorter alternative to `context.this_script.split(".")[0]. * * In rare cases where it's not known at build time, it's `"UNKNOWN"`. */ const _SCRIPT_USER: string /** @deprecated Use `_SCRIPT_SUBNAME` instead. */ const _SCRIPT_NAME: string /** The name of this script excluding the user and `.`. * * e.g. in the script `foo.bar`, `_SCRIPT_NAME` is `bar`. * * Shorter alternative to `context.this_script.split(".")[1]. * * In rare cases where it's not known at build time, it's `"UNKNOWN"`. */ const _SCRIPT_SUBNAME: string /** The full name of this script equivilent to `context.this_script` but should use less characters. * * In rare cases where it's not known at build time, it's `"UNKNOWN"`. */ const _FULL_SCRIPT_NAME: string /** The seclevel of this script as a number. * * In rare cases where it's not known at build time, it's `-1`. */ const _SECLEVEL: -1 | 0 | 1 | 2 | 3 | 4 /** Recursively * [`Object.freeze()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze) * an object and its properties' objects and its properties' objects and so on. * * [Official Hackmud Wiki](https://wiki.hackmud.com/scripting/extensions/deep_freeze) */ const DEEP_FREEZE: <T>(value: T) => DeepFreeze<T> const _RUN_ID: string } export {}