forgeos 0.1.0-alpha.12 → 0.1.0-alpha.14
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/AGENTS.md +6 -5
- package/CHANGELOG.md +23 -0
- package/adapters/java/README.md +68 -0
- package/adapters/java/pom.xml +34 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Auth.java +20 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Diagnostic.java +16 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Entry.java +38 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/EntryKind.java +16 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ErrorInfo.java +4 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Forge.java +94 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeCall.java +12 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeContext.java +11 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHandler.java +8 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHttpHandler.java +179 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeRegistry.java +121 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Json.java +14 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Manifest.java +14 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/RequestEnvelope.java +6 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ResponseEnvelope.java +25 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Risk.java +18 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Schemas.java +36 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Service.java +65 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/TransactionMode.java +18 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/TypedForgeHandler.java +6 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Auth.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Diagnostic.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Entry.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/EntryKind.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ErrorInfo.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Forge.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ForgeCall.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ForgeContext.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ForgeHandler.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ForgeHttpHandler.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry$EntryOption.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry$RegisteredEntry.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry$RegistryOption.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Json.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Manifest.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/RequestEnvelope.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ResponseEnvelope.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Risk.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Schemas.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Service.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/TransactionMode.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/TypedForgeHandler.class +0 -0
- package/adapters/java/target/forge-java-adapter-0.1.0-alpha.11.jar +0 -0
- package/adapters/java/target/maven-archiver/pom.properties +3 -0
- package/adapters/java/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +23 -0
- package/adapters/java/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +20 -0
- package/adapters/java-spring-boot-starter/README.md +32 -0
- package/adapters/java-spring-boot-starter/pom.xml +36 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeCommand.java +22 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeExternalService.java +15 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeQuery.java +16 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.java +18 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.java +16 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringRuntime.java +104 -0
- package/adapters/java-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -0
- package/adapters/java-spring-boot-starter/target/classes/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -0
- package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeCommand.class +0 -0
- package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeExternalService.class +0 -0
- package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeQuery.class +0 -0
- package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.class +0 -0
- package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.class +0 -0
- package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeSpringRuntime.class +0 -0
- package/adapters/java-spring-boot-starter/target/forge-java-spring-boot-starter-0.1.0-alpha.11.jar +0 -0
- package/adapters/java-spring-boot-starter/target/maven-archiver/pom.properties +3 -0
- package/adapters/java-spring-boot-starter/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +6 -0
- package/adapters/java-spring-boot-starter/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +6 -0
- package/docs/forge-protocol.md +33 -0
- package/examples/java-billing/pom.xml +52 -0
- package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/CreateInvoiceInput.java +4 -0
- package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Invoice.java +11 -0
- package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Main.java +127 -0
- package/examples/java-billing/target/classes/dev/forgeos/examples/billing/CreateInvoiceInput.class +0 -0
- package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Invoice.class +0 -0
- package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Main$EmptyInput.class +0 -0
- package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Main$Options.class +0 -0
- package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Main.class +0 -0
- package/examples/java-billing/target/java-billing-0.1.0-alpha.11-all.jar +0 -0
- package/examples/java-billing/target/java-billing-0.1.0-alpha.11.jar +0 -0
- package/examples/java-billing/target/maven-archiver/pom.properties +3 -0
- package/examples/java-billing/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +5 -0
- package/examples/java-billing/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +3 -0
- package/package.json +4 -1
- package/src/forge/_generated/actionSubscriptions.json +1 -1
- package/src/forge/_generated/actionSubscriptions.ts +3 -3
- package/src/forge/_generated/agentAdapterManifest.json +1 -1
- package/src/forge/_generated/agentAdapterManifest.ts +3 -3
- package/src/forge/_generated/agentContract.json +1 -1
- package/src/forge/_generated/agentContract.ts +1274 -7
- package/src/forge/_generated/agentQuickstart.md +1 -1
- package/src/forge/_generated/agentTools.json +1 -1
- package/src/forge/_generated/agentTools.md +1 -1
- package/src/forge/_generated/agentTools.ts +2 -2
- package/src/forge/_generated/aiContext.ts +1 -1
- package/src/forge/_generated/aiModels.ts +1 -1
- package/src/forge/_generated/aiProviders.ts +1 -1
- package/src/forge/_generated/aiRegistry.json +1 -1
- package/src/forge/_generated/aiRegistry.ts +3 -3
- package/src/forge/_generated/api.json +1 -1
- package/src/forge/_generated/api.ts +1 -1
- package/src/forge/_generated/appGraph.json +1 -1
- package/src/forge/_generated/appGraph.ts +392 -94
- package/src/forge/_generated/appMap.md +1 -1
- package/src/forge/_generated/artifactManifest.json +1 -1
- package/src/forge/_generated/artifactManifest.ts +2 -2
- package/src/forge/_generated/authClaims.ts +1 -1
- package/src/forge/_generated/authConfig.ts +1 -1
- package/src/forge/_generated/authContext.ts +1 -1
- package/src/forge/_generated/authRegistry.ts +1 -1
- package/src/forge/_generated/buildInfo.json +1 -1
- package/src/forge/_generated/buildInfo.ts +4 -4
- package/src/forge/_generated/capabilityMap.json +1 -1
- package/src/forge/_generated/capabilityMap.md +1 -1
- package/src/forge/_generated/capabilityMap.ts +2 -2
- package/src/forge/_generated/client.ts +1 -1
- package/src/forge/_generated/clientApi.ts +1 -1
- package/src/forge/_generated/clientManifest.json +1 -1
- package/src/forge/_generated/clientManifest.ts +14 -3
- package/src/forge/_generated/clientTypes.ts +1 -1
- package/src/forge/_generated/configRegistry.ts +1 -1
- package/src/forge/_generated/dataGraph.json +1 -1
- package/src/forge/_generated/dataGraph.ts +3 -3
- package/src/forge/_generated/db.ts +1 -1
- package/src/forge/_generated/dbSecurityManifest.ts +1 -1
- package/src/forge/_generated/dbSessionContext.ts +1 -1
- package/src/forge/_generated/deployManifest.json +1 -1
- package/src/forge/_generated/deployManifest.ts +7 -7
- package/src/forge/_generated/devManifest.json +1 -1
- package/src/forge/_generated/devManifest.ts +3 -3
- package/src/forge/_generated/envSchema.ts +1 -1
- package/src/forge/_generated/externalServices.ts +1 -1
- package/src/forge/_generated/frontendGraph.ts +1 -1
- package/src/forge/_generated/importGuards.json +1 -1
- package/src/forge/_generated/importGuards.ts +35 -1
- package/src/forge/_generated/index.ts +3 -1
- package/src/forge/_generated/liveProductionManifest.ts +1 -1
- package/src/forge/_generated/liveProtocol.ts +1 -1
- package/src/forge/_generated/liveQueryRegistry.json +1 -1
- package/src/forge/_generated/liveQueryRegistry.ts +3 -3
- package/src/forge/_generated/liveTransportConfig.ts +1 -1
- package/src/forge/_generated/makeRegistry.json +1 -1
- package/src/forge/_generated/makeRegistry.ts +8 -8
- package/src/forge/_generated/makeTemplates.json +1 -1
- package/src/forge/_generated/makeTemplates.ts +2 -2
- package/src/forge/_generated/mockMap.ts +1 -1
- package/src/forge/_generated/operationPlaybooks.md +6 -6
- package/src/forge/_generated/packageGraph.json +1 -1
- package/src/forge/_generated/packageGraph.ts +52412 -2
- package/src/forge/_generated/packageUpgradeRegistry.json +1 -1
- package/src/forge/_generated/packageUpgradeRegistry.ts +2 -2
- package/src/forge/_generated/permissionMatrix.json +1 -1
- package/src/forge/_generated/permissionMatrix.ts +3 -3
- package/src/forge/_generated/policyRegistry.json +1 -1
- package/src/forge/_generated/policyRegistry.ts +3 -3
- package/src/forge/_generated/queryRegistry.json +1 -1
- package/src/forge/_generated/queryRegistry.ts +3 -3
- package/src/forge/_generated/react.d.ts +1 -1
- package/src/forge/_generated/react.ts +1 -1
- package/src/forge/_generated/reactManifest.json +1 -1
- package/src/forge/_generated/reactManifest.ts +3 -3
- package/src/forge/_generated/releaseManifest.json +1 -1
- package/src/forge/_generated/releaseManifest.ts +3 -3
- package/src/forge/_generated/rlsPolicies.sql +1 -1
- package/src/forge/_generated/rlsPolicies.ts +1 -1
- package/src/forge/_generated/runtimeGraph.json +1 -1
- package/src/forge/_generated/runtimeGraph.ts +3 -3
- package/src/forge/_generated/runtimeMatrix.json +1 -1
- package/src/forge/_generated/runtimeMatrix.ts +70357 -1
- package/src/forge/_generated/runtimeRegistry.ts +1 -1
- package/src/forge/_generated/runtimeRules.md +1 -1
- package/src/forge/_generated/secretRegistry.ts +1 -1
- package/src/forge/_generated/secretsContext.ts +1 -1
- package/src/forge/_generated/serverApi.ts +1 -1
- package/src/forge/_generated/sourceMapManifest.json +1 -1
- package/src/forge/_generated/sourceMapManifest.ts +2 -2
- package/src/forge/_generated/sqlPlan.ts +1 -1
- package/src/forge/_generated/subscriptionManifest.json +1 -1
- package/src/forge/_generated/subscriptionManifest.ts +3 -3
- package/src/forge/_generated/symbolicationManifest.json +1 -1
- package/src/forge/_generated/symbolicationManifest.ts +2 -2
- package/src/forge/_generated/telemetryRegistry.json +1 -1
- package/src/forge/_generated/telemetryRegistry.ts +3 -3
- package/src/forge/_generated/telemetrySinks.json +1 -1
- package/src/forge/_generated/telemetrySinks.ts +2 -2
- package/src/forge/_generated/tenantScope.json +1 -1
- package/src/forge/_generated/tenantScope.ts +3 -3
- package/src/forge/_generated/testGraph.json +1 -1
- package/src/forge/_generated/testGraph.ts +89 -5
- package/src/forge/_generated/testPlanRegistry.json +1 -1
- package/src/forge/_generated/testPlanRegistry.ts +2 -2
- package/src/forge/_generated/uiRoutes.ts +1 -1
- package/src/forge/_generated/uiScenarios.ts +1 -1
- package/src/forge/_generated/uiTestManifest.json +1 -1
- package/src/forge/_generated/uiTestManifest.ts +2 -2
- package/src/forge/_generated/vue.d.ts +25 -0
- package/src/forge/_generated/vue.ts +30 -0
- package/src/forge/_generated/vueManifest.json +1 -0
- package/src/forge/_generated/vueManifest.ts +19 -0
- package/src/forge/_generated/workflowRegistry.json +1 -1
- package/src/forge/_generated/workflowRegistry.ts +3 -3
- package/src/forge/_generated/workflowSubscriptions.json +1 -1
- package/src/forge/_generated/workflowSubscriptions.ts +3 -3
- package/src/forge/agent-adapters/index.ts +37 -3
- package/src/forge/agent-adapters/types.ts +10 -1
- package/src/forge/agent-memory/bridge.ts +228 -0
- package/src/forge/agent-memory/context-pack.ts +104 -0
- package/src/forge/agent-memory/mcp.ts +224 -0
- package/src/forge/agent-memory/normalize.ts +249 -0
- package/src/forge/agent-memory/redaction.ts +94 -0
- package/src/forge/agent-memory/sources/claude-code.ts +51 -0
- package/src/forge/agent-memory/sources/codex.ts +58 -0
- package/src/forge/agent-memory/sources/cursor.ts +35 -0
- package/src/forge/agent-memory/types.ts +112 -0
- package/src/forge/cli/build.ts +19 -3
- package/src/forge/cli/commands.ts +4 -0
- package/src/forge/cli/main.ts +2 -0
- package/src/forge/cli/parse.ts +48 -3
- package/src/forge/cli/verify.ts +2 -0
- package/src/forge/compiler/agent-contract/build.ts +10 -9
- package/src/forge/compiler/client-sdk/build-manifest.ts +55 -0
- package/src/forge/compiler/client-sdk/render-client.ts +66 -1
- package/src/forge/compiler/diagnostics/create.ts +6 -1
- package/src/forge/compiler/emitter/barrel.ts +3 -0
- package/src/forge/compiler/frontend-graph/build.ts +85 -13
- package/src/forge/compiler/make-registry/build.ts +6 -7
- package/src/forge/compiler/orchestrator/plan.ts +13 -0
- package/src/forge/compiler/orchestrator/serialize.ts +6 -0
- package/src/forge/compiler/types/frontend-graph.ts +2 -2
- package/src/forge/delta/ids.ts +2 -0
- package/src/forge/delta/schema.ts +38 -1
- package/src/forge/delta/store.ts +235 -2
- package/src/forge/intent/index.ts +11 -6
- package/src/forge/make/index.ts +23 -3
- package/src/forge/make/templates.ts +153 -0
- package/src/forge/make/types.ts +2 -1
- package/src/forge/version.ts +1 -1
- package/src/forge/vue/index.ts +407 -0
package/AGENTS.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @forge-generated generator=0.1.0-alpha.
|
|
1
|
+
// @forge-generated generator=0.1.0-alpha.14 input=675f1561e5787d5107285fb1d3627501242d220f0be03e89adf99930e6c23c69 content=143ee5e2d6fee031a4952f21ee3cc8f1e5678fd11ea673c2cb79196c251c32b6
|
|
2
2
|
# AGENTS.md
|
|
3
3
|
|
|
4
4
|
<!-- forge-generated:start -->
|
|
@@ -142,9 +142,9 @@ Agents:
|
|
|
142
142
|
|
|
143
143
|
Rules:
|
|
144
144
|
|
|
145
|
-
- Use the local `web/**/lib/forge.ts` bridge to generated
|
|
146
|
-
- Mount `<ForgeProvider devAuth>` in local development.
|
|
147
|
-
- Use `useQuery
|
|
145
|
+
- Use the local `web/**/lib/forge.ts` or Nuxt `web/composables/forge.ts` bridge to generated bindings.
|
|
146
|
+
- Mount `<ForgeProvider devAuth>` or install the Nuxt Forge plugin in local development.
|
|
147
|
+
- Use `useQuery`/`useCommand`/`useLiveQuery` or `useForgeQuery`/`useForgeCommand`/`useForgeLiveQuery` instead of raw Forge endpoint fetches in components.
|
|
148
148
|
- Keep frontend routes reflected in `src/forge/_generated/frontendGraph.json`.
|
|
149
149
|
|
|
150
150
|
## Common tasks
|
|
@@ -177,6 +177,7 @@ Use:
|
|
|
177
177
|
forge make resource <name> --fields title:text,status:enum(open,closed) --dry-run --json
|
|
178
178
|
forge make resource <name> --fields title:text,status:enum(open,closed) --with-ui --yes
|
|
179
179
|
forge make ui --framework vite --dry-run --json
|
|
180
|
+
forge make ui --framework nuxt --dry-run --json
|
|
180
181
|
forge make ai-chat support --dry-run --json
|
|
181
182
|
```
|
|
182
183
|
|
|
@@ -193,7 +194,7 @@ forge inspect frontend --json
|
|
|
193
194
|
forge inspect capabilities --json
|
|
194
195
|
```
|
|
195
196
|
|
|
196
|
-
`forge dev` starts the API runtime and web app together when `web/` exists. `forge dev --once --json` reports routes, components,
|
|
197
|
+
`forge dev` starts the API runtime and web app together when `web/` exists. `forge dev --once --json` reports routes, components, providers/plugins, bridge files, generated client bindings, direct runtime fetch warnings, capability-map parity warnings, and fix hints.
|
|
197
198
|
|
|
198
199
|
### Apply a feature blueprint
|
|
199
200
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# forgeos
|
|
2
2
|
|
|
3
|
+
## 0.1.0-alpha.14
|
|
4
|
+
|
|
5
|
+
Java and Nuxt/Vue support:
|
|
6
|
+
|
|
7
|
+
- Added the Java external runtime adapter with a lightweight JDK HTTP bridge, manifest export, typed handlers, tenant/auth context, diagnostics, and command/query registration.
|
|
8
|
+
- Added a Spring Boot starter for Java services that want annotation-based Forge command/query exposure.
|
|
9
|
+
- Added the `java-billing` conformance example and packaged it with the public alpha line.
|
|
10
|
+
- Added generated Vue bindings and a `forgeos/vue` export with `provideForge`, `ForgeVuePlugin`, `useForgeQuery`, `useForgeCommand`, and `useForgeLiveQuery`.
|
|
11
|
+
- Added Nuxt UI scaffolding through `forge make ui --framework nuxt`, including plugin wiring, composable bridge files, and frontend graph detection for `.vue` routes/components.
|
|
12
|
+
- Updated docs, agent adapter guidance, generated manifests, and focused Java/Vue/Nuxt tests.
|
|
13
|
+
- Kept H44-H48 memory, sessions, timeline, grouping, and MCP surfaces intact while merging the Java/Nuxt work into `main`.
|
|
14
|
+
|
|
15
|
+
## 0.1.0-alpha.13
|
|
16
|
+
|
|
17
|
+
Agent Memory Bridge:
|
|
18
|
+
|
|
19
|
+
- Added the H48 Agent Memory Bridge alpha with redacted external agent event ingestion and normalized `forge.agent-event.v1` envelopes.
|
|
20
|
+
- Added Codex and Claude Code hook installers plus Cursor MCP/rules setup, all with raw prompts, completions, tool args, transcripts, and cloud sync off by default.
|
|
21
|
+
- Added `forge mcp serve` with context, memory, timeline, and inspect tools for external agents.
|
|
22
|
+
- Added `forge agent install`, `forge agent ingest`, `forge agent context`, and `forge agent memory` commands.
|
|
23
|
+
- Persisted external agent activity in DeltaDB and linked agent/tool/file events into the semantic timeline.
|
|
24
|
+
- Added focused privacy, ingest, MCP, installer, and CLI parse coverage for the H48 bridge.
|
|
25
|
+
|
|
3
26
|
## 0.1.0-alpha.12
|
|
4
27
|
|
|
5
28
|
Semantic Timeline:
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Forge Java Adapter
|
|
2
|
+
|
|
3
|
+
`adapters/java` is the minimal Java SDK for external Forge runtimes. It mirrors
|
|
4
|
+
the Go adapter: register commands and queries, emit a `forge.manifest.json`, and
|
|
5
|
+
serve Forge-compatible HTTP envelopes.
|
|
6
|
+
|
|
7
|
+
```java
|
|
8
|
+
ForgeRegistry app = Forge.service("billing",
|
|
9
|
+
Forge.framework("java/jdk-http"),
|
|
10
|
+
Forge.baseUrl("http://127.0.0.1:8788"));
|
|
11
|
+
|
|
12
|
+
app.command("createInvoice",
|
|
13
|
+
Forge.handle(CreateInvoiceInput.class, Billing::createInvoice),
|
|
14
|
+
Forge.policy("billing.manage"),
|
|
15
|
+
Forge.tenantScoped(true),
|
|
16
|
+
Forge.needsApproval(true),
|
|
17
|
+
Forge.inputSchema(Schemas.object(Map.of("title", Schemas.string()), "title")));
|
|
18
|
+
|
|
19
|
+
app.query("listInvoices",
|
|
20
|
+
Forge.handle(EmptyInput.class, Billing::listInvoices),
|
|
21
|
+
Forge.policy("billing.manage"),
|
|
22
|
+
Forge.tenantScoped(true),
|
|
23
|
+
Forge.readOnly());
|
|
24
|
+
|
|
25
|
+
ForgeHttpHandler.listen(app, "127.0.0.1", 8788);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The HTTP handler exposes:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
GET /health
|
|
32
|
+
GET /manifest?baseUrl=http://127.0.0.1:8788
|
|
33
|
+
POST /commands/:name
|
|
34
|
+
POST /queries/:name
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The handler accepts Forge runtime envelopes and returns Forge response
|
|
38
|
+
envelopes:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"args": { "title": "Invoice" },
|
|
43
|
+
"auth": { "kind": "user", "userId": "u1", "tenantId": "t1", "role": "admin" },
|
|
44
|
+
"forge": { "service": "billing", "entry": "createInvoice", "kind": "command", "traceId": "trace_..." }
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Build locally:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
mvn -f adapters/java/pom.xml install
|
|
52
|
+
mvn -f examples/java-billing/pom.xml package
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Emit and import a manifest:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
java -jar examples/java-billing/target/java-billing-0.1.0-alpha.11-all.jar --manifest --base-url http://127.0.0.1:8788 > java-billing.manifest.json
|
|
59
|
+
forge manifest import java-billing.manifest.json --json
|
|
60
|
+
forge generate
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Invoke through Forge:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
forge run billing.createInvoice --args '{"title":"Invoice"}' --role admin --tenant-id tenant-a
|
|
67
|
+
forge query billing.listInvoices --args '{}' --role admin --tenant-id tenant-a
|
|
68
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
3
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
4
|
+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
5
|
+
<modelVersion>4.0.0</modelVersion>
|
|
6
|
+
|
|
7
|
+
<groupId>dev.forgeos</groupId>
|
|
8
|
+
<artifactId>forge-java-adapter</artifactId>
|
|
9
|
+
<version>0.1.0-alpha.11</version>
|
|
10
|
+
<name>Forge Java Adapter</name>
|
|
11
|
+
<description>Minimal Java SDK for Forge external runtimes.</description>
|
|
12
|
+
<url>https://forgeos.dev</url>
|
|
13
|
+
|
|
14
|
+
<licenses>
|
|
15
|
+
<license>
|
|
16
|
+
<name>Apache License, Version 2.0</name>
|
|
17
|
+
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
|
18
|
+
</license>
|
|
19
|
+
</licenses>
|
|
20
|
+
|
|
21
|
+
<properties>
|
|
22
|
+
<maven.compiler.release>17</maven.compiler.release>
|
|
23
|
+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
24
|
+
<jackson.version>2.17.2</jackson.version>
|
|
25
|
+
</properties>
|
|
26
|
+
|
|
27
|
+
<dependencies>
|
|
28
|
+
<dependency>
|
|
29
|
+
<groupId>com.fasterxml.jackson.core</groupId>
|
|
30
|
+
<artifactId>jackson-databind</artifactId>
|
|
31
|
+
<version>${jackson.version}</version>
|
|
32
|
+
</dependency>
|
|
33
|
+
</dependencies>
|
|
34
|
+
</project>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
package dev.forgeos.adapter;
|
|
2
|
+
|
|
3
|
+
import java.util.List;
|
|
4
|
+
import java.util.Map;
|
|
5
|
+
|
|
6
|
+
public record Auth(
|
|
7
|
+
String kind,
|
|
8
|
+
String userId,
|
|
9
|
+
String tenantId,
|
|
10
|
+
String role,
|
|
11
|
+
List<String> roles,
|
|
12
|
+
List<String> permissions,
|
|
13
|
+
String email,
|
|
14
|
+
String name,
|
|
15
|
+
Map<String, Object> claims
|
|
16
|
+
) {
|
|
17
|
+
public static Auth anonymous() {
|
|
18
|
+
return new Auth("anonymous", null, null, null, null, null, null, null, null);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package dev.forgeos.adapter;
|
|
2
|
+
|
|
3
|
+
import java.util.List;
|
|
4
|
+
|
|
5
|
+
public record Diagnostic(
|
|
6
|
+
String severity,
|
|
7
|
+
String code,
|
|
8
|
+
String message,
|
|
9
|
+
String file,
|
|
10
|
+
String fixHint,
|
|
11
|
+
List<String> docs
|
|
12
|
+
) {
|
|
13
|
+
public static Diagnostic error(String code, String message) {
|
|
14
|
+
return new Diagnostic("error", code, message, null, null, List.of("docs/forge-protocol.md"));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
package dev.forgeos.adapter;
|
|
2
|
+
|
|
3
|
+
import java.util.ArrayList;
|
|
4
|
+
import java.util.List;
|
|
5
|
+
|
|
6
|
+
public final class Entry {
|
|
7
|
+
public String name;
|
|
8
|
+
public String kind;
|
|
9
|
+
public String description;
|
|
10
|
+
public String path;
|
|
11
|
+
public String method;
|
|
12
|
+
public Object inputSchema;
|
|
13
|
+
public Object outputSchema;
|
|
14
|
+
public String policy;
|
|
15
|
+
public Boolean tenantScoped;
|
|
16
|
+
public String transaction;
|
|
17
|
+
public String risk;
|
|
18
|
+
public Boolean needsApproval;
|
|
19
|
+
public List<String> effects;
|
|
20
|
+
|
|
21
|
+
public Entry copy() {
|
|
22
|
+
Entry copy = new Entry();
|
|
23
|
+
copy.name = name;
|
|
24
|
+
copy.kind = kind;
|
|
25
|
+
copy.description = description;
|
|
26
|
+
copy.path = path;
|
|
27
|
+
copy.method = method;
|
|
28
|
+
copy.inputSchema = inputSchema;
|
|
29
|
+
copy.outputSchema = outputSchema;
|
|
30
|
+
copy.policy = policy;
|
|
31
|
+
copy.tenantScoped = tenantScoped;
|
|
32
|
+
copy.transaction = transaction;
|
|
33
|
+
copy.risk = risk;
|
|
34
|
+
copy.needsApproval = needsApproval;
|
|
35
|
+
copy.effects = effects == null ? null : new ArrayList<>(effects);
|
|
36
|
+
return copy;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
package dev.forgeos.adapter;
|
|
2
|
+
|
|
3
|
+
import com.fasterxml.jackson.databind.JsonNode;
|
|
4
|
+
import java.util.Arrays;
|
|
5
|
+
import java.util.List;
|
|
6
|
+
|
|
7
|
+
public final class Forge {
|
|
8
|
+
private Forge() {
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public static ForgeRegistry service(String serviceName, ForgeRegistry.RegistryOption... options) {
|
|
12
|
+
return new ForgeRegistry(serviceName, options);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public static ForgeRegistry.RegistryOption framework(String value) {
|
|
16
|
+
return registry -> registry.setFramework(value);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public static ForgeRegistry.RegistryOption baseUrl(String value) {
|
|
20
|
+
return registry -> registry.setBaseUrl(value);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public static ForgeRegistry.RegistryOption health(String path) {
|
|
24
|
+
return registry -> registry.setHealth(path);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public static ForgeRegistry.RegistryOption schemaRef(String name, Object schema) {
|
|
28
|
+
return registry -> registry.addSchema(name, schema);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public static ForgeRegistry.EntryOption description(String value) {
|
|
32
|
+
return entry -> entry.description = value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public static ForgeRegistry.EntryOption path(String value) {
|
|
36
|
+
return entry -> entry.path = value;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public static ForgeRegistry.EntryOption method(String value) {
|
|
40
|
+
return entry -> entry.method = value;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public static ForgeRegistry.EntryOption inputSchema(Object schema) {
|
|
44
|
+
return entry -> entry.inputSchema = schema;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public static ForgeRegistry.EntryOption outputSchema(Object schema) {
|
|
48
|
+
return entry -> entry.outputSchema = schema;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public static ForgeRegistry.EntryOption policy(String value) {
|
|
52
|
+
return entry -> entry.policy = value;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public static ForgeRegistry.EntryOption tenantScoped(boolean value) {
|
|
56
|
+
return entry -> entry.tenantScoped = value;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public static ForgeRegistry.EntryOption transaction(TransactionMode value) {
|
|
60
|
+
return entry -> entry.transaction = value.value();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public static ForgeRegistry.EntryOption risk(Risk value) {
|
|
64
|
+
return entry -> entry.risk = value.value();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public static ForgeRegistry.EntryOption needsApproval(boolean value) {
|
|
68
|
+
return entry -> entry.needsApproval = value;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public static ForgeRegistry.EntryOption effects(String... values) {
|
|
72
|
+
return entry -> entry.effects = List.copyOf(Arrays.asList(values));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public static ForgeRegistry.EntryOption readOnly() {
|
|
76
|
+
return entry -> {
|
|
77
|
+
entry.transaction = TransactionMode.READ_ONLY.value();
|
|
78
|
+
entry.risk = Risk.READ.value();
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public static <In, Out> ForgeHandler handle(
|
|
83
|
+
Class<In> inputClass,
|
|
84
|
+
TypedForgeHandler<In, Out> handler
|
|
85
|
+
) {
|
|
86
|
+
return (context, rawArgs) -> {
|
|
87
|
+
JsonNode args = rawArgs == null || rawArgs.isNull()
|
|
88
|
+
? Json.MAPPER.createObjectNode()
|
|
89
|
+
: rawArgs;
|
|
90
|
+
In input = Json.MAPPER.treeToValue(args, inputClass);
|
|
91
|
+
return handler.handle(context, input);
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
package dev.forgeos.adapter;
|
|
2
|
+
|
|
3
|
+
public record ForgeCall(String service, String entry, String kind, String traceId) {
|
|
4
|
+
public ForgeCall withDefaults(String serviceName, String entryName, String entryKind, String fallbackTraceId) {
|
|
5
|
+
return new ForgeCall(
|
|
6
|
+
service == null || service.isBlank() ? serviceName : service,
|
|
7
|
+
entry == null || entry.isBlank() ? entryName : entry,
|
|
8
|
+
kind == null || kind.isBlank() ? entryKind : kind,
|
|
9
|
+
traceId == null || traceId.isBlank() ? fallbackTraceId : traceId
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
package dev.forgeos.adapter;
|
|
2
|
+
|
|
3
|
+
import com.fasterxml.jackson.databind.JsonNode;
|
|
4
|
+
import com.sun.net.httpserver.Headers;
|
|
5
|
+
import com.sun.net.httpserver.HttpExchange;
|
|
6
|
+
import com.sun.net.httpserver.HttpHandler;
|
|
7
|
+
import com.sun.net.httpserver.HttpServer;
|
|
8
|
+
import java.io.IOException;
|
|
9
|
+
import java.io.InputStream;
|
|
10
|
+
import java.io.OutputStream;
|
|
11
|
+
import java.net.InetSocketAddress;
|
|
12
|
+
import java.net.URI;
|
|
13
|
+
import java.net.URLDecoder;
|
|
14
|
+
import java.nio.charset.StandardCharsets;
|
|
15
|
+
import java.util.HashMap;
|
|
16
|
+
import java.util.List;
|
|
17
|
+
import java.util.Map;
|
|
18
|
+
|
|
19
|
+
public final class ForgeHttpHandler implements HttpHandler {
|
|
20
|
+
private final ForgeRegistry registry;
|
|
21
|
+
|
|
22
|
+
public ForgeHttpHandler(ForgeRegistry registry) {
|
|
23
|
+
this.registry = registry;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public static HttpServer listen(ForgeRegistry registry, String host, int port) throws IOException {
|
|
27
|
+
HttpServer server = HttpServer.create(new InetSocketAddress(host, port), 0);
|
|
28
|
+
ForgeHttpHandler handler = new ForgeHttpHandler(registry);
|
|
29
|
+
server.createContext("/", handler);
|
|
30
|
+
server.start();
|
|
31
|
+
return server;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@Override
|
|
35
|
+
public void handle(HttpExchange exchange) throws IOException {
|
|
36
|
+
String path = exchange.getRequestURI().getPath();
|
|
37
|
+
try {
|
|
38
|
+
if (registry.healthPath().equals(path)) {
|
|
39
|
+
writeJson(exchange, 200, Map.of("ok", true, "service", registry.serviceName()));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if ("/manifest".equals(path)) {
|
|
43
|
+
String baseUrl = queryParams(exchange.getRequestURI()).getOrDefault("baseUrl", registry.baseUrl());
|
|
44
|
+
writeJson(exchange, 200, registry.manifest(baseUrl));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (path.startsWith("/commands/")) {
|
|
48
|
+
handleRuntime(exchange, EntryKind.COMMAND, path.substring("/commands/".length()));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (path.startsWith("/queries/")) {
|
|
52
|
+
handleRuntime(exchange, EntryKind.QUERY, path.substring("/queries/".length()));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
writeError(exchange, 404, traceIdFrom(exchange, null), "FORGE_JAVA_ROUTE_NOT_FOUND", "route not found");
|
|
56
|
+
} catch (Exception error) {
|
|
57
|
+
writeError(exchange, 500, traceIdFrom(exchange, null), "FORGE_JAVA_HANDLER_FAILED", error.getMessage());
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private void handleRuntime(HttpExchange exchange, EntryKind kind, String rawName) throws IOException {
|
|
62
|
+
String name = decode(rawName);
|
|
63
|
+
if (!"POST".equals(exchange.getRequestMethod()) && !"GET".equals(exchange.getRequestMethod())) {
|
|
64
|
+
writeError(exchange, 405, traceIdFrom(exchange, null), "FORGE_JAVA_METHOD_NOT_ALLOWED", "external entry only accepts GET or POST");
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
ForgeRegistry.RegisteredEntry registered = registry.lookup(kind, name);
|
|
69
|
+
if (registered == null) {
|
|
70
|
+
writeError(exchange, 404, traceIdFrom(exchange, null), "FORGE_JAVA_ENTRY_NOT_FOUND", "external entry not found");
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
RequestEnvelope envelope;
|
|
75
|
+
try {
|
|
76
|
+
envelope = readEnvelope(exchange);
|
|
77
|
+
} catch (Exception error) {
|
|
78
|
+
writeError(exchange, 400, traceIdFrom(exchange, null), "FORGE_JAVA_BAD_REQUEST", error.getMessage());
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
String traceId = traceIdFrom(exchange, envelope);
|
|
83
|
+
ForgeCall forge = envelope.forge() == null
|
|
84
|
+
? new ForgeCall(registry.serviceName(), name, kind.value(), traceId)
|
|
85
|
+
: envelope.forge().withDefaults(registry.serviceName(), name, kind.value(), traceId);
|
|
86
|
+
Auth auth = envelope.auth() == null || envelope.auth().kind() == null
|
|
87
|
+
? authFromHeaders(exchange.getRequestHeaders())
|
|
88
|
+
: envelope.auth();
|
|
89
|
+
|
|
90
|
+
ForgeContext context = new ForgeContext(auth, forge, exchange.getRequestHeaders());
|
|
91
|
+
try {
|
|
92
|
+
Object result = registered.handler().handle(context, envelope.args());
|
|
93
|
+
writeJson(exchange, 200, ResponseEnvelope.ok(result, forge.traceId()));
|
|
94
|
+
} catch (Exception error) {
|
|
95
|
+
writeError(exchange, 500, forge.traceId(), "FORGE_JAVA_HANDLER_FAILED", error.getMessage());
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private RequestEnvelope readEnvelope(HttpExchange exchange) throws IOException {
|
|
100
|
+
if ("GET".equals(exchange.getRequestMethod())) {
|
|
101
|
+
String args = queryParams(exchange.getRequestURI()).getOrDefault("args", "{}");
|
|
102
|
+
JsonNode argsNode = Json.MAPPER.readTree(args);
|
|
103
|
+
return new RequestEnvelope(argsNode, null, null);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
try (InputStream body = exchange.getRequestBody()) {
|
|
107
|
+
byte[] bytes = body.readAllBytes();
|
|
108
|
+
if (bytes.length == 0) {
|
|
109
|
+
return new RequestEnvelope(Json.MAPPER.createObjectNode(), null, null);
|
|
110
|
+
}
|
|
111
|
+
RequestEnvelope envelope = Json.MAPPER.readValue(bytes, RequestEnvelope.class);
|
|
112
|
+
JsonNode args = envelope.args() == null ? Json.MAPPER.createObjectNode() : envelope.args();
|
|
113
|
+
return new RequestEnvelope(args, envelope.auth(), envelope.forge());
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private static Auth authFromHeaders(Headers headers) {
|
|
118
|
+
String kind = firstHeader(headers, "x-forge-auth-kind");
|
|
119
|
+
if (kind == null || kind.isBlank()) {
|
|
120
|
+
kind = "anonymous";
|
|
121
|
+
}
|
|
122
|
+
return new Auth(
|
|
123
|
+
kind,
|
|
124
|
+
firstHeader(headers, "x-forge-user-id"),
|
|
125
|
+
firstHeader(headers, "x-forge-tenant-id"),
|
|
126
|
+
firstHeader(headers, "x-forge-role"),
|
|
127
|
+
null,
|
|
128
|
+
null,
|
|
129
|
+
null,
|
|
130
|
+
null,
|
|
131
|
+
null
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private static String traceIdFrom(HttpExchange exchange, RequestEnvelope envelope) {
|
|
136
|
+
if (envelope != null && envelope.forge() != null && envelope.forge().traceId() != null) {
|
|
137
|
+
return envelope.forge().traceId();
|
|
138
|
+
}
|
|
139
|
+
return firstHeader(exchange.getRequestHeaders(), "x-forge-trace-id");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private static String firstHeader(Headers headers, String name) {
|
|
143
|
+
List<String> values = headers.get(name);
|
|
144
|
+
if (values == null || values.isEmpty()) {
|
|
145
|
+
values = headers.get(name.toLowerCase());
|
|
146
|
+
}
|
|
147
|
+
return values == null || values.isEmpty() ? null : values.get(0);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private static Map<String, String> queryParams(URI uri) {
|
|
151
|
+
Map<String, String> params = new HashMap<>();
|
|
152
|
+
String query = uri.getRawQuery();
|
|
153
|
+
if (query == null || query.isBlank()) {
|
|
154
|
+
return params;
|
|
155
|
+
}
|
|
156
|
+
for (String part : query.split("&")) {
|
|
157
|
+
String[] pieces = part.split("=", 2);
|
|
158
|
+
params.put(decode(pieces[0]), pieces.length > 1 ? decode(pieces[1]) : "");
|
|
159
|
+
}
|
|
160
|
+
return params;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private static String decode(String value) {
|
|
164
|
+
return URLDecoder.decode(value, StandardCharsets.UTF_8);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private static void writeError(HttpExchange exchange, int status, String traceId, String code, String message) throws IOException {
|
|
168
|
+
writeJson(exchange, status, ResponseEnvelope.error(code, message, traceId));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private static void writeJson(HttpExchange exchange, int status, Object body) throws IOException {
|
|
172
|
+
byte[] bytes = Json.MAPPER.writeValueAsBytes(body);
|
|
173
|
+
exchange.getResponseHeaders().set("content-type", "application/json");
|
|
174
|
+
exchange.sendResponseHeaders(status, bytes.length);
|
|
175
|
+
try (OutputStream response = exchange.getResponseBody()) {
|
|
176
|
+
response.write(bytes);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|