@ontahi/runtime-nextjs 1.0.0-alpha.11 → 1.0.0-alpha.13
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 +61 -7
- package/dist/event-ingress/index.d.ts +3 -0
- package/dist/event-ingress/index.d.ts.map +1 -0
- package/dist/event-ingress/index.js +2 -0
- package/dist/event-ingress/index.js.map +1 -0
- package/dist/event-ingress/route.d.ts +10 -0
- package/dist/event-ingress/route.d.ts.map +1 -0
- package/dist/event-ingress/route.js +31 -0
- package/dist/event-ingress/route.js.map +1 -0
- package/dist/graph-read/route.d.ts.map +1 -1
- package/dist/graph-read/route.js +5 -3
- package/dist/graph-read/route.js.map +1 -1
- package/dist/runtime-protocol/route.d.ts +4 -2
- package/dist/runtime-protocol/route.d.ts.map +1 -1
- package/dist/runtime-protocol/route.js +20 -13
- package/dist/runtime-protocol/route.js.map +1 -1
- package/package.json +10 -3
package/README.md
CHANGED
|
@@ -13,6 +13,8 @@ This package depends on `@ontahi/core` and owns the Next.js / `next-safe-action`
|
|
|
13
13
|
4. `@ontahi/runtime-nextjs/graph-read`: an App Router adapter for policy-scoped remote data graph reads.
|
|
14
14
|
5. `@ontahi/runtime-nextjs/runtime-protocol`: an App Router adapter for an injected common Runtime
|
|
15
15
|
Protocol dispatcher and receiver-owned context factory.
|
|
16
|
+
6. `@ontahi/runtime-nextjs/event-ingress`: an App Router adapter that passes the original `Request`
|
|
17
|
+
to a provider for authentication and normalization before ingesting a declared Event.
|
|
16
18
|
|
|
17
19
|
New generic consumers should import action metadata and result helpers from `@ontahi/core/runtime/actions`. React hooks and operation bridge adapters live in `@ontahi/react/actions` so this package can stay focused on Next.js runtime concerns.
|
|
18
20
|
|
|
@@ -24,12 +26,19 @@ Export a `POST` handler from an App Router route such as `app/api/runtime/route.
|
|
|
24
26
|
import { createRuntimeProtocolDispatcher } from '@ontahi/core/runtime/protocol';
|
|
25
27
|
import { createNextRuntimeProtocolRouteHandler } from '@ontahi/runtime-nextjs/runtime-protocol';
|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
type RuntimeAuthority = {
|
|
30
|
+
principal: Awaited<ReturnType<typeof resolvePrincipal>>;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const dispatcher = createRuntimeProtocolDispatcher<RuntimeAuthority>({
|
|
28
34
|
handlers: {
|
|
29
|
-
operation:
|
|
35
|
+
operation: (request, authority) =>
|
|
36
|
+
TodoApplication.app.runtime.withInvocationContext(authority, () =>
|
|
37
|
+
operationDispatcher(request),
|
|
38
|
+
),
|
|
30
39
|
'durable.operation': durableObservationHandler,
|
|
31
|
-
'graph.read': graphReadDispatcher,
|
|
32
|
-
'graph.command': graphCommandDispatcher,
|
|
40
|
+
'graph.read': (request, authority) => graphReadDispatcher(request, { authority }),
|
|
41
|
+
'graph.command': (request, authority) => graphCommandDispatcher(request, { authority }),
|
|
33
42
|
},
|
|
34
43
|
});
|
|
35
44
|
|
|
@@ -44,13 +53,27 @@ export const POST = createNextRuntimeProtocolRouteHandler({
|
|
|
44
53
|
The adapter validates JSON, the common envelope, and the canonical family body before calling the
|
|
45
54
|
context factory. It installs no handlers, policies, authorization, or capabilities; the host owns
|
|
46
55
|
the dispatcher and derives trusted context only from the received server request. All registered
|
|
47
|
-
families pass through the same dispatcher without Next.js-specific routing.
|
|
56
|
+
families pass through the same dispatcher without Next.js-specific routing. Family adapters feed
|
|
57
|
+
the server-derived context to the canonical Operation and Graph policy boundaries; clients never
|
|
58
|
+
author authority or policies.
|
|
59
|
+
|
|
60
|
+
Point the Fetch client at the App Router route once; Operations, Graph Reads, Graph Commands, and
|
|
61
|
+
Durable inspection then share that Runtime Transport:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { createFetchGraphClient } from '@ontahi/react/graph';
|
|
65
|
+
|
|
66
|
+
const client = createFetchGraphClient({
|
|
67
|
+
runtimeTransport: { endpoint: '/api/runtime' },
|
|
68
|
+
});
|
|
69
|
+
```
|
|
48
70
|
|
|
49
71
|
Common invalid requests return `400`, a known family without an installed handler returns `501`,
|
|
50
72
|
unavailable dispatch returns `503`, invalid upstream responses return `502`, and complete family
|
|
51
73
|
responses—including semantic rejections and family protocol errors—return `200`. Existing
|
|
52
|
-
`operation-invocation` and `graph-read` adapters remain
|
|
53
|
-
|
|
74
|
+
`operation-invocation` and `graph-read` adapters remain explicit compatibility surfaces. Select
|
|
75
|
+
them with `createFetchGraphClient({ compatibility: ... })` only while a host is migrating; the
|
|
76
|
+
client never falls back or replays a transmitted request against a second endpoint.
|
|
54
77
|
|
|
55
78
|
## Operation invocation
|
|
56
79
|
|
|
@@ -105,3 +128,34 @@ export const POST = createNextGraphReadRouteHandler({
|
|
|
105
128
|
Malformed graph programs return `400`, denied reads return `403`, unavailable execution returns
|
|
106
129
|
`503`, and successful reads return `200`. Caller-provided authority in the request body is never
|
|
107
130
|
used to authorize dispatch.
|
|
131
|
+
|
|
132
|
+
## Event ingress
|
|
133
|
+
|
|
134
|
+
Bind one App Router endpoint to an explicit Event declaration identity, provider, and channel. The
|
|
135
|
+
provider receives the original Web `Request`, so signature verification can use the unmodified raw
|
|
136
|
+
body before returning a normalized domain payload:
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
import { createNextEventIngressRouteHandler } from '@ontahi/runtime-nextjs/event-ingress';
|
|
140
|
+
|
|
141
|
+
import { TodoApplication, TodoListExportReady } from '@/application';
|
|
142
|
+
import { githubWebhookProvider } from '@/github-webhooks';
|
|
143
|
+
|
|
144
|
+
export const POST = createNextEventIngressRouteHandler({
|
|
145
|
+
events: TodoApplication.events,
|
|
146
|
+
route: {
|
|
147
|
+
eventId: TodoListExportReady.id,
|
|
148
|
+
eventVersion: TodoListExportReady.version,
|
|
149
|
+
method: 'POST',
|
|
150
|
+
route: '/api/events/export-ready',
|
|
151
|
+
provider: 'github-webhook',
|
|
152
|
+
channel: 'todo.export-ready',
|
|
153
|
+
},
|
|
154
|
+
providers: { 'github-webhook': githubWebhookProvider },
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The provider owns authentication and normalization. Ontahi matches the accepted provider identity
|
|
159
|
+
and channel against the explicit route, validates the payload against the registered declaration,
|
|
160
|
+
and only then creates the Event occurrence. Rejected or ignored deliveries never materialize an
|
|
161
|
+
occurrence.
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { createNextEventIngressRouteHandler, type CreateNextEventIngressRouteHandlerOptions, } from './route.js';
|
|
2
|
+
export type { GraphHttpEventIngressRoute, GraphHttpIngressProvider, GraphHttpIngressProviderRegistry, } from '@ontahi/core/runtime/server/ingress';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/event-ingress/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kCAAkC,EAClC,KAAK,yCAAyC,GAC/C,MAAM,YAAY,CAAC;AAEpB,YAAY,EACV,0BAA0B,EAC1B,wBAAwB,EACxB,gCAAgC,GACjC,MAAM,qCAAqC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/event-ingress/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kCAAkC,GAEnC,MAAM,YAAY,CAAC","sourcesContent":["export {\n createNextEventIngressRouteHandler,\n type CreateNextEventIngressRouteHandlerOptions,\n} from './route.js';\n\nexport type {\n GraphHttpEventIngressRoute,\n GraphHttpIngressProvider,\n GraphHttpIngressProviderRegistry,\n} from '@ontahi/core/runtime/server/ingress';\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AnyEventDeclaration, EventApplication } from '@ontahi/core/runtime/server';
|
|
2
|
+
import { type GraphHttpEventIngressRoute, type GraphHttpIngressProviderRegistry } from '@ontahi/core/runtime/server/ingress';
|
|
3
|
+
export type CreateNextEventIngressRouteHandlerOptions = {
|
|
4
|
+
events: EventApplication<readonly AnyEventDeclaration[]>;
|
|
5
|
+
route: GraphHttpEventIngressRoute;
|
|
6
|
+
providers: GraphHttpIngressProviderRegistry;
|
|
7
|
+
reportError?: (error: unknown, request: Request) => void;
|
|
8
|
+
};
|
|
9
|
+
export declare const createNextEventIngressRouteHandler: (options: CreateNextEventIngressRouteHandlerOptions) => (request: Request) => Promise<Response>;
|
|
10
|
+
//# sourceMappingURL=route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/event-ingress/route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACzF,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,gCAAgC,EACtC,MAAM,qCAAqC,CAAC;AAE7C,MAAM,MAAM,yCAAyC,GAAG;IACtD,MAAM,EAAE,gBAAgB,CAAC,SAAS,mBAAmB,EAAE,CAAC,CAAC;IACzD,KAAK,EAAE,0BAA0B,CAAC;IAClC,SAAS,EAAE,gCAAgC,CAAC;IAC5C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1D,CAAC;AAUF,eAAO,MAAM,kCAAkC,GAC7C,SAAS,yCAAyC,MAapC,SAAS,OAAO,KAAG,OAAO,CAAC,QAAQ,CAYlD,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createGraphHttpEventIngressDispatcher, createGraphHttpEventIngressRouter, } from '@ontahi/core/runtime/server/ingress';
|
|
2
|
+
const unavailableResponse = () => Response.json({ ok: false, error: 'Event ingress is temporarily unavailable.' }, { status: 500 });
|
|
3
|
+
const responseError = async (response) => {
|
|
4
|
+
const body = (await response.clone().json());
|
|
5
|
+
return new Error(body.error);
|
|
6
|
+
};
|
|
7
|
+
export const createNextEventIngressRouteHandler = (options) => {
|
|
8
|
+
const reportError = options.reportError ??
|
|
9
|
+
((error) => {
|
|
10
|
+
globalThis.console.error('Ontahi Next.js Event ingress failed.', error);
|
|
11
|
+
});
|
|
12
|
+
const router = createGraphHttpEventIngressRouter({
|
|
13
|
+
routes: [options.route],
|
|
14
|
+
providers: options.providers,
|
|
15
|
+
dispatch: createGraphHttpEventIngressDispatcher({ events: options.events }),
|
|
16
|
+
});
|
|
17
|
+
return async (request) => {
|
|
18
|
+
try {
|
|
19
|
+
const response = await router.handle(request);
|
|
20
|
+
if (response.status !== 500)
|
|
21
|
+
return response;
|
|
22
|
+
reportError(await responseError(response), request);
|
|
23
|
+
return unavailableResponse();
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
reportError(error, request);
|
|
27
|
+
return unavailableResponse();
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../src/event-ingress/route.ts"],"names":[],"mappings":"AACA,OAAO,EACL,qCAAqC,EACrC,iCAAiC,GAGlC,MAAM,qCAAqC,CAAC;AAS7C,MAAM,mBAAmB,GAAG,GAAG,EAAE,CAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,2CAA2C,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;AAEpG,MAAM,aAAa,GAAG,KAAK,EAAE,QAAkB,EAAE,EAAE;IACjD,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAsB,CAAC;IAClE,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kCAAkC,GAAG,CAChD,OAAkD,EAClD,EAAE;IACF,MAAM,WAAW,GACf,OAAO,CAAC,WAAW;QACnB,CAAC,CAAC,KAAc,EAAE,EAAE;YAClB,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,KAAK,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;IACL,MAAM,MAAM,GAAG,iCAAiC,CAAC;QAC/C,MAAM,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;QACvB,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,QAAQ,EAAE,qCAAqC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;KAC5E,CAAC,CAAC;IAEH,OAAO,KAAK,EAAE,OAAgB,EAAqB,EAAE;QACnD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC9C,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,QAAQ,CAAC;YAE7C,WAAW,CAAC,MAAM,aAAa,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;YACpD,OAAO,mBAAmB,EAAE,CAAC;QAC/B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YAC5B,OAAO,mBAAmB,EAAE,CAAC;QAC/B,CAAC;IACH,CAAC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import type { AnyEventDeclaration, EventApplication } from '@ontahi/core/runtime/server';\nimport {\n createGraphHttpEventIngressDispatcher,\n createGraphHttpEventIngressRouter,\n type GraphHttpEventIngressRoute,\n type GraphHttpIngressProviderRegistry,\n} from '@ontahi/core/runtime/server/ingress';\n\nexport type CreateNextEventIngressRouteHandlerOptions = {\n events: EventApplication<readonly AnyEventDeclaration[]>;\n route: GraphHttpEventIngressRoute;\n providers: GraphHttpIngressProviderRegistry;\n reportError?: (error: unknown, request: Request) => void;\n};\n\nconst unavailableResponse = () =>\n Response.json({ ok: false, error: 'Event ingress is temporarily unavailable.' }, { status: 500 });\n\nconst responseError = async (response: Response) => {\n const body = (await response.clone().json()) as { error: string };\n return new Error(body.error);\n};\n\nexport const createNextEventIngressRouteHandler = (\n options: CreateNextEventIngressRouteHandlerOptions,\n) => {\n const reportError =\n options.reportError ??\n ((error: unknown) => {\n globalThis.console.error('Ontahi Next.js Event ingress failed.', error);\n });\n const router = createGraphHttpEventIngressRouter({\n routes: [options.route],\n providers: options.providers,\n dispatch: createGraphHttpEventIngressDispatcher({ events: options.events }),\n });\n\n return async (request: Request): Promise<Response> => {\n try {\n const response = await router.handle(request);\n if (response.status !== 500) return response;\n\n reportError(await responseError(response), request);\n return unavailableResponse();\n } catch (error) {\n reportError(error, request);\n return unavailableResponse();\n }\n };\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/graph-read/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,mBAAmB,EAEzB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,6BAA6B,CAAC;AAErC,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AAE1E,MAAM,MAAM,6BAA6B,CAAC,UAAU,IAAI,CACtD,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,OAAO,KACb,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,KAAK,sCAAsC,GAAG;IAC5C,iBAAiB,CAAC,EAAE,4BAA4B,CAAC;IACjD,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1D,CAAC;AAEF,MAAM,MAAM,sCAAsC,CAAC,UAAU,GAAG,iBAAiB,IAC/E,sCAAsC,GACpC,CACI;IACE,UAAU,EAAE,mBAAmB,CAAC,iBAAiB,CAAC,CAAC;IACnD,SAAS,CAAC,EAAE,KAAK,CAAC;CACnB,GACD;IACE,UAAU,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAC5C,SAAS,EAAE,6BAA6B,CAAC,UAAU,CAAC,CAAC;CACtD,CACJ,CAAC;
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/graph-read/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,mBAAmB,EAEzB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,6BAA6B,CAAC;AAErC,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AAE1E,MAAM,MAAM,6BAA6B,CAAC,UAAU,IAAI,CACtD,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,OAAO,KACb,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,KAAK,sCAAsC,GAAG;IAC5C,iBAAiB,CAAC,EAAE,4BAA4B,CAAC;IACjD,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1D,CAAC;AAEF,MAAM,MAAM,sCAAsC,CAAC,UAAU,GAAG,iBAAiB,IAC/E,sCAAsC,GACpC,CACI;IACE,UAAU,EAAE,mBAAmB,CAAC,iBAAiB,CAAC,CAAC;IACnD,SAAS,CAAC,EAAE,KAAK,CAAC;CACnB,GACD;IACE,UAAU,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAC5C,SAAS,EAAE,6BAA6B,CAAC,UAAU,CAAC,CAAC;CACtD,CACJ,CAAC;AAUN,eAAO,MAAM,+BAA+B,GACzC,UAAU,EAAE,SAAS,sCAAsC,CAAC,UAAU,CAAC,MACjE,SAAS,OAAO,KAAG,OAAO,CAAC,QAAQ,CAoCzC,CAAC"}
|
package/dist/graph-read/route.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import { graphReadProtocolError,
|
|
1
|
+
import { graphReadProtocolError, parseGraphReadFamilyRequest, } from '@ontahi/core/data-graph';
|
|
2
2
|
import { getCurrentInvocationContext, withInvocationContext, } from '@ontahi/core/runtime/server';
|
|
3
3
|
const responseStatus = (response) => {
|
|
4
|
-
if (response.kind
|
|
4
|
+
if (response.kind !== 'protocol-error')
|
|
5
5
|
return 200;
|
|
6
6
|
if (response.error.code === 'access_denied')
|
|
7
7
|
return 403;
|
|
8
|
+
if (response.error.code === 'cardinality_mismatch')
|
|
9
|
+
return 409;
|
|
8
10
|
if (response.error.code === 'execution_unavailable')
|
|
9
11
|
return 503;
|
|
10
12
|
return 400;
|
|
11
13
|
};
|
|
12
14
|
export const createNextGraphReadRouteHandler = (options) => async (request) => {
|
|
13
|
-
const parsed =
|
|
15
|
+
const parsed = parseGraphReadFamilyRequest(await request.json().catch(() => null));
|
|
14
16
|
if (!parsed.success) {
|
|
15
17
|
return Response.json(parsed.error, { status: 400 });
|
|
16
18
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../src/graph-read/route.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,
|
|
1
|
+
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../src/graph-read/route.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,2BAA2B,GAG5B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,2BAA2B,EAC3B,qBAAqB,GAEtB,MAAM,6BAA6B,CAAC;AA2BrC,MAAM,cAAc,GAAG,CAAC,QAAmC,EAAE,EAAE;IAC7D,IAAI,QAAQ,CAAC,IAAI,KAAK,gBAAgB;QAAE,OAAO,GAAG,CAAC;IACnD,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,eAAe;QAAE,OAAO,GAAG,CAAC;IACxD,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,sBAAsB;QAAE,OAAO,GAAG,CAAC;IAC/D,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,uBAAuB;QAAE,OAAO,GAAG,CAAC;IAChE,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,+BAA+B,GAC1C,CAAa,OAA2D,EAAE,EAAE,CAC5E,KAAK,EAAE,OAAgB,EAAqB,EAAE;IAC5C,MAAM,MAAM,GAAG,2BAA2B,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IACnF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;YAC1B,MAAM,cAAc,GAAG,2BAA2B,EAAE,CAAC;YACrD,IAAI,CAAC,cAAc,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;YAC3E,CAAC;YACD,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;gBACtB,OAAO,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE;oBACxC,SAAS,EAAE,MAAM,OAAO,CAAC,SAAS,CAAC,cAAc,EAAE,OAAO,CAAC;iBAC5D,CAAC,CAAC;YACL,CAAC;YACD,OAAO,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC,CAAC;QAC3E,CAAC,CAAC;QACF,MAAM,gBAAgB,GAAG,MAAM,qBAAqB,CAClD,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EACzE,QAAQ,CACT,CAAC;QAEF,OAAO,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,cAAc,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;IACvF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAEtC,OAAO,QAAQ,CAAC,IAAI,CAClB,sBAAsB,CACpB,uBAAuB,EACvB,uDAAuD,CACxD,EACD,EAAE,MAAM,EAAE,GAAG,EAAE,CAChB,CAAC;IACJ,CAAC;AACH,CAAC,CAAC","sourcesContent":["import {\n graphReadProtocolError,\n parseGraphReadFamilyRequest,\n type GraphReadDispatcher,\n type GraphReadDispatchResponse,\n} from '@ontahi/core/data-graph';\nimport {\n getCurrentInvocationContext,\n withInvocationContext,\n type InvocationContext,\n} from '@ontahi/core/runtime/server';\n\nimport type { NextInvocationContextFactory } from '../request-context.js';\n\nexport type NextGraphReadAuthorityFactory<TAuthority> = (\n context: InvocationContext,\n request: Request,\n) => TAuthority | Promise<TAuthority>;\n\ntype NextGraphReadRouteHandlerCommonOptions = {\n invocationContext?: NextInvocationContextFactory;\n reportError?: (error: unknown, request: Request) => void;\n};\n\nexport type CreateNextGraphReadRouteHandlerOptions<TAuthority = InvocationContext> =\n NextGraphReadRouteHandlerCommonOptions &\n (\n | {\n dispatcher: GraphReadDispatcher<InvocationContext>;\n authority?: never;\n }\n | {\n dispatcher: GraphReadDispatcher<TAuthority>;\n authority: NextGraphReadAuthorityFactory<TAuthority>;\n }\n );\n\nconst responseStatus = (response: GraphReadDispatchResponse) => {\n if (response.kind !== 'protocol-error') return 200;\n if (response.error.code === 'access_denied') return 403;\n if (response.error.code === 'cardinality_mismatch') return 409;\n if (response.error.code === 'execution_unavailable') return 503;\n return 400;\n};\n\nexport const createNextGraphReadRouteHandler =\n <TAuthority>(options: CreateNextGraphReadRouteHandlerOptions<TAuthority>) =>\n async (request: Request): Promise<Response> => {\n const parsed = parseGraphReadFamilyRequest(await request.json().catch(() => null));\n if (!parsed.success) {\n return Response.json(parsed.error, { status: 400 });\n }\n\n try {\n const dispatch = async () => {\n const currentContext = getCurrentInvocationContext();\n if (!currentContext) {\n throw new Error('Next.js graph read invocation context is unavailable.');\n }\n if (options.authority) {\n return options.dispatcher(parsed.request, {\n authority: await options.authority(currentContext, request),\n });\n }\n return options.dispatcher(parsed.request, { authority: currentContext });\n };\n const protocolResponse = await withInvocationContext(\n options.invocationContext ? await options.invocationContext(request) : {},\n dispatch,\n );\n\n return Response.json(protocolResponse, { status: responseStatus(protocolResponse) });\n } catch (error) {\n options.reportError?.(error, request);\n\n return Response.json(\n graphReadProtocolError(\n 'execution_unavailable',\n 'Data graph read execution is temporarily unavailable.',\n ),\n { status: 503 },\n );\n }\n };\n"]}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { type RuntimeProtocolDispatcher } from '@ontahi/core/runtime/protocol';
|
|
2
|
+
import type { ApplicationRuntimeProtocol } from '@ontahi/core/runtime/server';
|
|
2
3
|
export type NextRuntimeProtocolContextFactory<TContext> = (request: Request) => TContext | Promise<TContext>;
|
|
3
4
|
export type CreateNextRuntimeProtocolRouteHandlerOptions<TContext> = {
|
|
4
|
-
dispatcher
|
|
5
|
+
dispatcher?: RuntimeProtocolDispatcher<TContext>;
|
|
6
|
+
receiver?: ApplicationRuntimeProtocol<TContext>;
|
|
5
7
|
context: NextRuntimeProtocolContextFactory<TContext>;
|
|
6
8
|
reportError?: (error: unknown, request: Request) => void;
|
|
7
9
|
};
|
|
8
|
-
export declare const createNextRuntimeProtocolRouteHandler: <TContext>({ dispatcher, context, reportError, }: CreateNextRuntimeProtocolRouteHandlerOptions<TContext>) => (request: Request) => Promise<Response>;
|
|
10
|
+
export declare const createNextRuntimeProtocolRouteHandler: <TContext>({ dispatcher, receiver, context, reportError, }: CreateNextRuntimeProtocolRouteHandlerOptions<TContext>) => (request: Request) => Promise<Response>;
|
|
9
11
|
//# sourceMappingURL=route.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/runtime-protocol/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,yBAAyB,EAC/B,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/runtime-protocol/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,yBAAyB,EAC/B,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AAE9E,MAAM,MAAM,iCAAiC,CAAC,QAAQ,IAAI,CACxD,OAAO,EAAE,OAAO,KACb,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AAElC,MAAM,MAAM,4CAA4C,CAAC,QAAQ,IAAI;IACnE,UAAU,CAAC,EAAE,yBAAyB,CAAC,QAAQ,CAAC,CAAC;IACjD,QAAQ,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IAChD,OAAO,EAAE,iCAAiC,CAAC,QAAQ,CAAC,CAAC;IACrD,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1D,CAAC;AAsBF,eAAO,MAAM,qCAAqC,GAAI,QAAQ,EAAE,iDAK7D,4CAA4C,CAAC,QAAQ,CAAC,MAIzC,SAAS,OAAO,KAAG,OAAO,CAAC,QAAQ,CAwBlD,CAAC"}
|
|
@@ -17,18 +17,25 @@ const responseStatus = (result) => {
|
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
19
|
const registry = createRuntimeProtocolRegistry(runtimeProtocolFamilies);
|
|
20
|
-
export const createNextRuntimeProtocolRouteHandler = ({ dispatcher, context, reportError, }) =>
|
|
21
|
-
const
|
|
22
|
-
if (!
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
20
|
+
export const createNextRuntimeProtocolRouteHandler = ({ dispatcher, receiver, context, reportError, }) => {
|
|
21
|
+
const dispatch = receiver?.dispatcher ?? dispatcher;
|
|
22
|
+
if (!dispatch)
|
|
23
|
+
throw new TypeError('Runtime Protocol requires a receiver or dispatcher.');
|
|
24
|
+
return async (request) => {
|
|
25
|
+
const parsed = registry.parseRequest(await request.json().catch(() => null));
|
|
26
|
+
if (!parsed.success) {
|
|
27
|
+
return Response.json(parsed.error, { status: responseStatus(parsed.error) });
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const result = await dispatch(parsed.request, await context(request), {
|
|
31
|
+
signal: request.signal,
|
|
32
|
+
});
|
|
33
|
+
return Response.json(result, { status: responseStatus(result) });
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
reportError?.(error, request);
|
|
37
|
+
return Response.json(runtimeProtocolError('dispatch_unavailable', 'Runtime Protocol dispatch is temporarily unavailable.', { id: parsed.request.id, family: parsed.request.family }), { status: 503 });
|
|
38
|
+
}
|
|
39
|
+
};
|
|
33
40
|
};
|
|
34
41
|
//# sourceMappingURL=route.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../src/runtime-protocol/route.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,6BAA6B,EAC7B,oBAAoB,EACpB,uBAAuB,GAGxB,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../src/runtime-protocol/route.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,6BAA6B,EAC7B,oBAAoB,EACpB,uBAAuB,GAGxB,MAAM,+BAA+B,CAAC;AAcvC,MAAM,cAAc,GAAG,CAAC,MAAqC,EAAE,EAAE;IAC/D,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB;QAAE,OAAO,GAAG,CAAC;IAEjD,QAAQ,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC1B,KAAK,kBAAkB,CAAC;QACxB,KAAK,qBAAqB,CAAC;QAC3B,KAAK,gBAAgB,CAAC;QACtB,KAAK,wBAAwB;YAC3B,OAAO,GAAG,CAAC;QACb,KAAK,oBAAoB;YACvB,OAAO,GAAG,CAAC;QACb,KAAK,sBAAsB;YACzB,OAAO,GAAG,CAAC;QACb,KAAK,kBAAkB;YACrB,OAAO,GAAG,CAAC;IACf,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,QAAQ,GAAG,6BAA6B,CAAC,uBAAuB,CAAC,CAAC;AAExE,MAAM,CAAC,MAAM,qCAAqC,GAAG,CAAW,EAC9D,UAAU,EACV,QAAQ,EACR,OAAO,EACP,WAAW,GAC4C,EAAE,EAAE;IAC3D,MAAM,QAAQ,GAAG,QAAQ,EAAE,UAAU,IAAI,UAAU,CAAC;IACpD,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,SAAS,CAAC,qDAAqD,CAAC,CAAC;IAE1F,OAAO,KAAK,EAAE,OAAgB,EAAqB,EAAE;QACnD,MAAM,MAAM,GAAG,QAAQ,CAAC,YAAY,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;QAC7E,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC/E,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE;gBACpE,MAAM,EAAE,OAAO,CAAC,MAAM;aACvB,CAAC,CAAC;YACH,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACnE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YAE9B,OAAO,QAAQ,CAAC,IAAI,CAClB,oBAAoB,CAClB,sBAAsB,EACtB,uDAAuD,EACvD,EAAE,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CACzD,EACD,EAAE,MAAM,EAAE,GAAG,EAAE,CAChB,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {\n createRuntimeProtocolRegistry,\n runtimeProtocolError,\n runtimeProtocolFamilies,\n type RuntimeProtocolDispatchResult,\n type RuntimeProtocolDispatcher,\n} from '@ontahi/core/runtime/protocol';\nimport type { ApplicationRuntimeProtocol } from '@ontahi/core/runtime/server';\n\nexport type NextRuntimeProtocolContextFactory<TContext> = (\n request: Request,\n) => TContext | Promise<TContext>;\n\nexport type CreateNextRuntimeProtocolRouteHandlerOptions<TContext> = {\n dispatcher?: RuntimeProtocolDispatcher<TContext>;\n receiver?: ApplicationRuntimeProtocol<TContext>;\n context: NextRuntimeProtocolContextFactory<TContext>;\n reportError?: (error: unknown, request: Request) => void;\n};\n\nconst responseStatus = (result: RuntimeProtocolDispatchResult) => {\n if (result.kind !== 'protocol-error') return 200;\n\n switch (result.error.code) {\n case 'invalid_envelope':\n case 'unsupported_version':\n case 'unknown_family':\n case 'invalid_family_request':\n return 400;\n case 'family_unavailable':\n return 501;\n case 'dispatch_unavailable':\n return 503;\n case 'invalid_response':\n return 502;\n }\n};\n\nconst registry = createRuntimeProtocolRegistry(runtimeProtocolFamilies);\n\nexport const createNextRuntimeProtocolRouteHandler = <TContext>({\n dispatcher,\n receiver,\n context,\n reportError,\n}: CreateNextRuntimeProtocolRouteHandlerOptions<TContext>) => {\n const dispatch = receiver?.dispatcher ?? dispatcher;\n if (!dispatch) throw new TypeError('Runtime Protocol requires a receiver or dispatcher.');\n\n return async (request: Request): Promise<Response> => {\n const parsed = registry.parseRequest(await request.json().catch(() => null));\n if (!parsed.success) {\n return Response.json(parsed.error, { status: responseStatus(parsed.error) });\n }\n\n try {\n const result = await dispatch(parsed.request, await context(request), {\n signal: request.signal,\n });\n return Response.json(result, { status: responseStatus(result) });\n } catch (error) {\n reportError?.(error, request);\n\n return Response.json(\n runtimeProtocolError(\n 'dispatch_unavailable',\n 'Runtime Protocol dispatch is temporarily unavailable.',\n { id: parsed.request.id, family: parsed.request.family },\n ),\n { status: 503 },\n );\n }\n };\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ontahi/runtime-nextjs",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.13",
|
|
4
4
|
"description": "Next.js runtime and transport adapters for Ontahi applications",
|
|
5
5
|
"homepage": "https://github.com/javifernandes/ontahi/tree/main/packages/runtime-nextjs",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -48,6 +48,11 @@
|
|
|
48
48
|
"types": "./dist/runtime-protocol/index.d.ts",
|
|
49
49
|
"import": "./dist/runtime-protocol/index.js",
|
|
50
50
|
"require": "./dist/runtime-protocol/index.js"
|
|
51
|
+
},
|
|
52
|
+
"./event-ingress": {
|
|
53
|
+
"types": "./dist/event-ingress/index.d.ts",
|
|
54
|
+
"import": "./dist/event-ingress/index.js",
|
|
55
|
+
"require": "./dist/event-ingress/index.js"
|
|
51
56
|
}
|
|
52
57
|
},
|
|
53
58
|
"publishConfig": {
|
|
@@ -55,13 +60,15 @@
|
|
|
55
60
|
"provenance": true
|
|
56
61
|
},
|
|
57
62
|
"dependencies": {
|
|
63
|
+
"@ontahi/core": "1.0.0-alpha.13",
|
|
58
64
|
"effect": "^3.21.0",
|
|
59
65
|
"next-safe-action": "^8.3.0",
|
|
60
66
|
"server-only": "^0.0.1",
|
|
61
|
-
"zod": "^4.3.6"
|
|
62
|
-
"@ontahi/core": "1.0.0-alpha.11"
|
|
67
|
+
"zod": "^4.3.6"
|
|
63
68
|
},
|
|
64
69
|
"devDependencies": {
|
|
70
|
+
"@ontahi/react": "1.0.0-alpha.13",
|
|
71
|
+
"@ontahi/runtime-express": "1.0.0-alpha.13",
|
|
65
72
|
"@types/node": "^20.0.0",
|
|
66
73
|
"@types/react": "^18.3.0",
|
|
67
74
|
"@types/react-dom": "^18.3.0",
|