forgeos 0.1.0-alpha.65 → 0.1.0-alpha.67
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/.npmignore +19 -19
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +24 -0
- package/LICENSE +21 -21
- package/README.md +525 -525
- package/adapters/java/README.md +68 -68
- package/adapters/java/pom.xml +47 -47
- package/adapters/java/src/main/java/dev/forgeos/adapter/Auth.java +20 -20
- package/adapters/java/src/main/java/dev/forgeos/adapter/Diagnostic.java +16 -16
- package/adapters/java/src/main/java/dev/forgeos/adapter/Entry.java +38 -38
- package/adapters/java/src/main/java/dev/forgeos/adapter/EntryKind.java +16 -16
- package/adapters/java/src/main/java/dev/forgeos/adapter/ErrorInfo.java +4 -4
- package/adapters/java/src/main/java/dev/forgeos/adapter/Forge.java +94 -94
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeCall.java +12 -12
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeContext.java +11 -11
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHandler.java +8 -8
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHttpHandler.java +179 -179
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeRegistry.java +121 -121
- package/adapters/java/src/main/java/dev/forgeos/adapter/Json.java +14 -14
- package/adapters/java/src/main/java/dev/forgeos/adapter/Manifest.java +14 -14
- package/adapters/java/src/main/java/dev/forgeos/adapter/RequestEnvelope.java +6 -6
- package/adapters/java/src/main/java/dev/forgeos/adapter/ResponseEnvelope.java +25 -25
- package/adapters/java/src/main/java/dev/forgeos/adapter/Risk.java +18 -18
- package/adapters/java/src/main/java/dev/forgeos/adapter/Schemas.java +36 -36
- package/adapters/java/src/main/java/dev/forgeos/adapter/Service.java +65 -65
- package/adapters/java/src/main/java/dev/forgeos/adapter/TransactionMode.java +18 -18
- package/adapters/java/src/main/java/dev/forgeos/adapter/TypedForgeHandler.java +6 -6
- package/adapters/java-spring-boot-starter/README.md +32 -32
- package/adapters/java-spring-boot-starter/pom.xml +49 -49
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeCommand.java +22 -22
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeExternalService.java +15 -15
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeQuery.java +16 -16
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.java +18 -18
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.java +16 -16
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringRuntime.java +104 -104
- package/adapters/java-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -1
- package/bin/forge.mjs +38 -38
- package/docs/agent-fabric.md +131 -0
- package/examples/java-billing/pom.xml +60 -60
- package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/CreateInvoiceInput.java +4 -4
- package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Invoice.java +11 -11
- package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Main.java +127 -127
- package/package.json +5 -4
- package/packages/eslint-plugin-forge/index.ts +15 -15
- package/packages/eslint-plugin-forge/package.json +10 -10
- package/packages/eslint-plugin-forge/src/check-source.ts +95 -95
- package/packages/eslint-plugin-forge/src/load-artifacts.ts +24 -24
- package/packages/eslint-plugin-forge/src/rule-no-forge-guard-violation.ts +93 -93
- package/schemas/agent-fabric/v0.1/control-event.schema.json +281 -281
- package/scripts/field-test-forgeos.mjs +1021 -1021
- package/src/forge/_generated/releaseManifest.json +1 -1
- package/src/forge/_generated/releaseManifest.ts +3 -3
- package/src/forge/agent-adapters/index.ts +7 -3
- package/src/forge/agent-adapters/types.ts +1 -0
- package/src/forge/agent-fabric/attached-snapshot.ts +55 -0
- package/src/forge/agent-fabric/attached-task-contract.ts +105 -0
- package/src/forge/agent-fabric/attached-task-service.ts +127 -0
- package/src/forge/agent-fabric/attached-task-store.ts +109 -0
- package/src/forge/agent-fabric/codex-adversarial-review.ts +229 -0
- package/src/forge/agent-fabric/codex-sdk-worker.ts +163 -0
- package/src/forge/agent-fabric/index.ts +19 -0
- package/src/forge/agent-fabric/local-adaptive-digest-worker.mjs +26 -26
- package/src/forge/agent-fabric/local-change-review-service.ts +374 -0
- package/src/forge/agent-fabric/local-task-server.ts +324 -249
- package/src/forge/agent-fabric/managed-environment.ts +205 -0
- package/src/forge/agent-fabric/managed-run-contract.ts +102 -0
- package/src/forge/agent-fabric/managed-run-service.ts +392 -0
- package/src/forge/agent-fabric/managed-run-store.ts +135 -0
- package/src/forge/agent-fabric/managed-workspace.ts +214 -0
- package/src/forge/agent-fabric/readiness.ts +26 -0
- package/src/forge/agent-fabric/workflow-engine.ts +218 -0
- package/src/forge/agent-fabric/workflow-task-actions.ts +104 -0
- package/src/forge/agent-fabric/workflow-templates.ts +11 -0
- package/src/forge/agent-memory/bridge.ts +309 -47
- package/src/forge/agent-memory/context-pack.ts +8 -1
- package/src/forge/agent-memory/hook-runner.ts +38 -19
- package/src/forge/agent-memory/mcp.ts +500 -286
- package/src/forge/agent-memory/sources/codex-hook-runner.mjs +343 -234
- package/src/forge/agent-memory/sources/codex.ts +49 -7
- package/src/forge/agent-memory/types.ts +11 -0
- package/src/forge/bench.ts +154 -154
- package/src/forge/cair/action-journal.ts +61 -61
- package/src/forge/cair/action-parser.ts +314 -314
- package/src/forge/cair/action-validator.ts +40 -40
- package/src/forge/cair/actions.ts +1818 -1818
- package/src/forge/cair/format.ts +77 -77
- package/src/forge/cair/index.ts +106 -106
- package/src/forge/cair/query.ts +478 -478
- package/src/forge/cair/snapshot.ts +315 -315
- package/src/forge/cair/types.ts +248 -248
- package/src/forge/cli/ai.ts +816 -816
- package/src/forge/cli/codex-app-server.ts +877 -877
- package/src/forge/cli/fabric.ts +205 -131
- package/src/forge/cli/index.ts +26 -26
- package/src/forge/cli/main.ts +259 -245
- package/src/forge/cli/next-actions.ts +23 -23
- package/src/forge/cli/parse.ts +3574 -3542
- package/src/forge/cli/release.ts +309 -309
- package/src/forge/cli/self-host.ts +510 -510
- package/src/forge/compiler/ai-registry/parse.ts +219 -219
- package/src/forge/compiler/app-graph/classify.ts +10 -10
- package/src/forge/compiler/app-graph/dup-symbol.ts +29 -29
- package/src/forge/compiler/app-graph/extract.ts +231 -231
- package/src/forge/compiler/app-graph/forge-apis.ts +25 -25
- package/src/forge/compiler/app-graph/index.ts +11 -11
- package/src/forge/compiler/app-graph/module-graph.ts +151 -151
- package/src/forge/compiler/app-graph/parser.ts +71 -71
- package/src/forge/compiler/app-graph/symbols.ts +48 -48
- package/src/forge/compiler/app-graph/types.ts +43 -43
- package/src/forge/compiler/app-graph/versions.ts +14 -14
- package/src/forge/compiler/cache/index.ts +17 -17
- package/src/forge/compiler/cache/key.ts +46 -46
- package/src/forge/compiler/cache/scheduler.ts +72 -72
- package/src/forge/compiler/cache/store.ts +78 -78
- package/src/forge/compiler/classifier/capabilities.ts +64 -64
- package/src/forge/compiler/classifier/classify.ts +76 -76
- package/src/forge/compiler/classifier/contexts.ts +188 -188
- package/src/forge/compiler/classifier/index.ts +18 -18
- package/src/forge/compiler/classifier/runtime-matrix.ts +45 -45
- package/src/forge/compiler/classifier/secrets.ts +31 -31
- package/src/forge/compiler/classifier/signals.ts +95 -95
- package/src/forge/compiler/client-sdk/build-manifest.ts +210 -210
- package/src/forge/compiler/data-graph/sql/serialize.ts +89 -89
- package/src/forge/compiler/data-graph/sql/types.ts +38 -38
- package/src/forge/compiler/diagnostics/index.ts +57 -57
- package/src/forge/compiler/emitter/artifact-kind.ts +14 -14
- package/src/forge/compiler/emitter/barrel.ts +47 -47
- package/src/forge/compiler/emitter/constants.ts +7 -7
- package/src/forge/compiler/emitter/emit.ts +223 -223
- package/src/forge/compiler/emitter/index.ts +24 -24
- package/src/forge/compiler/emitter/lock.ts +61 -61
- package/src/forge/compiler/external-manifest/registry.ts +205 -205
- package/src/forge/compiler/external-manifest/types.ts +91 -91
- package/src/forge/compiler/external-manifest/validate.ts +373 -373
- package/src/forge/compiler/frontend-graph/build.ts +623 -623
- package/src/forge/compiler/guards/artifacts.ts +96 -96
- package/src/forge/compiler/guards/check-import-guards.ts +106 -106
- package/src/forge/compiler/guards/index.ts +11 -11
- package/src/forge/compiler/guards/propagate-contexts.ts +57 -57
- package/src/forge/compiler/index.ts +17 -17
- package/src/forge/compiler/integration/index.ts +17 -17
- package/src/forge/compiler/integration/snapshot.ts +54 -54
- package/src/forge/compiler/integration/templates/convex.ts +70 -70
- package/src/forge/compiler/orchestrator/discover.ts +214 -214
- package/src/forge/compiler/orchestrator/guards.ts +5 -5
- package/src/forge/compiler/orchestrator/index.ts +27 -27
- package/src/forge/compiler/orchestrator/orphans.ts +51 -51
- package/src/forge/compiler/orchestrator/profile.ts +23 -23
- package/src/forge/compiler/orchestrator/serialize.ts +979 -979
- package/src/forge/compiler/orchestrator/verify.ts +35 -35
- package/src/forge/compiler/package-graph/capabilities-stub.ts +33 -33
- package/src/forge/compiler/package-graph/checksum.ts +107 -107
- package/src/forge/compiler/package-graph/exports-discovery.ts +91 -91
- package/src/forge/compiler/package-graph/extract-dts.ts +32 -32
- package/src/forge/compiler/package-graph/index.ts +24 -24
- package/src/forge/compiler/package-graph/jsdoc.ts +50 -50
- package/src/forge/compiler/package-graph/oracle.ts +326 -326
- package/src/forge/compiler/package-graph/read-file.ts +21 -21
- package/src/forge/compiler/package-graph/resolve.ts +131 -131
- package/src/forge/compiler/package-manager/adapter.ts +240 -240
- package/src/forge/compiler/package-manager/commands.ts +51 -51
- package/src/forge/compiler/package-manager/detect.ts +65 -65
- package/src/forge/compiler/package-manager/executor.ts +146 -146
- package/src/forge/compiler/package-manager/index.ts +22 -22
- package/src/forge/compiler/package-manager/parse-spec.ts +16 -16
- package/src/forge/compiler/primitives/compare.ts +26 -26
- package/src/forge/compiler/primitives/hash.ts +29 -29
- package/src/forge/compiler/primitives/header.ts +43 -43
- package/src/forge/compiler/primitives/index.ts +45 -45
- package/src/forge/compiler/primitives/paths.ts +24 -24
- package/src/forge/compiler/primitives/serialize.ts +66 -66
- package/src/forge/compiler/primitives/sort.ts +87 -87
- package/src/forge/compiler/recipes/helpers.ts +37 -37
- package/src/forge/compiler/sandbox/artifact-sanitize.ts +26 -26
- package/src/forge/compiler/sandbox/backends/child.ts +123 -123
- package/src/forge/compiler/sandbox/backends/docker.ts +173 -173
- package/src/forge/compiler/sandbox/index.ts +51 -51
- package/src/forge/compiler/sandbox/inspect.ts +143 -143
- package/src/forge/compiler/sandbox/inspector-entry.ts +115 -115
- package/src/forge/compiler/sandbox/limits.ts +31 -31
- package/src/forge/compiler/sandbox/scrub-env.ts +60 -60
- package/src/forge/compiler/sandbox/secret-scan.ts +54 -54
- package/src/forge/compiler/sandbox/serialize.ts +106 -106
- package/src/forge/compiler/sandbox/types.ts +7 -7
- package/src/forge/compiler/test-graph/build.ts +285 -285
- package/src/forge/compiler/types/app-graph.ts +87 -87
- package/src/forge/compiler/types/capability.ts +29 -29
- package/src/forge/compiler/types/classification.ts +9 -9
- package/src/forge/compiler/types/diagnostic.ts +2 -2
- package/src/forge/compiler/types/frontend-graph.ts +81 -81
- package/src/forge/compiler/types/import-guards.ts +19 -19
- package/src/forge/compiler/types/index.ts +98 -98
- package/src/forge/compiler/types/json.ts +3 -3
- package/src/forge/compiler/types/lock.ts +37 -37
- package/src/forge/compiler/types/runtime-matrix.ts +16 -16
- package/src/forge/compiler/types/runtime.ts +30 -30
- package/src/forge/compiler/types/sandbox.ts +24 -24
- package/src/forge/delta/broker-runner.mjs +5 -0
- package/src/forge/delta/broker.ts +429 -0
- package/src/forge/delta/classifier.ts +52 -52
- package/src/forge/delta/explain.ts +238 -238
- package/src/forge/delta/git-observer.ts +24 -0
- package/src/forge/delta/ids.ts +40 -40
- package/src/forge/delta/index.ts +25 -25
- package/src/forge/delta/process-identity.ts +31 -0
- package/src/forge/delta/queue-status.ts +190 -0
- package/src/forge/delta/redaction.ts +50 -50
- package/src/forge/delta/schema.ts +135 -135
- package/src/forge/delta/session.ts +142 -142
- package/src/forge/delta/status.ts +82 -145
- package/src/forge/delta/store.ts +77 -32
- package/src/forge/delta/timeline.ts +178 -178
- package/src/forge/dev/types.ts +63 -63
- package/src/forge/dev/watch.ts +119 -119
- package/src/forge/intent/index.ts +509 -509
- package/src/forge/make/types.ts +153 -153
- package/src/forge/refactor/index.ts +1937 -1937
- package/src/forge/refactor/runtime-rename.ts +598 -598
- package/src/forge/repair/rules/index.ts +476 -476
- package/src/forge/review/types.ts +211 -211
- package/src/forge/runtime/db/generated-client.ts +305 -305
- package/src/forge/runtime/db/pglite-adapter.ts +33 -11
- package/src/forge/runtime/runner/run-entry.ts +236 -236
- package/src/forge/version.ts +1 -1
- package/templates/agent-workroom/AGENTS.md +29 -29
- package/templates/agent-workroom/README.md +34 -34
- package/templates/agent-workroom/forge.config.ts +3 -3
- package/templates/agent-workroom/package.json +34 -34
- package/templates/agent-workroom/pnpm-workspace.yaml +2 -2
- package/templates/agent-workroom/src/actions/indexAgentSignal.ts +10 -10
- package/templates/agent-workroom/src/commands/openWorkroom.ts +61 -61
- package/templates/agent-workroom/src/commands/recordAgentSignal.ts +119 -119
- package/templates/agent-workroom/src/commands/recordCheckRun.ts +52 -52
- package/templates/agent-workroom/src/forge/schema.ts +54 -54
- package/templates/agent-workroom/src/policies.ts +6 -6
- package/templates/agent-workroom/src/queries/listWorkrooms.ts +11 -11
- package/templates/agent-workroom/src/queries/liveWorkroom.ts +63 -63
- package/templates/agent-workroom/tsconfig.json +16 -16
- package/templates/agent-workroom/web/index.html +13 -13
- package/templates/agent-workroom/web/package.json +21 -21
- package/templates/agent-workroom/web/src/App.tsx +345 -345
- package/templates/agent-workroom/web/src/main.tsx +13 -13
- package/templates/agent-workroom/web/src/styles.css +545 -545
- package/templates/agent-workroom/web/tsconfig.json +27 -27
- package/templates/b2b-support-web/package.json +37 -37
- package/templates/b2b-support-web/pnpm-workspace.yaml +2 -2
- package/templates/b2b-support-web/web/package.json +21 -21
- package/templates/minimal-web/package.json +34 -34
- package/templates/minimal-web/pnpm-workspace.yaml +2 -2
- package/templates/minimal-web/web/index.html +13 -13
- package/templates/minimal-web/web/src/styles.css +190 -190
- package/templates/nuxt-web/.vscode/settings.json +14 -14
- package/templates/nuxt-web/.yarnrc.yml +1 -1
- package/templates/nuxt-web/README.md +30 -30
- package/templates/nuxt-web/forge.config.ts +3 -3
- package/templates/nuxt-web/package.json +34 -34
- package/templates/nuxt-web/pnpm-workspace.yaml +2 -2
- package/templates/nuxt-web/src/actions/logNoteCreated.ts +11 -11
- package/templates/nuxt-web/src/commands/createNote.ts +26 -26
- package/templates/nuxt-web/src/forge/schema.ts +12 -12
- package/templates/nuxt-web/src/policies.ts +6 -6
- package/templates/nuxt-web/src/queries/listNotes.ts +8 -8
- package/templates/nuxt-web/src/queries/liveNotes.ts +8 -8
- package/templates/nuxt-web/tsconfig.json +17 -17
- package/templates/nuxt-web/web/app.vue +67 -67
- package/templates/nuxt-web/web/components/LiveNotes.vue +89 -89
- package/templates/nuxt-web/web/components/NoteComposer.vue +100 -100
- package/templates/nuxt-web/web/composables/forge.ts +13 -13
- package/templates/nuxt-web/web/composables/useNotes.ts +24 -24
- package/templates/nuxt-web/web/nuxt.config.ts +11 -11
- package/templates/nuxt-web/web/package.json +19 -19
- package/templates/nuxt-web/web/plugins/forge.client.ts +10 -10
- package/templates/nuxt-web/web/plugins/forge.server.ts +10 -10
- package/templates/nuxt-web/web/server/api/forge-health.get.ts +7 -7
- package/templates/nuxt-web/web/tsconfig.json +6 -6
- package/templates/vendor-access/.vscode/settings.json +14 -14
- package/templates/vendor-access/README.md +30 -30
- package/templates/vendor-access/package.json +35 -35
- package/templates/vendor-access/pnpm-workspace.yaml +2 -2
- package/templates/vendor-access/tsconfig.json +17 -17
- package/templates/vendor-access/web/index.html +13 -13
- package/templates/vendor-access/web/package.json +21 -21
- package/templates/vendor-access/web/src/styles.css +682 -682
- package/templates/vendor-access/web/tsconfig.json +18 -18
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
package dev.forgeos.adapter;
|
|
2
|
-
|
|
3
|
-
import com.fasterxml.jackson.databind.JsonNode;
|
|
4
|
-
|
|
5
|
-
@FunctionalInterface
|
|
6
|
-
public interface ForgeHandler {
|
|
7
|
-
Object handle(ForgeContext context, JsonNode args) throws Exception;
|
|
8
|
-
}
|
|
1
|
+
package dev.forgeos.adapter;
|
|
2
|
+
|
|
3
|
+
import com.fasterxml.jackson.databind.JsonNode;
|
|
4
|
+
|
|
5
|
+
@FunctionalInterface
|
|
6
|
+
public interface ForgeHandler {
|
|
7
|
+
Object handle(ForgeContext context, JsonNode args) throws Exception;
|
|
8
|
+
}
|
|
@@ -1,179 +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
|
-
}
|
|
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
|
+
}
|
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
package dev.forgeos.adapter;
|
|
2
|
-
|
|
3
|
-
import java.io.IOException;
|
|
4
|
-
import java.io.OutputStream;
|
|
5
|
-
import java.util.ArrayList;
|
|
6
|
-
import java.util.LinkedHashMap;
|
|
7
|
-
import java.util.List;
|
|
8
|
-
import java.util.Map;
|
|
9
|
-
|
|
10
|
-
public final class ForgeRegistry {
|
|
11
|
-
private final Service service;
|
|
12
|
-
private final Map<String, Object> schemas = new LinkedHashMap<>();
|
|
13
|
-
private final List<RegisteredEntry> entries = new ArrayList<>();
|
|
14
|
-
private final Map<String, RegisteredEntry> lookup = new LinkedHashMap<>();
|
|
15
|
-
private String framework = "java/jdk-http";
|
|
16
|
-
|
|
17
|
-
public ForgeRegistry(String serviceName, RegistryOption... options) {
|
|
18
|
-
this.service = new Service(serviceName, "http", null, null, "/health");
|
|
19
|
-
for (RegistryOption option : options) {
|
|
20
|
-
option.apply(this);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public String serviceName() {
|
|
25
|
-
return service.name();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
public String baseUrl() {
|
|
29
|
-
return service.baseUrl();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
public String healthPath() {
|
|
33
|
-
return service.health() == null ? "/health" : service.health();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
public void command(String name, ForgeHandler handler, EntryOption... options) {
|
|
37
|
-
Entry entry = new Entry();
|
|
38
|
-
entry.name = name;
|
|
39
|
-
entry.kind = EntryKind.COMMAND.value();
|
|
40
|
-
entry.path = "/commands/" + name;
|
|
41
|
-
entry.method = "POST";
|
|
42
|
-
entry.transaction = TransactionMode.EXTERNAL_MANAGED.value();
|
|
43
|
-
entry.risk = Risk.WRITE.value();
|
|
44
|
-
add(entry, handler, options);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
public void query(String name, ForgeHandler handler, EntryOption... options) {
|
|
48
|
-
Entry entry = new Entry();
|
|
49
|
-
entry.name = name;
|
|
50
|
-
entry.kind = EntryKind.QUERY.value();
|
|
51
|
-
entry.path = "/queries/" + name;
|
|
52
|
-
entry.method = "POST";
|
|
53
|
-
entry.transaction = TransactionMode.READ_ONLY.value();
|
|
54
|
-
entry.risk = Risk.READ.value();
|
|
55
|
-
add(entry, handler, options);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
public Manifest manifest(String baseUrl) {
|
|
59
|
-
Service manifestService = service;
|
|
60
|
-
if (baseUrl != null && !baseUrl.isBlank()) {
|
|
61
|
-
manifestService = new Service(service.name(), service.transport(), baseUrl, service.command(), service.health());
|
|
62
|
-
}
|
|
63
|
-
List<Entry> manifestEntries = entries.stream().map(registered -> registered.entry().copy()).toList();
|
|
64
|
-
return new Manifest("1.0", "java", framework, manifestService, manifestEntries, schemas.isEmpty() ? null : schemas);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
public byte[] marshalManifest(String baseUrl) throws IOException {
|
|
68
|
-
return Json.MAPPER.writerWithDefaultPrettyPrinter().writeValueAsBytes(manifest(baseUrl));
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
public void writeManifest(OutputStream output, String baseUrl) throws IOException {
|
|
72
|
-
output.write(marshalManifest(baseUrl));
|
|
73
|
-
output.write('\n');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
RegisteredEntry lookup(EntryKind kind, String name) {
|
|
77
|
-
return lookup.get(key(kind, name));
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
void setFramework(String framework) {
|
|
81
|
-
this.framework = framework;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
void setBaseUrl(String baseUrl) {
|
|
85
|
-
this.service.setBaseUrl(baseUrl);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
void setHealth(String health) {
|
|
89
|
-
this.service.setHealth(health);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
void addSchema(String name, Object schema) {
|
|
93
|
-
this.schemas.put(name, schema);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
private void add(Entry entry, ForgeHandler handler, EntryOption... options) {
|
|
97
|
-
for (EntryOption option : options) {
|
|
98
|
-
option.apply(entry);
|
|
99
|
-
}
|
|
100
|
-
RegisteredEntry registered = new RegisteredEntry(entry, handler);
|
|
101
|
-
entries.add(registered);
|
|
102
|
-
lookup.put(key(EntryKind.valueOf(entry.kind.toUpperCase()), entry.name), registered);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
private static String key(EntryKind kind, String name) {
|
|
106
|
-
return kind.value() + ":" + name;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
@FunctionalInterface
|
|
110
|
-
public interface RegistryOption {
|
|
111
|
-
void apply(ForgeRegistry registry);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
@FunctionalInterface
|
|
115
|
-
public interface EntryOption {
|
|
116
|
-
void apply(Entry entry);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
record RegisteredEntry(Entry entry, ForgeHandler handler) {
|
|
120
|
-
}
|
|
121
|
-
}
|
|
1
|
+
package dev.forgeos.adapter;
|
|
2
|
+
|
|
3
|
+
import java.io.IOException;
|
|
4
|
+
import java.io.OutputStream;
|
|
5
|
+
import java.util.ArrayList;
|
|
6
|
+
import java.util.LinkedHashMap;
|
|
7
|
+
import java.util.List;
|
|
8
|
+
import java.util.Map;
|
|
9
|
+
|
|
10
|
+
public final class ForgeRegistry {
|
|
11
|
+
private final Service service;
|
|
12
|
+
private final Map<String, Object> schemas = new LinkedHashMap<>();
|
|
13
|
+
private final List<RegisteredEntry> entries = new ArrayList<>();
|
|
14
|
+
private final Map<String, RegisteredEntry> lookup = new LinkedHashMap<>();
|
|
15
|
+
private String framework = "java/jdk-http";
|
|
16
|
+
|
|
17
|
+
public ForgeRegistry(String serviceName, RegistryOption... options) {
|
|
18
|
+
this.service = new Service(serviceName, "http", null, null, "/health");
|
|
19
|
+
for (RegistryOption option : options) {
|
|
20
|
+
option.apply(this);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public String serviceName() {
|
|
25
|
+
return service.name();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public String baseUrl() {
|
|
29
|
+
return service.baseUrl();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public String healthPath() {
|
|
33
|
+
return service.health() == null ? "/health" : service.health();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public void command(String name, ForgeHandler handler, EntryOption... options) {
|
|
37
|
+
Entry entry = new Entry();
|
|
38
|
+
entry.name = name;
|
|
39
|
+
entry.kind = EntryKind.COMMAND.value();
|
|
40
|
+
entry.path = "/commands/" + name;
|
|
41
|
+
entry.method = "POST";
|
|
42
|
+
entry.transaction = TransactionMode.EXTERNAL_MANAGED.value();
|
|
43
|
+
entry.risk = Risk.WRITE.value();
|
|
44
|
+
add(entry, handler, options);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public void query(String name, ForgeHandler handler, EntryOption... options) {
|
|
48
|
+
Entry entry = new Entry();
|
|
49
|
+
entry.name = name;
|
|
50
|
+
entry.kind = EntryKind.QUERY.value();
|
|
51
|
+
entry.path = "/queries/" + name;
|
|
52
|
+
entry.method = "POST";
|
|
53
|
+
entry.transaction = TransactionMode.READ_ONLY.value();
|
|
54
|
+
entry.risk = Risk.READ.value();
|
|
55
|
+
add(entry, handler, options);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public Manifest manifest(String baseUrl) {
|
|
59
|
+
Service manifestService = service;
|
|
60
|
+
if (baseUrl != null && !baseUrl.isBlank()) {
|
|
61
|
+
manifestService = new Service(service.name(), service.transport(), baseUrl, service.command(), service.health());
|
|
62
|
+
}
|
|
63
|
+
List<Entry> manifestEntries = entries.stream().map(registered -> registered.entry().copy()).toList();
|
|
64
|
+
return new Manifest("1.0", "java", framework, manifestService, manifestEntries, schemas.isEmpty() ? null : schemas);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public byte[] marshalManifest(String baseUrl) throws IOException {
|
|
68
|
+
return Json.MAPPER.writerWithDefaultPrettyPrinter().writeValueAsBytes(manifest(baseUrl));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public void writeManifest(OutputStream output, String baseUrl) throws IOException {
|
|
72
|
+
output.write(marshalManifest(baseUrl));
|
|
73
|
+
output.write('\n');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
RegisteredEntry lookup(EntryKind kind, String name) {
|
|
77
|
+
return lookup.get(key(kind, name));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
void setFramework(String framework) {
|
|
81
|
+
this.framework = framework;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
void setBaseUrl(String baseUrl) {
|
|
85
|
+
this.service.setBaseUrl(baseUrl);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
void setHealth(String health) {
|
|
89
|
+
this.service.setHealth(health);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
void addSchema(String name, Object schema) {
|
|
93
|
+
this.schemas.put(name, schema);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private void add(Entry entry, ForgeHandler handler, EntryOption... options) {
|
|
97
|
+
for (EntryOption option : options) {
|
|
98
|
+
option.apply(entry);
|
|
99
|
+
}
|
|
100
|
+
RegisteredEntry registered = new RegisteredEntry(entry, handler);
|
|
101
|
+
entries.add(registered);
|
|
102
|
+
lookup.put(key(EntryKind.valueOf(entry.kind.toUpperCase()), entry.name), registered);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private static String key(EntryKind kind, String name) {
|
|
106
|
+
return kind.value() + ":" + name;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@FunctionalInterface
|
|
110
|
+
public interface RegistryOption {
|
|
111
|
+
void apply(ForgeRegistry registry);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@FunctionalInterface
|
|
115
|
+
public interface EntryOption {
|
|
116
|
+
void apply(Entry entry);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
record RegisteredEntry(Entry entry, ForgeHandler handler) {
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
package dev.forgeos.adapter;
|
|
2
|
-
|
|
3
|
-
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
4
|
-
import com.fasterxml.jackson.databind.DeserializationFeature;
|
|
5
|
-
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
6
|
-
|
|
7
|
-
public final class Json {
|
|
8
|
-
public static final ObjectMapper MAPPER = new ObjectMapper()
|
|
9
|
-
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
|
|
10
|
-
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
|
11
|
-
|
|
12
|
-
private Json() {
|
|
13
|
-
}
|
|
14
|
-
}
|
|
1
|
+
package dev.forgeos.adapter;
|
|
2
|
+
|
|
3
|
+
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
4
|
+
import com.fasterxml.jackson.databind.DeserializationFeature;
|
|
5
|
+
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
6
|
+
|
|
7
|
+
public final class Json {
|
|
8
|
+
public static final ObjectMapper MAPPER = new ObjectMapper()
|
|
9
|
+
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
|
|
10
|
+
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
|
11
|
+
|
|
12
|
+
private Json() {
|
|
13
|
+
}
|
|
14
|
+
}
|