@jgengine/convex 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -2
- package/LICENSE +203 -661
- package/README.md +3 -3
- package/dist/convexSaveBackend.d.ts +35 -0
- package/dist/convexSaveBackend.js +24 -0
- package/dist/hostedServer.d.ts +7 -3
- package/dist/hostedServer.js +9 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/occ.d.ts +2 -0
- package/dist/occ.js +2 -0
- package/dist/server.d.ts +19 -3
- package/dist/server.js +120 -122
- package/package.json +4 -4
- package/skills/jgengine/SKILL.md +54 -0
- package/skills/jgengine/api.md +527 -0
- package/skills/jgengine/capabilities.md +131 -0
- package/skills/jgengine/recipes/minimal-game.md +88 -0
- package/skills/jgengine-multiplayer/SKILL.md +47 -0
- package/skills/jgengine-multiplayer/api.md +620 -0
- package/skills/jgengine-multiplayer/capabilities.md +17 -0
- package/skills/jgengine-multiplayer/reference.md +71 -0
- package/llms.txt +0 -974
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ import { resolveConvexMultiplayer } from "@jgengine/convex/resolveConvexMultipla
|
|
|
11
11
|
|
|
12
12
|
const session = resolveConvexMultiplayer({
|
|
13
13
|
game: myGame,
|
|
14
|
-
gameId: "
|
|
14
|
+
gameId: "my-game",
|
|
15
15
|
url: import.meta.env.VITE_CONVEX_URL,
|
|
16
16
|
force: import.meta.env.VITE_CONVEX_URL !== undefined,
|
|
17
17
|
});
|
|
@@ -44,6 +44,6 @@ No game-specific code lives there — any JGengine game can point at the same de
|
|
|
44
44
|
|
|
45
45
|
Every factory defaults to `auth: "anonymous"` — the client's `externalId` is trusted as claimed, fine for local dev but spoofable. Pass `{ auth: "required" }` to every factory for production; the resolved actor becomes `ctx.auth.getUserIdentity()`'s `subject`, and `externalId` is only cross-checked against it, never trusted alone.
|
|
46
46
|
|
|
47
|
-
See `examples/convex-host` for the reference thin consumer (`bunx convex dev` codegens `convex/_generated/` and prints the dev URL)
|
|
47
|
+
See `examples/convex-host` for the reference thin consumer (`bunx convex dev` codegens `convex/_generated/` and prints the dev URL). Point any game that declares `multiplayer: convexPresence({ topology: "shared" })` (or `convex({ topology: "shared", authority: "server" })` for a shared sim) at the same deployment. No Convex Cloud account is needed — `examples/convex-host/docker-compose.yml` runs the open-source backend anywhere Docker runs, with `CONVEX_SELF_HOSTED_URL`/`CONVEX_SELF_HOSTED_ADMIN_KEY` pointing the same CLI at it.
|
|
48
48
|
|
|
49
|
-
Part of [JGengine](https://github.com/Noisemaker111/jgengine).
|
|
49
|
+
Part of [JGengine](https://github.com/Noisemaker111/jgengine). Apache-2.0.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ConvexReactClient } from "convex/react";
|
|
2
|
+
import type { FunctionReference } from "convex/server";
|
|
3
|
+
import { type SaveBackend } from "@jgengine/core/game/saveStore";
|
|
4
|
+
/** The three Convex functions a save backend calls — a `query` that returns the stored string (or `null`) and two `mutation`s. Point them at your app's own module, or lean on the default `saves.*` convention. */
|
|
5
|
+
export interface ConvexSaveFunctions {
|
|
6
|
+
read: FunctionReference<"query", "public", {
|
|
7
|
+
key: string;
|
|
8
|
+
}, string | null>;
|
|
9
|
+
write: FunctionReference<"mutation", "public", {
|
|
10
|
+
key: string;
|
|
11
|
+
value: string;
|
|
12
|
+
}, unknown>;
|
|
13
|
+
remove: FunctionReference<"mutation", "public", {
|
|
14
|
+
key: string;
|
|
15
|
+
}, unknown>;
|
|
16
|
+
}
|
|
17
|
+
/** Default `saves.read` / `saves.write` / `saves.remove` refs for apps that follow the convention — pass your own `functions` to override. */
|
|
18
|
+
export declare function defaultConvexSaveFunctions(): ConvexSaveFunctions;
|
|
19
|
+
/** Config for {@link createConvexSaveBackend} — the Convex client, optional function refs (defaults to the `saves.*` convention), and an optional key `namespace`. */
|
|
20
|
+
export interface ConvexSaveBackendOptions {
|
|
21
|
+
client: ConvexReactClient;
|
|
22
|
+
/** The read/write/remove function refs; defaults to the `saves.*` convention. */
|
|
23
|
+
functions?: ConvexSaveFunctions;
|
|
24
|
+
/** Prefix every key so multiple games or users can share one `saves` table. */
|
|
25
|
+
namespace?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A cloud {@link SaveBackend} backed by Convex — reads through a query and
|
|
29
|
+
* writes through mutations, so a {@link createSaveStore} configured with it
|
|
30
|
+
* saves to the server instead of `localStorage`. The only change from an offline
|
|
31
|
+
* game is swapping the backend; autosave, slots, and migration behave the same.
|
|
32
|
+
*
|
|
33
|
+
* @capability convex-save save a game to Convex (cloud) through the SaveBackend seam
|
|
34
|
+
*/
|
|
35
|
+
export declare function createConvexSaveBackend(options: ConvexSaveBackendOptions): SaveBackend;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { anyApi } from "convex/server";
|
|
2
|
+
import { remoteSaveBackend } from "@jgengine/core/game/saveStore";
|
|
3
|
+
/** Default `saves.read` / `saves.write` / `saves.remove` refs for apps that follow the convention — pass your own `functions` to override. */
|
|
4
|
+
export function defaultConvexSaveFunctions() {
|
|
5
|
+
return anyApi.saves;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A cloud {@link SaveBackend} backed by Convex — reads through a query and
|
|
9
|
+
* writes through mutations, so a {@link createSaveStore} configured with it
|
|
10
|
+
* saves to the server instead of `localStorage`. The only change from an offline
|
|
11
|
+
* game is swapping the backend; autosave, slots, and migration behave the same.
|
|
12
|
+
*
|
|
13
|
+
* @capability convex-save save a game to Convex (cloud) through the SaveBackend seam
|
|
14
|
+
*/
|
|
15
|
+
export function createConvexSaveBackend(options) {
|
|
16
|
+
const functions = options.functions ?? defaultConvexSaveFunctions();
|
|
17
|
+
const prefix = options.namespace === undefined ? "" : `${options.namespace}:`;
|
|
18
|
+
const scope = (key) => `${prefix}${key}`;
|
|
19
|
+
return remoteSaveBackend({
|
|
20
|
+
read: (key) => options.client.query(functions.read, { key: scope(key) }),
|
|
21
|
+
write: (key, value) => options.client.mutation(functions.write, { key: scope(key), value }).then(() => undefined),
|
|
22
|
+
remove: (key) => options.client.mutation(functions.remove, { key: scope(key) }).then(() => undefined),
|
|
23
|
+
});
|
|
24
|
+
}
|
package/dist/hostedServer.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { GameDefinition } from "@jgengine/core/game/defineGame";
|
|
2
|
-
import type { GameContextContent } from "@jgengine/core/runtime/gameContext";
|
|
2
|
+
import type { GameContextContent, GameContextModels } from "@jgengine/core/runtime/gameContext";
|
|
3
3
|
import { type InputFrame } from "@jgengine/core/runtime/hostedGameRunner";
|
|
4
4
|
import { type HostedWorldSession, type HostedWorldStore } from "@jgengine/core/runtime/hostedWorldSession";
|
|
5
5
|
import type { ModelAssetRef } from "@jgengine/core/scene/assetCatalog";
|
|
@@ -8,6 +8,8 @@ import { type JgAuthMode } from "./server.js";
|
|
|
8
8
|
export interface HostedGameConfig {
|
|
9
9
|
definition: GameDefinition<ModelAssetRef, unknown>;
|
|
10
10
|
content: GameContextContent;
|
|
11
|
+
/** Render-model lookup for collider auto-fit — pass the same lookup the shell derives (`contextModels(playable)`) so the authoritative host resolves the hitboxes clients see. */
|
|
12
|
+
models?: GameContextModels;
|
|
11
13
|
}
|
|
12
14
|
/**
|
|
13
15
|
* Everything one stateless invocation reconstructs a hosted world from: the persisted record via `store`,
|
|
@@ -32,7 +34,8 @@ export interface HostedWorldOutcome<T> {
|
|
|
32
34
|
* The reconstruct → op → save core of the stateless hosted path, Convex-agnostic so it unit-tests against
|
|
33
35
|
* `memoryWorldStore`: build a fresh {@link createHostedWorldSession} from `store.load()`, resume persisted
|
|
34
36
|
* members and replay held inputs, run the op, then persist the snapshot at `revision + 1` iff the world changed.
|
|
35
|
-
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
36
39
|
export declare function invokeHostedWorld<T>(invocation: HostedWorldInvocation<T>): HostedWorldOutcome<T>;
|
|
37
40
|
/** Default minimum elapsed ms before `tickHostedWorlds` advances a world — override via the factory's `tickMs`. */
|
|
38
41
|
export declare const JG_HOSTED_TICK_MS = 1000;
|
|
@@ -41,7 +44,8 @@ export declare const JG_HOSTED_TICK_MS = 1000;
|
|
|
41
44
|
* reconstructing a hosted session from the persisted `jgHostedWorlds` row on every invocation via
|
|
42
45
|
* {@link invokeHostedWorld}. Destructure + re-export the returned functions from a `convex/` module and
|
|
43
46
|
* drive `tickHostedWorlds` from a cron. Requires {@link jgengineHostedTables} in the deployment schema.
|
|
44
|
-
|
|
47
|
+
* @internal
|
|
48
|
+
*/
|
|
45
49
|
export declare function createHostedGameServerFunctions(options: {
|
|
46
50
|
games: Record<string, HostedGameConfig>;
|
|
47
51
|
auth?: JgAuthMode;
|
package/dist/hostedServer.js
CHANGED
|
@@ -8,7 +8,8 @@ import { jgengineHostedTables, resolveActor } from "./server.js";
|
|
|
8
8
|
* The reconstruct → op → save core of the stateless hosted path, Convex-agnostic so it unit-tests against
|
|
9
9
|
* `memoryWorldStore`: build a fresh {@link createHostedWorldSession} from `store.load()`, resume persisted
|
|
10
10
|
* members and replay held inputs, run the op, then persist the snapshot at `revision + 1` iff the world changed.
|
|
11
|
-
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
12
13
|
export function invokeHostedWorld(invocation) {
|
|
13
14
|
const { game, store, members = [], inputs = {}, now, op } = invocation;
|
|
14
15
|
const loaded = store.load();
|
|
@@ -18,6 +19,7 @@ export function invokeHostedWorld(invocation) {
|
|
|
18
19
|
content: game.content,
|
|
19
20
|
store: { load: () => loaded, save: () => { } },
|
|
20
21
|
...(now === undefined ? {} : { now }),
|
|
22
|
+
...(game.models === undefined ? {} : { models: game.models }),
|
|
21
23
|
});
|
|
22
24
|
for (const userId of members)
|
|
23
25
|
session.runner().resume(userId);
|
|
@@ -94,7 +96,8 @@ async function persistWorldRow(ctx, args) {
|
|
|
94
96
|
* reconstructing a hosted session from the persisted `jgHostedWorlds` row on every invocation via
|
|
95
97
|
* {@link invokeHostedWorld}. Destructure + re-export the returned functions from a `convex/` module and
|
|
96
98
|
* drive `tickHostedWorlds` from a cron. Requires {@link jgengineHostedTables} in the deployment schema.
|
|
97
|
-
|
|
99
|
+
* @internal
|
|
100
|
+
*/
|
|
98
101
|
export function createHostedGameServerFunctions(options) {
|
|
99
102
|
const mode = options.auth ?? "anonymous";
|
|
100
103
|
const tickMs = options.tickMs ?? JG_HOSTED_TICK_MS;
|
|
@@ -302,7 +305,10 @@ export function createHostedGameServerFunctions(options) {
|
|
|
302
305
|
args: {},
|
|
303
306
|
handler: async (ctx) => {
|
|
304
307
|
const nowMs = Date.now();
|
|
305
|
-
const rows = await ctx.db
|
|
308
|
+
const rows = await ctx.db
|
|
309
|
+
.query("jgHostedWorlds")
|
|
310
|
+
.withIndex("by_tick_anchor", (q) => q.lte("tickAnchorMs", nowMs - tickMs))
|
|
311
|
+
.collect();
|
|
306
312
|
let ticked = 0;
|
|
307
313
|
let saved = 0;
|
|
308
314
|
for (const row of rows) {
|
|
@@ -312,8 +318,6 @@ export function createHostedGameServerFunctions(options) {
|
|
|
312
318
|
if (row.memberUserIds.length === 0)
|
|
313
319
|
continue;
|
|
314
320
|
const elapsedMs = nowMs - row.tickAnchorMs;
|
|
315
|
-
if (elapsedMs < tickMs)
|
|
316
|
-
continue;
|
|
317
321
|
const { store, captured } = worldStoreForRow(row);
|
|
318
322
|
const outcome = invokeHostedWorld({
|
|
319
323
|
game,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from "./convexChatTransport.js";
|
|
2
2
|
export * from "./convexPresenceTransport.js";
|
|
3
3
|
export * from "./createConvexBackend.js";
|
|
4
|
+
export * from "./convexSaveBackend.js";
|
|
4
5
|
export * from "./createConvexGameTransport.js";
|
|
5
6
|
export * from "./hostedServer.js";
|
|
6
7
|
export * from "./occ.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from "./convexChatTransport.js";
|
|
2
2
|
export * from "./convexPresenceTransport.js";
|
|
3
3
|
export * from "./createConvexBackend.js";
|
|
4
|
+
export * from "./convexSaveBackend.js";
|
|
4
5
|
export * from "./createConvexGameTransport.js";
|
|
5
6
|
export * from "./hostedServer.js";
|
|
6
7
|
export * from "./occ.js";
|
package/dist/occ.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { GameRuntime } from "@jgengine/core/runtime/gameRuntime";
|
|
2
2
|
import type { GameRuntimeSnapshot } from "@jgengine/core/runtime/snapshot";
|
|
3
3
|
export declare const REVISION_CONFLICT_REASON = "Revision conflict";
|
|
4
|
+
/** @internal */
|
|
4
5
|
export declare function commitIfRevisionMatch(loadedRevision: number, currentRevision: number): {
|
|
5
6
|
ok: true;
|
|
6
7
|
} | {
|
|
7
8
|
ok: false;
|
|
8
9
|
reason: string;
|
|
9
10
|
};
|
|
11
|
+
/** @internal */
|
|
10
12
|
export declare function applyCommandWithOcc(args: {
|
|
11
13
|
loadedRevision: number;
|
|
12
14
|
currentRevision: number;
|
package/dist/occ.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
export const REVISION_CONFLICT_REASON = "Revision conflict";
|
|
2
|
+
/** @internal */
|
|
2
3
|
export function commitIfRevisionMatch(loadedRevision, currentRevision) {
|
|
3
4
|
if (currentRevision !== loadedRevision) {
|
|
4
5
|
return { ok: false, reason: REVISION_CONFLICT_REASON };
|
|
5
6
|
}
|
|
6
7
|
return { ok: true };
|
|
7
8
|
}
|
|
9
|
+
/** @internal */
|
|
8
10
|
export function applyCommandWithOcc(args) {
|
|
9
11
|
const gate = commitIfRevisionMatch(args.loadedRevision, args.currentRevision);
|
|
10
12
|
if (!gate.ok)
|
package/dist/server.d.ts
CHANGED
|
@@ -5,6 +5,9 @@ import type { ChatSendOutcome } from "@jgengine/core/multiplayer/chatContract";
|
|
|
5
5
|
import { type PoseSyncRules } from "@jgengine/core/multiplayer/presenceModel";
|
|
6
6
|
import type { GameRuntime } from "@jgengine/core/runtime/gameRuntime";
|
|
7
7
|
import type { LeaderboardIncrement } from "@jgengine/core/runtime/hostPersistence";
|
|
8
|
+
/** @internal Re-export shared host-policy pure helpers so existing convex imports keep working. */
|
|
9
|
+
export { canJoinPrivateServer, isListablePublicly, } from "@jgengine/core/runtime/hostPolicy";
|
|
10
|
+
/** @internal */
|
|
8
11
|
export declare function jgengineTables(): {
|
|
9
12
|
jgGameServers: import("convex/server").TableDefinition<import("convex/values").VObject<{
|
|
10
13
|
createdAt: number;
|
|
@@ -55,7 +58,9 @@ export declare function jgengineTables(): {
|
|
|
55
58
|
createdAt: import("convex/values").VFloat64<number, "required">;
|
|
56
59
|
updatedAt: import("convex/values").VFloat64<number, "required">;
|
|
57
60
|
}, "required", "createdAt" | "dirtyAt" | "gameId" | "joinCode" | "lastSavedAt" | "memberUserIds" | "mode" | "modeConfig" | "revision" | "save" | "save.auto" | "save.scope" | "serverState" | "sessionPlayers" | "slotsPerServer" | "status" | "tickAnchorMs" | "updatedAt" | "visibility" | `modeConfig.${string}` | `serverState.${string}` | `sessionPlayers.${string}`>, {
|
|
61
|
+
by_dirty: ["dirtyAt", "_creationTime"];
|
|
58
62
|
by_game_and_status: ["gameId", "status", "_creationTime"];
|
|
63
|
+
by_status: ["status", "_creationTime"];
|
|
59
64
|
}, {}, {}>;
|
|
60
65
|
jgPlayerProfiles: import("convex/server").TableDefinition<import("convex/values").VObject<{
|
|
61
66
|
createdAt: number;
|
|
@@ -167,7 +172,8 @@ export declare function jgengineTables(): {
|
|
|
167
172
|
* Convex table for the hosted GameContext-world path: one row per (gameId, serverId) holding the full
|
|
168
173
|
* `WorldSnapshot` blob, its revision, the member roster, and each member's held input. A sibling of
|
|
169
174
|
* {@link jgengineTables} — spread either (or both) into `defineSchema`.
|
|
170
|
-
|
|
175
|
+
* @internal
|
|
176
|
+
*/
|
|
171
177
|
export declare function jgengineHostedTables(): {
|
|
172
178
|
jgHostedWorlds: import("convex/server").TableDefinition<import("convex/values").VObject<{
|
|
173
179
|
createdAt: number;
|
|
@@ -191,6 +197,7 @@ export declare function jgengineHostedTables(): {
|
|
|
191
197
|
updatedAt: import("convex/values").VFloat64<number, "required">;
|
|
192
198
|
}, "required", "createdAt" | "gameId" | "inputs" | "memberUserIds" | "revision" | "serverId" | "snapshot" | "tickAnchorMs" | "updatedAt" | `inputs.${string}` | `snapshot.${string}`>, {
|
|
193
199
|
by_game_and_server: ["gameId", "serverId", "_creationTime"];
|
|
200
|
+
by_tick_anchor: ["tickAnchorMs", "_creationTime"];
|
|
194
201
|
}, {}, {}>;
|
|
195
202
|
};
|
|
196
203
|
declare const schemaForTypes: import("convex/server").SchemaDefinition<{
|
|
@@ -243,7 +250,9 @@ declare const schemaForTypes: import("convex/server").SchemaDefinition<{
|
|
|
243
250
|
createdAt: import("convex/values").VFloat64<number, "required">;
|
|
244
251
|
updatedAt: import("convex/values").VFloat64<number, "required">;
|
|
245
252
|
}, "required", "createdAt" | "dirtyAt" | "gameId" | "joinCode" | "lastSavedAt" | "memberUserIds" | "mode" | "modeConfig" | "revision" | "save" | "save.auto" | "save.scope" | "serverState" | "sessionPlayers" | "slotsPerServer" | "status" | "tickAnchorMs" | "updatedAt" | "visibility" | `modeConfig.${string}` | `serverState.${string}` | `sessionPlayers.${string}`>, {
|
|
253
|
+
by_dirty: ["dirtyAt", "_creationTime"];
|
|
246
254
|
by_game_and_status: ["gameId", "status", "_creationTime"];
|
|
255
|
+
by_status: ["status", "_creationTime"];
|
|
247
256
|
}, {}, {}>;
|
|
248
257
|
jgPlayerProfiles: import("convex/server").TableDefinition<import("convex/values").VObject<{
|
|
249
258
|
createdAt: number;
|
|
@@ -355,12 +364,16 @@ type JGDataModel = DataModelFromSchemaDefinition<typeof schemaForTypes>;
|
|
|
355
364
|
type JGMutationCtx = GenericMutationCtx<JGDataModel>;
|
|
356
365
|
export type JgAuthMode = "anonymous" | "required";
|
|
357
366
|
export declare const DEFAULT_CONVEX_POSE_RULES: PoseSyncRules;
|
|
358
|
-
/** Resolve the acting user id under a {@link JgAuthMode}: the Convex identity when signed in (rejecting a mismatched claim), the claimed external id under `"anonymous"`, else `null`.
|
|
367
|
+
/** Resolve the acting user id under a {@link JgAuthMode}: the Convex identity when signed in (rejecting a mismatched claim), the claimed external id under `"anonymous"`, else `null`.
|
|
368
|
+
* @internal
|
|
369
|
+
*/
|
|
359
370
|
export declare function resolveActor(ctx: {
|
|
360
371
|
auth: Auth;
|
|
361
372
|
}, claimedExternalId: string | undefined, mode: JgAuthMode): Promise<string | null>;
|
|
373
|
+
/** @internal */
|
|
362
374
|
export declare function applyLeaderboardIncrements(ctx: JGMutationCtx, gameId: string, entries: LeaderboardIncrement[]): Promise<void>;
|
|
363
375
|
export declare const JG_RUNTIME_TICK_MS = 1000;
|
|
376
|
+
/** @internal */
|
|
364
377
|
export declare function createGameServerFunctions(options?: {
|
|
365
378
|
runtimes?: GameRuntime[];
|
|
366
379
|
auth?: JgAuthMode;
|
|
@@ -460,6 +473,7 @@ export declare function createGameServerFunctions(options?: {
|
|
|
460
473
|
saved: number;
|
|
461
474
|
}>>;
|
|
462
475
|
};
|
|
476
|
+
/** @internal */
|
|
463
477
|
export declare function createLeaderboardFunctions(options?: {
|
|
464
478
|
auth?: JgAuthMode;
|
|
465
479
|
}): {
|
|
@@ -490,6 +504,7 @@ export declare function createLeaderboardFunctions(options?: {
|
|
|
490
504
|
gameId: string;
|
|
491
505
|
}, Promise<null>>;
|
|
492
506
|
};
|
|
507
|
+
/** @internal */
|
|
493
508
|
export declare function createPresenceFunctions(options?: {
|
|
494
509
|
auth?: JgAuthMode;
|
|
495
510
|
freshWindowMs?: number;
|
|
@@ -525,6 +540,7 @@ export declare function createPresenceFunctions(options?: {
|
|
|
525
540
|
serverId: string;
|
|
526
541
|
}, Promise<null>>;
|
|
527
542
|
};
|
|
543
|
+
/** @internal */
|
|
528
544
|
export declare function createChatFunctions(options?: {
|
|
529
545
|
auth?: JgAuthMode;
|
|
530
546
|
historyLimit?: number;
|
|
@@ -548,5 +564,5 @@ export type JgCronSpec = {
|
|
|
548
564
|
intervalSeconds: number;
|
|
549
565
|
functionKey: "tickActiveServers" | "flushDirtyServers";
|
|
550
566
|
};
|
|
567
|
+
/** @internal */
|
|
551
568
|
export declare function jgengineCronSpecs(): readonly JgCronSpec[];
|
|
552
|
-
export {};
|