Commit graph

91 commits

Author SHA1 Message Date
Snider
fb498f0b88 feat(api): canonical webhook events + chat completions transport discovery
Implements gaps between RFC.md spec and code:

- Export canonical webhook event identifiers (RFC §6) as Go constants:
  WebhookEventWorkspaceCreated, WebhookEventLinkClicked, etc. Plus
  WebhookEvents() and IsKnownWebhookEvent(name) helpers for SDK consumers
  and middleware validation.

- Surface the chat completions endpoint (RFC §11.1) through TransportConfig
  (ChatCompletionsEnabled + ChatCompletionsPath) and the OpenAPI spec
  extensions (x-chat-completions-enabled, x-chat-completions-path) so
  clients can auto-discover the local OpenAI-compatible endpoint.

- Add internal test coverage for chat completions sampling defaults
  (Gemma 4 calibrated temp=1.0, top_p=0.95, top_k=64, max_tokens=2048)
  and the ThinkingExtractor channel routing (RFC §11.6).

Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-14 15:02:18 +01:00
Snider
da1839f730 feat(api): webhooks + sunset headers + WithWebSocket + cmd/api migration
- webhook.go: HMAC-SHA256 WebhookSigner matching PHP WebhookSignature —
  sign/verify, X-Webhook-Signature / X-Webhook-Timestamp headers,
  VerifyRequest middleware helper, 5-minute default tolerance,
  secret generator (RFC §6)
- sunset.go: ApiSunsetWith(date, replacement, opts...) + WithSunsetNoticeURL;
  ApiSunset now emits API-Suggested-Replacement when replacement set;
  RouteDescription.NoticeURL surfaces API-Deprecation-Notice-URL (RFC §8)
- options.go + api.go + transport.go: WithWebSocket(gin.HandlerFunc)
  alongside existing WithWSHandler(http.Handler); gin form wins when
  both supplied (RFC §2.2)
- openapi.go: apiSuggestedReplacement + apiDeprecationNoticeURL as
  reusable header components; NoticeURL on a RouteDescription flips
  operation deprecated flag and emits response header doc
- cmd/api/*.go: migrated from Cobra (cli.NewCommand, StringFlag) to
  new path-based CLI API (c.Command + core.Options.String/Int/Bool);
  replaces the 1,422-line Cobra test suite with _Good/_Bad/_Ugly
  triads on the new surface
- webhook_test.go + sunset_test.go + websocket_test.go: full coverage

Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-14 14:51:04 +01:00
Snider
fbb58486c4 feat(api): WithChatCompletions option + bug fixes in chat_completions
- options.go: new WithChatCompletions(resolver) and
  WithChatCompletionsPath(path); api.New(...) now auto-mounts at
  /v1/chat/completions when a resolver is configured (previously the
  resolver could be attached but never mounted, which would have
  panicked Gin)
- chat_completions.go: fixed missing net/http import, dropped
  ModelType during discovery, Retry-After header set after c.JSON
  silently lost, swapped OpenAI error type/code fields, swapped
  validate call site, redundant nil check, builder length read before
  nil-receiver check
- openapi.go: effective*Path helpers surface an explicit path even
  when the corresponding Enabled flag is false so CLI callers still
  get x-*-path extensions; /swagger always in authentik public paths
- chat_completions_test.go: Good/Bad/Ugly coverage for new options,
  validation, no-resolver behaviour
- openapi_test.go: fix stale assertion for CacheEnabled-gated X-Cache
- go.mod: bump dappco.re/go/core/cli to v0.5.2
- Removed local go-io / go-log stubs — replace points to outer
  modules for single source of truth
- Migrated forge.lthn.ai/core/cli imports to dappco.re/go/core/cli
  across cmd/api/*.go + docs

Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-14 14:34:51 +01:00
Snider
d90a5be936 refactor: AX compliance sweep — replace banned stdlib imports with core primitives
Replaced fmt, strings, sort, os, io, sync, encoding/json, path/filepath,
errors, log, reflect with core.Sprintf, core.E, core.Contains, core.Trim,
core.Split, core.Join, core.JoinPath, slices.Sort, c.Fs(), c.Lock(),
core.JSONMarshal, core.ReadAll and other CoreGO v0.8.0 primitives.

Framework boundary exceptions preserved where stdlib types are required
by external interfaces (Gin, net/http, CGo, Wails, bubbletea).

Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-13 09:32:00 +01:00
Snider
372326297e fix(pr#2): address CodeRabbit round 2 review findings
Go:
- cache: fix TOCTOU race in get() — re-verify entry pointer under lock before
  evicting to prevent corrupting s.currentBytes and removing a newly-set entry
- bridge: fix writeErrorResponse recorder out of sync — buffer into w.body/
  w.headers and call commit() so Status(), Header(), Size() reflect error response
- bridge: fix ValidateResponse number precision — use json.Decoder+UseNumber for
  initial envelope decode to preserve large integers (matches Validate path)
- ratelimit: fix unreachable credential branches — move X-API-Key and
  Authorization hashing before IP fallback so NAT'd clients are bucketed by key
- openapi: gate cacheSuccessHeaders on sb.CacheEnabled flag, not just method==get
- openapi: use isNilRouteGroup in prepareRouteGroups to catch typed-nil RouteGroup

PHP:
- RateLimitExceededException: remove ad-hoc CORS handling — let framework CORS
  middleware apply correct headers for all responses including errors
- SeoReportService.extractCharset: parse charset token from Content-Type value
  instead of returning the full "text/html; charset=utf-8" string
- SeoReportService: validate IP literals directly with filter_var before DNS
  lookup so ::ffff:127.0.0.1-style hosts don't bypass private-IP checks
- SeoReportService.isPrivateIp: extract isPrivateIpv4 helper; handle
  IPv4-mapped IPv6 (::ffff::/96) by checking embedded IPv4 against private
  ranges; add 0.0.0.0/8 to private range list

Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-07 09:11:05 +01:00
Snider
e54dd2e370 fix(pr#2): address CodeRabbit major/critical review findings
Go:
- codegen: pass trimmed specPath to buildArgs instead of raw g.SpecPath
- cmd/sdk: use local resolvedSpecFile to avoid mutating flag variable per-invocation
- export: write to temp file + atomic rename to prevent destination truncation on failure
- openapi: gate effectiveGraphQLPath/SwaggerPath/WSPath/SSEPath on enable flags; use effectiveSwaggerPath in effectiveAuthentikPublicPaths
- cache: reject oversized replacement before mutating LRU state for existing keys
- ratelimit: move setRateLimitHeaders before c.Next() so headers are sent; hash credential headers with SHA-256 to avoid storing raw secrets; prefer validated principal from context
- response_meta: track size separately from body buffer so Size() is accurate after body rewrites and in passthrough mode
- bridge: limit request body reads with http.MaxBytesReader (10 MiB); allow missing data key in ValidateResponse for nil/zero success responses; update recorder status in writeErrorResponse
- pkg/provider/proxy: validate target scheme and host after url.Parse to catch hostless inputs
- cmd_test: snapshot/restore global spec registry in TestAPISpecCmd_Good_RegisteredSpecGroups

PHP:
- HasApiResponses.php, config.php: add declare(strict_types=1)
- RateLimitExceededException: validate Origin against cors.allowed_origins before reflecting in CORS header
- ApiUsageService: import and use Core\Api\Models\ApiKey instead of fully-qualified Mod\ path
- SeoReportService: add SSRF protection (scheme check, private-IP rejection); add .throw() for HTTP error handling; disable automatic redirects

Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-07 08:38:41 +01:00
Virgil
8dd15251ea fix(api): omit disabled graphql playground spec metadata
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-03 04:56:48 +00:00
Virgil
a3a1c20e7a fix(api): support custom GraphQL playground paths
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-03 04:53:30 +00:00
Virgil
76acb4534b fix(api): surface GraphQL playground metadata
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-03 04:38:22 +00:00
Virgil
0022931eff fix(openapi): normalise spec builder metadata
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 14:48:26 +00:00
Virgil
2b71c78c33 fix(openapi): ignore non-positive cache ttl in spec
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 14:42:01 +00:00
Virgil
be43aa3d72 fix(openapi): deep clone route metadata
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 14:35:59 +00:00
Virgil
579b27d84e refactor(openapi): precompute authentik public paths
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 14:09:35 +00:00
Virgil
eb771875e2 fix(openapi): document authentik public paths as public
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 14:03:16 +00:00
Virgil
a6693e1656 feat(api): surface effective Authentik public paths in specs
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 13:51:54 +00:00
Virgil
f234fcba5f feat(api): surface authentik metadata in specs
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 13:25:23 +00:00
Virgil
ec268c8100 feat(api): default enabled transport paths in specs
Treat enabled built-in transports as having their default paths when callers omit an explicit override. This keeps manual SpecBuilder usage aligned with the engine defaults and prevents Swagger, GraphQL, WebSocket, and SSE metadata from disappearing from generated documents.\n\nCo-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 13:07:05 +00:00
Virgil
f919e8a3be feat(api): expose cache and i18n OpenAPI metadata
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 12:29:40 +00:00
Virgil
71c179018d refactor(api): snapshot route metadata during spec build
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 09:08:16 +00:00
Virgil
4fc93612e4 feat(api): make spec builder nil-safe 2026-04-02 09:01:04 +00:00
Virgil
57ff0d2a48 feat(api): expose swagger and graphql spec flags 2026-04-02 08:57:41 +00:00
Virgil
d40ff2c294 fix(api): remove global openapi bearer security
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 08:54:24 +00:00
Virgil
192f8331f2 feat(api): expose websocket and sse transport flags
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 08:48:28 +00:00
Virgil
d225fd3178 feat(api): add openapi info summary support
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 08:16:56 +00:00
Virgil
ec945970ee docs(api): add AX usage examples
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 07:51:21 +00:00
Virgil
b0549dc14e fix(api): deep-clone swagger security schemes
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 07:19:32 +00:00
Virgil
69dd16cba6 feat(api): expose reusable OpenAPI response components
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 07:10:55 +00:00
Virgil
8e1a424fc8 feat(api): merge custom OpenAPI security schemes
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 07:01:41 +00:00
Virgil
b99e445436 feat(openapi): document debug endpoint rate-limit headers
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 06:52:40 +00:00
Virgil
3b75dc1701 fix(openapi): preserve example-only response schemas
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 06:33:24 +00:00
Virgil
9b24a46fd5 feat(openapi): export runtime transport metadata
Expose GraphQL, WebSocket, SSE, and debug endpoint metadata alongside the existing Swagger UI path in generated OpenAPI documents.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 06:08:44 +00:00
Virgil
a469a78b2a feat(openapi): document GraphQL GET queries
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 03:25:25 +00:00
Virgil
d9ccd7c49a feat(openapi): export swagger ui path metadata
Preserve the Swagger UI mount path in generated OpenAPI output and expose it through the spec and sdk CLI builders.\n\nCo-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 03:16:08 +00:00
Virgil
c3143a5029 feat(openapi): declare json schema dialect
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 03:09:28 +00:00
Virgil
e8d54797bf feat(openapi): include graphql tag for playground default path
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 03:04:55 +00:00
Virgil
85d6f6dd6e feat(openapi): default graphql path for playground specs
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 03:00:51 +00:00
Virgil
f53617c507 feat(openapi): document sunsetted operations as gone
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 02:56:13 +00:00
Virgil
006a065ea0 feat(openapi): document WebSocket endpoint
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 02:33:31 +00:00
Virgil
273bc3d70a feat(openapi): document GraphQL playground endpoint
Adds GraphQL Playground coverage to the generated OpenAPI spec when the GraphQL playground option is enabled, and wires the engine metadata through so runtime docs match the mounted route.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 02:29:20 +00:00
Virgil
41615bbe47 feat(api): document debug endpoints in OpenAPI spec
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 02:24:27 +00:00
Virgil
86c2150a21 feat(openapi): document SSE endpoint
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 01:44:49 +00:00
Virgil
02082db8f4 fix(openapi): document graphql cache headers
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 01:40:05 +00:00
Virgil
50b6a9197f refactor(openapi): remove unused route-group prep state
Simplifies route-group preparation by dropping dead metadata that was no longer used by the OpenAPI builder.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 01:34:14 +00:00
Virgil
08a2d93776 fix(openapi): fall back to Describe for nil iterators
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 01:27:40 +00:00
Virgil
e23d8e9780 feat(openapi): sort generated tags deterministically
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 00:47:51 +00:00
Virgil
812400f303 feat(openapi): keep empty describable group tags
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 00:39:04 +00:00
Virgil
0bb07f43f0 feat(openapi): hide undocumented routes
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 00:35:17 +00:00
Virgil
68bf8dcaf8 feat(openapi): document GraphQL endpoint
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 00:17:26 +00:00
Virgil
47e8c8a795 feat(openapi): document route headers on all responses
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-01 23:21:56 +00:00
Virgil
eb7e1e51cb feat(openapi): reuse deprecation header components 2026-04-01 23:12:40 +00:00