GearN dashboard cloud script function screenshot
Cloud Script Function

Cloud Script Function stores versioned server-side script bundles. Each bundle registers one or more named handlers, and Execute/Test runs the handler selected by function name.

  • Script bundle: Paste handler code that is injected into the server CloudScript template.
  • Handler registry: Register callable functions with handlers["functionName"].
  • Version control: Use canExecute for runtime availability and isLive for the default version.
  • Server helpers: Use admin, database, http, socket, mail, and pushNotification.
How CloudScript Runs

The dashboard does not save a complete TypeScript file. It saves only the script body. The server injects that body into the CloudScript template after runtime objects have already been created.

RuleWhat To Do
Register handlersEvery callable function must be assigned to handlers["functionName"]. The name must be 3 to 30 characters.
Do not import SDK manuallyThe runtime template already imports GearN SDK types, MongoDB, Axios, and CloudScript helpers.
Do not write GNNetworkThe server rejects submitted script when the literal text GNNetwork appears anywhere in it. Use admin instead.
Use JSON-safe logsCall log(value) only with serializable values. Runtime stores logs with JSON.stringify.
Return supported valuesReturn void, null, boolean, number, string, plain object, array, GNHashtable, or GNArray.
Minimal Script

Paste this into Cloud Script Function, save it with canExecute = true, then run pingCloudScript from Cloud Script Test.

handlers["pingCloudScript"] = async (args: any, context, log) => {
    const message = typeof args?.message === "string" && args.message.length > 0 ? args.message : "pong";

    log({
        action: "pingCloudScript",
        userId: context.userId,
        message: message
    });

    return {
        ok: true,
        gameId: gameId,
        userId: context.userId,
        customTags: context.customTags,
        message: message
    };
};
Handler Contract
ParameterMeaning
argsData from functionParameters. Treat it as untrusted input and validate fields before using them.
context.userIdUser id selected by the execute request. Client calls use the authenticated user; server/admin calls require an explicit 10-character user id.
context.customTagsOptional metadata passed outside functionParameters. Use it for tracing, source labels, or request tags.
logFunction-local logger. Output is returned in functionLogs and stored in CloudScript execution logs.
returnThe value returned to caller as functionResult when status is Ok.
Version Rules
  • Version length: Execute accepts a 7-character version when version is provided.
  • canExecute: The version must be executable. If this is false, the worker is not loaded for execution.
  • isLive: The live version is used when Execute/Test does not provide a version.
  • Safe release: Save new version with canExecute = true and isLive = false, test by explicit version, then edit it to live.
Runtime Objects
ObjectUse It ForCommon Methods Or Types
gameIdCurrent game id from the selected environment.Use in database namespaces and response payloads.
adminCalling GearN privileged APIs through a CloudScript-safe wrapper.admin.gamePlayer, admin.masterPlayer, admin.dashboard, admin.cloudScript
databaseReading and writing GearN MongoDB data.runtimeGameCollection, loadGamePlayerAsync, insertGamePlayerStatisticsLogAsync
httpCalling external REST APIs or webhooks.get, post, put, patch, delete
socketSending realtime events to connected players or rooms.sendEventTo, sendEventToMoreUser, sendEventToRoom
mailSending transactional HTML email through the server mail bridge.send, sendToMore
pushNotificationSending mobile push notification or managing topics.send, sendToMore, sendToTopic, subscribeToTopic
SDK typesBuilding GearN payloads and operation events.GNHashtable, GNArray, OperationEvent, OwnerType, model namespaces
Use Database For Internal Data

Use database when the script owns internal GearN data or custom game data. Prefer game-scoped collections for game-specific custom records.

const requireString = (value: unknown, fieldName: string): string => {
    if (typeof value !== "string" || value.trim().length === 0) {
        throw new Error(fieldName + " is required");
    }

    return value.trim();
};

handlers["saveCloudScriptSample"] = async (args: any, context, log) => {
    const key = requireString(args?.key, "key");
    const value = args?.value ?? null;
    const sampleCollection = database.runtimeGameCollection("CloudScript.Sample", gameId);

    await sampleCollection.updateOne(
        { key: key },
        {
            $set: {
                key: key,
                value: value,
                updatedByUserId: context.userId,
                tsUpdate: Date.now()
            }
        },
        { upsert: true }
    );

    const savedDocument = await sampleCollection.findOne(
        { key: key },
        { projection: { _id: 0 } }
    );

    return {
        gameId: gameId,
        savedDocument: savedDocument
    };
};
Use Admin For Existing GearN APIs

Use admin when GearN already has a typed API for the job. Always check response.hasReturnCodeError() before trusting response data.

const requireString = (value: unknown, fieldName: string): string => {
    if (typeof value !== "string" || value.trim().length === 0) {
        throw new Error(fieldName + " is required");
    }

    return value.trim();
};

handlers["adminGetPlayerDisplayName"] = async (args: any, context, log) => {
    const targetUserId = requireString(args?.userId, "userId");

    const response = await admin.gamePlayer.getDisplayNameAsync({
        userId: targetUserId
    });

    if (response.hasReturnCodeError()) {
        throw new Error(response.toString());
    }

    return {
        userId: targetUserId,
        errorCode: response.errorCode,
        responseData: response.responseData
    };
};
Call External Services

Use http for external REST APIs. Set a timeout and return only the fields the caller needs.

const requireString = (value: unknown, fieldName: string): string => {
    if (typeof value !== "string" || value.trim().length === 0) {
        throw new Error(fieldName + " is required");
    }

    return value.trim();
};

handlers["sendCloudScriptWebhook"] = async (args: any, context, log) => {
    const url = requireString(args?.url, "url");

    const response = await http.post(
        url,
        {
            eventName: "cloudScriptWebhook",
            gameId: gameId,
            userId: context.userId,
            payload: args?.payload ?? null,
            ts: Date.now()
        },
        {
            timeout: 8000,
            headers: {
                "content-type": "application/json"
            }
        }
    );

    return {
        status: response.status,
        data: response.data
    };
};
Notify Players

Use socket for online realtime delivery, mail for email, and pushNotification for mobile notification. Keep payloads small and do not log private tokens.

const requireString = (value: unknown, fieldName: string): string => {
    if (typeof value !== "string" || value.trim().length === 0) {
        throw new Error(fieldName + " is required");
    }

    return value.trim();
};

const createCloudScriptEvent = (eventName: string, payload: { [key: string]: any }) => {
    return new OperationEvent(
        eventName,
        GNHashtable.builder().addAll(payload).build()
    );
};

handlers["notifyPlayerFromCloudScript"] = async (args: any, context, log) => {
    const targetUserId = typeof args?.userId === "string" && args.userId.length > 0 ? args.userId : context.userId;
    const message = typeof args?.message === "string" && args.message.length > 0 ? args.message : "CloudScript notification";

    await socket.sendEventTo(
        targetUserId,
        createCloudScriptEvent("cloudScriptNotification", {
            message: message,
            sourceUserId: context.userId,
            ts: Date.now()
        })
    );

    if (typeof args?.email === "string" && args.email.length > 0) {
        await mail.send(args.email, "CloudScript notification", "<p>" + message + "</p>");
    }

    if (typeof args?.pushToken === "string" && args.pushToken.length > 0) {
        await pushNotification.send(args.pushToken, "CloudScript", message, 1, "default", "ic_notification", {
            source: "cloudScript",
            userId: targetUserId
        });
    }

    return {
        notified: true,
        userId: targetUserId
    };
};
How To Test
  1. Open Dashboard / Cloud Script / Function and create a new script version.
  2. Set canExecute = true so the server can load the worker.
  3. Keep isLive = false while testing a new version.
  4. Open Dashboard / Cloud Script / Test.
  5. Enter functionName, userId, the exact 7-character version, and JSON functionParameters.
  6. Review status, functionResult, functionLogs, executionTimeInMs, and memoryUsedInBytes.
Sample Test Parameters
{
    "message": "hello from dashboard",
    "key": "daily-reward",
    "value": {
        "coins": 100
    }
}
Execute Status
StatusMeaning
1 OkThe handler ran successfully and returned a supported value.
2 ExceptionThe handler threw an error or returned an unsupported value.
3 FunctionNameNotFoundThe selected version does not register handlers["functionName"].
4 VersionInvalidThe version does not exist, is not executable, or no live version is available when version is omitted.
5 TimeoutThe script exceeded the configured execute timeout. The current server default is 15 seconds.
Common Mistakes
  • Saving helper functions but forgetting to assign handlers["functionName"].
  • Calling Test without version and expecting the latest draft to run.
  • Setting canExecute = false and then wondering why execution returns version error.
  • Returning class instances, functions, Date objects, or large SDK responses instead of plain JSON.
  • Logging secrets, auth tokens, push tokens, or full external HTTP responses.
  • Using admin APIs as a shortcut when raw database or a narrower helper is the correct abstraction.