@volter/twin-inngest 0.1.1 → 0.1.3
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.
|
@@ -13,9 +13,11 @@
|
|
|
13
13
|
import { serveHttp } from '@volter/world-core';
|
|
14
14
|
import { handleInngestTwinRequest } from "./inngest-twin.js";
|
|
15
15
|
import { rows } from "./inngest-runtime.js";
|
|
16
|
-
import { createTwinFetchFromHandler, statefulTwinManifest } from '@volter/world-core';
|
|
16
|
+
import { createTwinFetchFromHandler, statefulTwinManifest, withRequestScopes } from '@volter/world-core';
|
|
17
17
|
export function createInngestTwinFetch(options = {}) {
|
|
18
|
-
|
|
18
|
+
// a read-only request (x-volter-read-only) is a request to a read-only twin: a run poll answers the run
|
|
19
|
+
// as it stands without running a step, nothing is written (withRequestScopes: the pack opts in)
|
|
20
|
+
return withRequestScopes(createTwinFetchFromHandler(handleInngestTwinRequest, {
|
|
19
21
|
...options,
|
|
20
22
|
manifest: statefulTwinManifest({ vendor: 'inngest', twinOf: 'the Inngest durable-execution surface', stores: 'events, registered functions and their kernel-persisted run state' }),
|
|
21
23
|
// THE STORE DOOR (R5c). The vendor's own read surface is addressed BY ID
|
|
@@ -29,7 +31,7 @@ export function createInngestTwinFetch(options = {}) {
|
|
|
29
31
|
runs: () => rows('run', options.root),
|
|
30
32
|
},
|
|
31
33
|
extras: (_request, url) => ({ host: url.host }),
|
|
32
|
-
});
|
|
34
|
+
}), { refuse: () => Response.json({ error: 'read_only', hint: 'this twin was started read-only; omit readOnly to accept writes' }, { status: 405 }) });
|
|
33
35
|
}
|
|
34
36
|
export async function createInngestTwinServer(options = {}) {
|
|
35
37
|
const server = await serveHttp({
|
package/dist/src/inngest-twin.js
CHANGED
|
@@ -245,7 +245,9 @@ async function handleGetRun(runId, req) {
|
|
|
245
245
|
const existing = getRow('run', runId, req.root);
|
|
246
246
|
if (!existing)
|
|
247
247
|
return apiError(404, 'run_not_found', `No run with id "${runId}".`);
|
|
248
|
-
|
|
248
|
+
// poll-fold advance on read (fal-twin.ts progressOnce pattern). A read-only twin (a World's read
|
|
249
|
+
// token) answers the run as it stands and never runs a step: the app's next poll sees what it would have.
|
|
250
|
+
const result = req.readOnly ? undefined : await advanceRun(runId, req.root, req.occurredAt);
|
|
249
251
|
const row = result?.run ?? existing;
|
|
250
252
|
return { status: 200, body: { data: runView(row), metadata: { fetchedAt: nowIso(req.occurredAt) } } };
|
|
251
253
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/twin-inngest",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Local Inngest twin for the durable-execution workflow-orchestration surface: event send/batch (Event API), function register/introspect (SDK exec protocol), and a REAL kernel-persisted step-machine (step.run memoize/replay, sleep/sleepUntil instant-advance, waitForEvent gating, exact retry-attempt counters), run status/get/list/cancel-via-event, HMAC-SHA256 executor<->SDK request signing, built on @volter/world-core.",
|
|
5
5
|
"author": "Volter (https://github.com/volter-ai)",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
"postpack": "node ../../../scripts/publish/prepare-publish.mjs postpack"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
|
-
"@volter/world-core": "2.0.
|
|
38
|
+
"@volter/world-core": "2.0.3"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/bun": "^1.2.20",
|
|
42
42
|
"@types/node": "^24.0.0",
|
|
43
|
-
"@volter/world-core": "2.0.
|
|
43
|
+
"@volter/world-core": "2.0.3",
|
|
44
44
|
"@volter/world-tooling": "0.1.0",
|
|
45
45
|
"inngest": "4.12.0",
|
|
46
46
|
"typescript": "^5.9.0"
|
package/src/inngest-server.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import { serveHttp } from '@volter/world-core';
|
|
14
14
|
import { handleInngestTwinRequest } from './inngest-twin.ts';
|
|
15
15
|
import { rows } from './inngest-runtime.ts';
|
|
16
|
-
import { createTwinFetchFromHandler, statefulTwinManifest } from '@volter/world-core';
|
|
16
|
+
import { createTwinFetchFromHandler, statefulTwinManifest, withRequestScopes } from '@volter/world-core';
|
|
17
17
|
|
|
18
18
|
/** Options every Inngest-twin HTTP surface needs, independent of who owns the socket. */
|
|
19
19
|
export interface InngestTwinFetchOptions {
|
|
@@ -22,7 +22,9 @@ export interface InngestTwinFetchOptions {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export function createInngestTwinFetch(options: InngestTwinFetchOptions = {}): (request: Request) => Promise<Response> {
|
|
25
|
-
|
|
25
|
+
// a read-only request (x-volter-read-only) is a request to a read-only twin: a run poll answers the run
|
|
26
|
+
// as it stands without running a step, nothing is written (withRequestScopes: the pack opts in)
|
|
27
|
+
return withRequestScopes(createTwinFetchFromHandler(handleInngestTwinRequest, {
|
|
26
28
|
...options,
|
|
27
29
|
manifest: statefulTwinManifest({ vendor: 'inngest', twinOf: 'the Inngest durable-execution surface', stores: 'events, registered functions and their kernel-persisted run state' }),
|
|
28
30
|
// THE STORE DOOR (R5c). The vendor's own read surface is addressed BY ID
|
|
@@ -36,7 +38,7 @@ export function createInngestTwinFetch(options: InngestTwinFetchOptions = {}): (
|
|
|
36
38
|
runs: () => rows('run', options.root),
|
|
37
39
|
},
|
|
38
40
|
extras: (_request, url) => ({ host: url.host }),
|
|
39
|
-
});
|
|
41
|
+
}), { refuse: () => Response.json({ error: 'read_only', hint: 'this twin was started read-only; omit readOnly to accept writes' }, { status: 405 }) });
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
export async function createInngestTwinServer(options: { root?: string; port?: number; readOnly?: boolean } = {}): Promise<{ port: number; stop: () => void }> {
|
package/src/inngest-twin.ts
CHANGED
|
@@ -274,7 +274,9 @@ async function handleExecInvoke(rawBody: string | undefined, req: InngestRequest
|
|
|
274
274
|
async function handleGetRun(runId: string, req: InngestRequest): Promise<InngestResponse> {
|
|
275
275
|
const existing = getRow('run', runId, req.root);
|
|
276
276
|
if (!existing) return apiError(404, 'run_not_found', `No run with id "${runId}".`);
|
|
277
|
-
|
|
277
|
+
// poll-fold advance on read (fal-twin.ts progressOnce pattern). A read-only twin (a World's read
|
|
278
|
+
// token) answers the run as it stands and never runs a step: the app's next poll sees what it would have.
|
|
279
|
+
const result = req.readOnly ? undefined : await advanceRun(runId, req.root, req.occurredAt);
|
|
278
280
|
const row = result?.run ?? existing;
|
|
279
281
|
return { status: 200, body: { data: runView(row), metadata: { fetchedAt: nowIso(req.occurredAt) } } };
|
|
280
282
|
}
|