package main import ( "encoding/json" "net/http" ) // SDKFunction describes a function in the SDK type SDKFunction struct { Name string `json:"name"` Signature string `json:"signature"` InsertText string `json:"insertText"` Documentation string `json:"documentation"` } // SDKNamespace describes a namespace with functions type SDKNamespace struct { Functions []SDKFunction `json:"functions,omitempty"` } // SDKField describes a field in an event type type SDKField struct { Name string `json:"name"` Type string `json:"type"` Doc string `json:"doc,omitempty"` } // SDKEventType describes an event type with nested fields type SDKEventType struct { Fields []SDKField `json:"fields"` } // SDKHookType maps hook names to their event types type SDKHookTypes map[string]SDKEventType // SDKSchema is the complete SDK schema for a language type SDKSchema struct { Runner SDKNamespace `json:"Runner"` Events SDKHookTypes `json:"events"` } // Event type definitions per hook (language-agnostic field names, language-specific in schema) var hookEventFields = map[string][]SDKField{ "post.published": { {Name: "post", Type: "Post", Doc: "The published post"}, {Name: "author", Type: "Author", Doc: "Post author"}, {Name: "blog", Type: "Blog", Doc: "Blog info"}, }, "post.updated": { {Name: "post", Type: "Post", Doc: "The updated post"}, {Name: "author", Type: "Author", Doc: "Post author"}, {Name: "changes", Type: "Changes", Doc: "What changed"}, }, "comment.validate": { {Name: "content", Type: "string", Doc: "Comment content"}, {Name: "authorName", Type: "string", Doc: "Author name"}, {Name: "authorEmail", Type: "string", Doc: "Author email"}, {Name: "postSlug", Type: "string", Doc: "Post slug"}, }, "comment.created": { {Name: "comment", Type: "Comment", Doc: "The created comment"}, {Name: "post", Type: "Post", Doc: "The post"}, }, "member.subscribed": { {Name: "member", Type: "Member", Doc: "The subscriber"}, {Name: "tier", Type: "Tier", Doc: "Subscription tier"}, }, "content.render": { {Name: "html", Type: "string", Doc: "HTML content to transform"}, {Name: "post", Type: "Post", Doc: "Post metadata"}, }, "asset.uploaded": { {Name: "id", Type: "string", Doc: "Asset ID"}, {Name: "url", Type: "string", Doc: "Asset URL"}, {Name: "contentType", Type: "string", Doc: "MIME type"}, {Name: "size", Type: "int", Doc: "Size in bytes"}, {Name: "width", Type: "int", Doc: "Image width (if image)"}, {Name: "height", Type: "int", Doc: "Image height (if image)"}, }, "analytics.sync": { {Name: "period", Type: "Period", Doc: "Time period"}, {Name: "pageviews", Type: "int", Doc: "Total pageviews"}, {Name: "visitors", Type: "int", Doc: "Unique visitors"}, {Name: "topPages", Type: "[]PageView", Doc: "Top pages"}, }, } // Nested type definitions var nestedTypes = map[string][]SDKField{ "Post": { {Name: "slug", Type: "string"}, {Name: "title", Type: "string"}, {Name: "url", Type: "string"}, {Name: "excerpt", Type: "string"}, {Name: "publishedAt", Type: "string"}, {Name: "updatedAt", Type: "string"}, {Name: "tags", Type: "[]string"}, {Name: "readingTime", Type: "int"}, }, "Author": { {Name: "name", Type: "string"}, {Name: "email", Type: "string"}, {Name: "avatar", Type: "string"}, }, "Blog": { {Name: "name", Type: "string"}, {Name: "url", Type: "string"}, }, "Comment": { {Name: "id", Type: "string"}, {Name: "content", Type: "string"}, {Name: "authorName", Type: "string"}, {Name: "authorEmail", Type: "string"}, {Name: "postSlug", Type: "string"}, {Name: "parentId", Type: "string"}, {Name: "createdAt", Type: "string"}, }, "Member": { {Name: "email", Type: "string"}, {Name: "name", Type: "string"}, {Name: "subscribedAt", Type: "string"}, }, "Tier": { {Name: "name", Type: "string"}, {Name: "price", Type: "int"}, }, "Changes": { {Name: "title", Type: "TitleChange"}, {Name: "content", Type: "bool"}, {Name: "tags", Type: "TagChanges"}, }, "TitleChange": { {Name: "old", Type: "string"}, {Name: "new", Type: "string"}, }, "TagChanges": { {Name: "added", Type: "[]string"}, {Name: "removed", Type: "[]string"}, }, "Period": { {Name: "start", Type: "string"}, {Name: "end", Type: "string"}, }, "PageView": { {Name: "path", Type: "string"}, {Name: "views", Type: "int"}, }, } func buildEventTypes(lang string) SDKHookTypes { events := make(SDKHookTypes) for hook, fields := range hookEventFields { // Convert field names for Go (PascalCase) if lang == "go" { converted := make([]SDKField, len(fields)) for i, f := range fields { converted[i] = SDKField{ Name: toPascalCase(f.Name), Type: f.Type, Doc: f.Doc, } } events[hook] = SDKEventType{Fields: converted} } else { events[hook] = SDKEventType{Fields: fields} } } return events } func toPascalCase(s string) string { if len(s) == 0 { return s } // Simple: just capitalize first letter return string(s[0]-32) + s[1:] } // SDK schemas for each language var sdkSchemas = map[string]SDKSchema{ "typescript": { Runner: SDKNamespace{ Functions: []SDKFunction{ { Name: "log", Signature: "log(message: string): void", InsertText: "log(${1:message})", Documentation: "Log a message to the plugin console", }, { Name: "httpRequest", Signature: "httpRequest(options: HttpRequestOptions): HttpResponse", InsertText: "httpRequest({\n url: ${1:url},\n method: \"${2:POST}\",\n headers: { \"Content-Type\": \"application/json\" },\n body: ${3:body}\n})", Documentation: "Make an HTTP request to an external service", }, }, }, Events: buildEventTypes("typescript"), }, "go": { Runner: SDKNamespace{ Functions: []SDKFunction{ { Name: "Log", Signature: "Log(message string)", InsertText: "Log(${1:message})", Documentation: "Log a message to the plugin console", }, { Name: "HttpRequest", Signature: "HttpRequest(url string, method string, body []byte) (*Response, error)", InsertText: "HttpRequest(${1:url}, \"${2:POST}\", []byte(${3:body}))", Documentation: "Make an HTTP request to an external service", }, }, }, Events: buildEventTypes("go"), }, } // Also expose nested types type FullSDKResponse struct { Runner SDKNamespace `json:"Runner"` Events SDKHookTypes `json:"events"` NestedTypes map[string][]SDKField `json:"nestedTypes"` } func sdkHandler(w http.ResponseWriter, r *http.Request) { language := r.URL.Query().Get("language") w.Header().Set("Content-Type", "application/json") if language != "" { if schema, ok := sdkSchemas[language]; ok { // Convert nested types for the language convertedNested := make(map[string][]SDKField) for typeName, fields := range nestedTypes { if language == "go" { converted := make([]SDKField, len(fields)) for i, f := range fields { converted[i] = SDKField{ Name: toPascalCase(f.Name), Type: f.Type, Doc: f.Doc, } } convertedNested[typeName] = converted } else { convertedNested[typeName] = fields } } response := FullSDKResponse{ Runner: schema.Runner, Events: schema.Events, NestedTypes: convertedNested, } json.NewEncoder(w).Encode(response) return } http.Error(w, "Unknown language", http.StatusBadRequest) return } // Return all schemas (without nested types for brevity) json.NewEncoder(w).Encode(sdkSchemas) }