@effectstream/runtime 0.100.14 → 0.100.15

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/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # @effectstream/runtime
2
+
3
+ The state-machine runtime — the loop that ties sync, state machine,
4
+ database, events, and HTTP API together inside an EffectStream node.
5
+ Boot it with `init()` then drive it with `start(config)` and your node
6
+ is up.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ bun add @effectstream/runtime
12
+ # or
13
+ npm install @effectstream/runtime
14
+ ```
15
+
16
+ `@effectstream/runtime` is the canonical import for `init` and `start`,
17
+ used directly by every template. The same surface is also reachable
18
+ through `@effectstream/node-sdk/runtime` if you prefer the umbrella.
19
+
20
+ ## Standalone usage
21
+
22
+ This package **owns the node's process model**. You don't pick parts of
23
+ it; you call `init()` once at boot and then `start(config)`. The config
24
+ brings together everything else:
25
+
26
+ ```typescript
27
+ import { init, start } from "@effectstream/runtime";
28
+ import { Stm } from "@effectstream/sm";
29
+ import { config } from "./config.dev.ts";
30
+
31
+ await init();
32
+
33
+ const gameStm = new Stm(grammar);
34
+ gameStm.addStateTransition("join", function* () { /* ... */ });
35
+
36
+ await start({
37
+ config,
38
+ gameStateTransitions: [gameStm],
39
+ apiRouter: undefined, // optional Fastify route plugin
40
+ dbMigrations: [], // SQL migrations
41
+ });
42
+ ```
43
+
44
+ While running, the runtime:
45
+
46
+ - Reads finalized blocks via `@effectstream/sync`.
47
+ - Routes batcher inputs through your registered `Stm`s.
48
+ - Commits all yielded SQL inside a per-block transaction.
49
+ - Publishes lifecycle and app events via `@effectstream/event-server`.
50
+ - Serves the optional Fastify API.
51
+ - Emits OpenTelemetry traces and logs through `@effectstream/log`.
52
+
53
+ ## Inside EffectStream
54
+
55
+ `@effectstream/runtime` is the conductor: it doesn't define any chain
56
+ integrations or queries itself, but every other node package only gets
57
+ exercised when this loop is running. The `StartConfig` shape determines
58
+ which DB migrations apply, which state machines fire, and whether the
59
+ runtime exposes a Fastify router.
60
+
61
+ ## Key exports
62
+
63
+ - `init()` — `Operation<void>`. One-shot setup: OpenTelemetry, config validation, version pinning. Call before `start`.
64
+ - `start(config: StartConfig)` — `Operation<void>`. Run the node loop until cancelled.
65
+
66
+ Types and helpers re-exported alongside `init` / `start`:
67
+
68
+ - `DBMigrations` — versioned SQL migrations passed into `start`.
69
+ - `StartConfig`, `StartConfigGameStateTransitions`, `StartConfigApiRouter` — `start`'s config types. Templates type-check against these implicitly but don't usually import them by name.
70
+ - `PrimitiveConstructor<T>` — extension point for new primitives.
71
+ - `VERSION` — `${number}.${number}.${number}` literal type for version pinning.
72
+ - Pagination helpers re-exported from `./api/pagination.ts`.
73
+
74
+ ## Examples
75
+
76
+ The templates under
77
+ [`templates/`](https://github.com/PaimaStudios/paima-engine/tree/main/templates)
78
+ are full working `init()` + `start()` examples. The simplest is
79
+ [`templates/minimal/`](https://github.com/PaimaStudios/paima-engine/tree/main/templates/minimal).
80
+
81
+ End-to-end EVM sync test:
82
+ [`e2e/evm/sync/`](https://github.com/PaimaStudios/paima-engine/tree/main/e2e/evm/sync).
83
+
84
+ Runnable: [`test/examples.test.ts`](./test/examples.test.ts).
85
+
86
+ ## Links
87
+
88
+ - Docs: https://effectstream.github.io/docs/packages/node/runtime
89
+ - Source: https://github.com/PaimaStudios/paima-engine/tree/main/packages/node-sdk/runtime
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effectstream/runtime",
3
- "version": "0.100.14",
3
+ "version": "0.100.15",
4
4
  "license": "MIT",
5
5
  "homepage": "https://effectstream.github.io/docs/",
6
6
  "repository": {
@@ -13,17 +13,17 @@
13
13
  },
14
14
  "exports": "./src/mod.ts",
15
15
  "dependencies": {
16
- "@effectstream/concise": "0.100.14",
17
- "@effectstream/config": "0.100.14",
18
- "@effectstream/coroutine": "0.100.14",
19
- "@effectstream/crypto": "0.100.14",
20
- "@effectstream/db": "0.100.14",
21
- "@effectstream/event-client": "0.100.14",
22
- "@effectstream/event-server": "0.100.14",
23
- "@effectstream/log": "0.100.14",
24
- "@effectstream/sm": "0.100.14",
25
- "@effectstream/sync": "0.100.14",
26
- "@effectstream/utils": "0.100.14",
16
+ "@effectstream/concise": "0.100.15",
17
+ "@effectstream/config": "0.100.15",
18
+ "@effectstream/coroutine": "0.100.15",
19
+ "@effectstream/crypto": "0.100.15",
20
+ "@effectstream/db": "0.100.15",
21
+ "@effectstream/event-client": "0.100.15",
22
+ "@effectstream/event-server": "0.100.15",
23
+ "@effectstream/log": "0.100.15",
24
+ "@effectstream/sm": "0.100.15",
25
+ "@effectstream/sync": "0.100.15",
26
+ "@effectstream/utils": "0.100.15",
27
27
  "@fastify/cors": "^11.0.1",
28
28
  "@metamask/json-rpc-engine": "^10.0.3",
29
29
  "pg": "8.17.2",
@@ -46,7 +46,7 @@ import {
46
46
  type TypePaginationQuerySchema,
47
47
  } from "./pagination.ts";
48
48
  import { PrimitiveRegistry } from "@effectstream/sm";
49
- import { ConfigNetworkType } from "@effectstream/config";
49
+ import { ConfigNetworkType, getWriteNamespace, usePaimaStaticConfig } from "@effectstream/config";
50
50
 
51
51
  function tableListContains(
52
52
  list: Array<{ table_name: string | null }>,
@@ -470,26 +470,36 @@ export const startHttpServer = function* (
470
470
  return cleanedProtocols;
471
471
  });
472
472
 
473
+ const staticConfigForRoute = yield* usePaimaStaticConfig();
474
+ const securityNamespaceForRoute = getWriteNamespace(
475
+ staticConfigForRoute.securityNamespace,
476
+ );
477
+
473
478
  server.get("/config", {
474
479
  schema: {
475
480
  tags: ["developer"],
476
481
  response: {
477
- 200: Type.Array(Type.Object({
478
- networkType: Type.String(),
479
- syncProtocolType: Type.String(),
480
- syncProtocol: Type.Object({}, { additionalProperties: true }),
481
- network: Type.Object({}, { additionalProperties: true }),
482
- primitives: Type.Array(
483
- Type.Object({}, { additionalProperties: true }),
484
- ),
485
- }, { additionalProperties: true })),
482
+ 200: Type.Object({
483
+ securityNamespace: Type.Union([Type.String(), Type.Null()]),
484
+ syncProtocols: Type.Array(Type.Object({
485
+ networkType: Type.String(),
486
+ syncProtocolType: Type.String(),
487
+ syncProtocol: Type.Object({}, { additionalProperties: true }),
488
+ network: Type.Object({}, { additionalProperties: true }),
489
+ primitives: Type.Array(
490
+ Type.Object({}, { additionalProperties: true }),
491
+ ),
492
+ }, { additionalProperties: true })),
493
+ }),
486
494
  },
487
495
  },
488
496
  }, () => {
489
497
  const config = syncProtocols.map((syncProtocol) => syncProtocol.config)
490
498
  .flat();
491
- const cleanedConfig = clearBigInts(config);
492
- return cleanedConfig;
499
+ return {
500
+ securityNamespace: securityNamespaceForRoute,
501
+ syncProtocols: clearBigInts(config),
502
+ };
493
503
  });
494
504
  }
495
505
 
package/src/main.ts CHANGED
@@ -36,7 +36,8 @@ import type { Client } from "pg";
36
36
  import type { EffectstreamBlockHash } from "@effectstream/utils";
37
37
  import { applySystemMigrations } from "./version-migrations.ts";
38
38
  import { getLastBlockHeight, getVersionInfo } from "@effectstream/db/version";
39
- import { type SyncProtocolWithNetwork, ConfigNetworkType } from "@effectstream/config";
39
+ import { ConfigNetworkType, usePaimaStaticConfig } from "@effectstream/config";
40
+ import type { SecurityNamespace, SyncProtocolWithNetwork } from "@effectstream/config";
40
41
  import { builtInPrimitivesMap } from "@effectstream/sm";
41
42
  import { validateAndSnapshotConfig } from "./config-snapshot.ts";
42
43
 
@@ -275,12 +276,16 @@ function* startup(
275
276
  ): Operation<AllSyncProtocols[]> {
276
277
  const versionInfo = yield* getVersionInfo(dbConn);
277
278
  const lastBlockHeight = yield* getLastBlockHeight(versionInfo, dbConn);
279
+ // Pull the security namespace from the static config so primitives that
280
+ // re-verify batched signatures can access it synchronously.
281
+ const staticConfig = yield* usePaimaStaticConfig();
278
282
  // Create Runtime Primitives Instances
279
283
  syncInfo.forEach((syncProtocol) => {
280
284
  syncProtocol.primitives.forEach((primitive, primitiveIndex) => {
281
285
  processPrimitives(
282
286
  syncProtocol.primitives,
283
287
  primitiveIndex,
288
+ staticConfig.securityNamespace,
284
289
  config.userDefinedPrimitives
285
290
  );
286
291
  });
@@ -327,6 +332,7 @@ function* startup(
327
332
  const processPrimitives = (
328
333
  primitives: {primitive: any, id: string}[],
329
334
  primitiveIndex: number,
335
+ securityNamespace: SecurityNamespace | undefined,
330
336
  userDefinedPrimitives?: Record<string, any>,
331
337
  ) => {
332
338
  const primitiveType = primitives[primitiveIndex].primitive.type;
@@ -349,6 +355,7 @@ const processPrimitives = (
349
355
  const classConfig = {
350
356
  ...primitiveConfig,
351
357
  instanceName: primitiveUniqueName,
358
+ securityNamespace,
352
359
  }
353
360
  if (isBuiltInPrimitive) {
354
361
  p = new builtInPrimitivesMap[primitiveType as keyof typeof builtInPrimitivesMap](classConfig as any) ;
@@ -0,0 +1,14 @@
1
+ // Examples for the README — verify the public surface resolves.
2
+
3
+ import { test, expect } from "bun:test";
4
+ import * as runtime from "../src/mod.ts";
5
+
6
+ test("README: init and start are exported as generator functions", () => {
7
+ expect(typeof runtime.init).toBe("function");
8
+ expect(typeof runtime.start).toBe("function");
9
+ });
10
+
11
+ test("README: pagination helpers are re-exported", async () => {
12
+ const pagination = await import("../src/api/pagination.ts");
13
+ expect(Object.keys(pagination).length).toBeGreaterThan(0);
14
+ });