package main // HookInfo describes a plugin hook type HookInfo struct { Name string `json:"name"` Label string `json:"label"` Description string `json:"description"` Pattern string `json:"pattern"` // event, validation, transform TestData map[string]any `json:"test_data"` } // Available hooks var hooks = []HookInfo{ { Name: "post.published", Label: "Post Published", Description: "Triggered when a post is published", Pattern: "event", TestData: map[string]any{ "post": map[string]any{ "slug": "hello-world", "title": "Hello World", "url": "/hello-world", "excerpt": "This is a test post for plugin development.", "publishedAt": "2024-01-15T10:30:00Z", "tags": []string{"test", "development"}, "readingTime": 3, }, "author": map[string]any{ "name": "Test Author", "email": "author@example.com", }, "blog": map[string]any{ "name": "Test Blog", "url": "https://test.writekit.dev", }, }, }, { Name: "post.updated", Label: "Post Updated", Description: "Triggered when a post is updated", Pattern: "event", TestData: map[string]any{ "post": map[string]any{ "slug": "hello-world", "title": "Hello World (Updated)", "url": "/hello-world", "excerpt": "This is a test post that was updated.", "publishedAt": "2024-01-15T10:30:00Z", "updatedAt": "2024-01-16T14:00:00Z", "tags": []string{"test", "development", "updated"}, }, "author": map[string]any{ "name": "Test Author", "email": "author@example.com", }, "changes": map[string]any{ "title": map[string]any{"old": "Hello World", "new": "Hello World (Updated)"}, "content": true, "tags": map[string]any{"added": []string{"updated"}, "removed": []string{}}, }, }, }, { Name: "comment.validate", Label: "Comment Validate", Description: "Validate comments before creation", Pattern: "validation", TestData: map[string]any{ "content": "This is a test comment for moderation.", "authorName": "Test User", "authorEmail": "user@example.com", "postSlug": "hello-world", }, }, { Name: "comment.created", Label: "Comment Created", Description: "Triggered when a comment is created", Pattern: "event", TestData: map[string]any{ "comment": map[string]any{ "id": "test-comment-123", "content": "Great post! Thanks for sharing.", "authorName": "Test User", "authorEmail": "user@example.com", "postSlug": "hello-world", "createdAt": "2024-01-15T12:00:00Z", }, "post": map[string]any{ "slug": "hello-world", "title": "Hello World", "url": "/hello-world", }, }, }, { Name: "member.subscribed", Label: "Member Subscribed", Description: "Triggered when a member subscribes", Pattern: "event", TestData: map[string]any{ "member": map[string]any{ "email": "subscriber@example.com", "name": "New Subscriber", "subscribedAt": "2024-01-15T09:00:00Z", }, "tier": map[string]any{ "name": "Free", "price": 0, }, }, }, { Name: "content.render", Label: "Content Render", Description: "Transform rendered HTML", Pattern: "transform", TestData: map[string]any{ "html": "

Hello World

This is test content.

const x = 1;
", "post": map[string]any{ "slug": "hello-world", "title": "Hello World", "tags": []string{"test"}, }, }, }, { Name: "asset.uploaded", Label: "Asset Uploaded", Description: "Triggered when an asset is uploaded", Pattern: "event", TestData: map[string]any{ "id": "asset-123", "url": "https://cdn.example.com/image.webp", "contentType": "image/webp", "size": 102400, "width": 1920, "height": 1080, }, }, { Name: "analytics.sync", Label: "Analytics Sync", Description: "Sync analytics data periodically", Pattern: "event", TestData: map[string]any{ "period": map[string]any{ "start": "2024-01-08T00:00:00Z", "end": "2024-01-15T00:00:00Z", }, "pageviews": 1250, "visitors": 890, "topPages": []map[string]any{ {"path": "/hello-world", "views": 450}, {"path": "/about", "views": 230}, }, }, }, } // Templates organized by hook and language var templates = map[string]map[string]string{ "post.published": { "typescript": `export const onPostPublished = (event: PostPublishedEvent): void => { Runner.log("Post published: " + event.post.title); // Example: Send Slack notification Runner.httpRequest({ url: Runner.secrets.SLACK_WEBHOOK, method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ text: "New post: " + event.post.title + "\n" + event.post.url, }), }); }; `, "go": `package main func OnPostPublished(event PostPublishedEvent) error { Runner.Log("Post published: " + event.Post.Title) // Example: Send Slack notification Runner.HttpRequest(Runner.Secrets.SlackWebhook, "POST", []byte("{\"text\":\"New post published\"}")) return nil } func main() {} `, }, "post.updated": { "typescript": `export const onPostUpdated = (event: PostUpdatedEvent): void => { Runner.log("Post updated: " + event.post.title); // Example: Sync to external CMS if (event.changes.content) { Runner.httpRequest({ url: "https://api.example.com/sync", method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ slug: event.post.slug, title: event.post.title, url: event.post.url, }), }); } }; `, "go": `package main func OnPostUpdated(event PostUpdatedEvent) error { Runner.Log("Post updated: " + event.Post.Title) return nil } func main() {} `, }, "comment.validate": { "typescript": `export const validateComment = (input: CommentInput): ValidationResult => { // Example: Simple spam check const spamWords = ["buy now", "click here", "free money"]; const content = input.content.toLowerCase(); for (const word of spamWords) { if (content.includes(word)) { return { allowed: false, reason: "Comment flagged as spam" }; } } // Example: Check minimum length if (input.content.length < 10) { return { allowed: false, reason: "Comment too short" }; } return { allowed: true }; }; `, "go": `package main import "strings" func ValidateComment(input CommentInput) (ValidationResult, error) { // Example: Simple spam check spamWords := []string{"buy now", "click here", "free money"} content := strings.ToLower(input.Content) for _, word := range spamWords { if strings.Contains(content, word) { return ValidationResult{Allowed: false, Reason: "Spam detected"}, nil } } return ValidationResult{Allowed: true}, nil } func main() {} `, }, "comment.created": { "typescript": `export const onCommentCreated = (event: CommentCreatedEvent): void => { Runner.log("New comment on: " + event.post.title); // Example: Send notification Runner.httpRequest({ url: Runner.secrets.SLACK_WEBHOOK, method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ text: "New comment by " + event.comment.authorName + " on \"" + event.post.title + "\"", }), }); }; `, "go": `package main func OnCommentCreated(event CommentCreatedEvent) error { Runner.Log("New comment on: " + event.Post.Title) return nil } func main() {} `, }, "member.subscribed": { "typescript": `export const onMemberSubscribed = (event: MemberSubscribedEvent): void => { Runner.log("New subscriber: " + event.member.email); // Example: Add to email list Runner.httpRequest({ url: "https://api.buttondown.email/v1/subscribers", method: "POST", headers: { "Content-Type": "application/json", "Authorization": "Token " + Runner.secrets.BUTTONDOWN_API_KEY, }, body: JSON.stringify({ email: event.member.email, notes: "Subscribed from blog", }), }); }; `, "go": `package main func OnMemberSubscribed(event MemberSubscribedEvent) error { Runner.Log("New subscriber: " + event.Member.Email) return nil } func main() {} `, }, "content.render": { "typescript": `export const renderContent = (input: ContentRenderInput): ContentRenderOutput => { let html = input.html; // Example: Add copy button to code blocks html = html.replace( /
 {
  Runner.log("Asset uploaded: " + event.url);

  // Example: Backup to external storage
  if (event.contentType.startsWith("image/")) {
    Runner.httpRequest({
      url: "https://api.cloudinary.com/v1_1/demo/image/upload",
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        file: event.url,
        folder: "blog-backups",
      }),
    });
  }
};
`,
		"go": `package main

func OnAssetUploaded(event AssetUploadedEvent) error {
	Runner.Log("Asset uploaded: " + event.Url)
	return nil
}

func main() {}
`,
	},
	"analytics.sync": {
		"typescript": `export const onAnalyticsSync = (event: AnalyticsSyncEvent): void => {
  Runner.log("Analytics sync: " + event.pageviews + " pageviews");

  // Example: Push to external analytics
  Runner.httpRequest({
    url: "https://api.example.com/analytics",
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + Runner.secrets.ANALYTICS_KEY,
    },
    body: JSON.stringify({
      period: event.period,
      pageviews: event.pageviews,
      visitors: event.visitors,
      topPages: event.topPages,
    }),
  });
};
`,
		"go": `package main

func OnAnalyticsSync(event AnalyticsSyncEvent) error {
	Runner.Log("Analytics sync completed")
	return nil
}

func main() {}
`,
	},
}

// GetTemplate returns the template for a specific hook and language
func GetTemplate(hook, language string) string {
	if hookTemplates, ok := templates[hook]; ok {
		if template, ok := hookTemplates[language]; ok {
			return template
		}
	}
	// Default fallback
	return templates["post.published"]["typescript"]
}