Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
306 changes: 246 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,74 +1,260 @@
# React + TypeScript + Vite
# InsForge Go SDK

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Official Go SDK for [InsForge](https://insforge.app) – Backend as a Service.

Currently, two official plugins are available:
## Installation

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
```bash
go get github.com/InsForge/insforge-go
```

## React Compiler
Requires Go 1.21+.

The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
## Quick Start

## Expanding the ESLint configuration
```go
package main

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
import (
"context"
"fmt"
"log"

```js
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
"github.com/InsForge/insforge-go/insforge"
)

// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,
func main() {
client := insforge.NewClient(insforge.Config{
BaseURL: "https://your-app.region.insforge.app",
AnonKey: "your-anon-key",
})

// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
]);
ctx := context.Background()

// Sign in
authResult := client.Auth.SignInWithPassword(ctx, "user@example.com", "password123")
if authResult.Error != nil {
log.Fatal(authResult.Error)
}
fmt.Println("Logged in:", authResult.Data.User.Email)

// Query database
dbResult := client.Database.From("posts").
Select("id, title, created_at").
Limit(10).
Execute(ctx)
if dbResult.Error != nil {
log.Fatal(dbResult.Error)
}
fmt.Println("Posts:", dbResult.Data)

// Upload file
data := []byte("hello world")
storageResult := client.Storage.From("files").
Upload(ctx, "hello.txt", data, "text/plain")
if storageResult.Error != nil {
log.Fatal(storageResult.Error)
}

// AI chat
aiResult := client.AI.Chat.Completions.Create(ctx, insforge.ChatCompletionRequest{
Model: "openai/gpt-4o",
Messages: []insforge.ChatMessage{
{Role: "user", Content: "Hello!"},
},
})
if aiResult.Error != nil {
log.Fatal(aiResult.Error)
}
fmt.Println(aiResult.Data.Choices[0].Message.Content)
}
```

## Modules

### `client.Auth`

| Method | Description |
|--------|-------------|
| `SignUp(ctx, email, password, opts...)` | Register a new user |
| `SignInWithPassword(ctx, email, password)` | Login with email/password |
| `SignOut(ctx)` | Logout |
| `SignInWithOAuth(ctx, provider, redirectTo)` | OAuth sign-in |
| `ExchangeOAuthCode(ctx, code, codeVerifier)` | Exchange OAuth code |
| `GetCurrentUser(ctx)` | Get the logged-in user |
| `RefreshSession(ctx, refreshToken)` | Refresh the session |
| `GetProfile(ctx, userID)` | Get user profile |
| `SetProfile(ctx, profile)` | Update current user's profile |
| `ResendVerificationEmail(ctx, email)` | Resend verification email |
| `VerifyEmail(ctx, email, otp)` | Verify email with OTP |
| `SendResetPasswordEmail(ctx, email)` | Send password reset email |
| `ResetPassword(ctx, newPassword, otp)` | Reset password |
| `GetPublicAuthConfig(ctx)` | Get public auth configuration |

### `client.Database`

```go
// SELECT
result := client.Database.From("users").
Select("id, name").
Eq("active", true).
Order("created_at", false). // false = DESC
Limit(20).
Execute(ctx)

// INSERT
result := client.Database.From("posts").
Insert(ctx, []map[string]interface{}{
{"title": "Hello", "body": "World"},
})

// UPDATE
result := client.Database.From("posts").
Eq("id", 5).
Update(ctx, map[string]interface{}{"title": "Updated"})

// DELETE
result := client.Database.From("posts").
Eq("id", 5).
Delete(ctx)

// RPC
result := client.Database.RPC(ctx, "get_stats", map[string]interface{}{"user_id": "abc"})

// Raw SQL (admin)
result := client.Database.Query(ctx, "SELECT * FROM users WHERE email = $1", "user@example.com")
```

### `client.Storage`

```go
bucket := client.Storage.From("my-bucket")

// Upload bytes
result := bucket.Upload(ctx, "path/file.png", fileBytes, "image/png")

// Upload from io.Reader
result := bucket.UploadReader(ctx, "path/file.png", file, "image/png")

// Download
result := bucket.Download(ctx, "path/file.png")
fileBytes := result.Data

// List
result := bucket.List(ctx, &insforge.ListOptions{Prefix: "path/", Limit: 50})

// Delete
result := bucket.Remove(ctx, "path/file.png")

// Get public URL
url := bucket.GetPublicURL("path/file.png")
```

You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:

```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x';
import reactDom from 'eslint-plugin-react-dom';

export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
### `client.AI`

```go
// Non-streaming completion
result := client.AI.Chat.Completions.Create(ctx, insforge.ChatCompletionRequest{
Model: "openai/gpt-4o",
Messages: []insforge.ChatMessage{
{Role: "system", Content: "You are a helpful assistant."},
{Role: "user", Content: "What is 2+2?"},
},
},
]);
})
fmt.Println(result.Data.Choices[0].Message.Content)

// Streaming
temp := 0.7
chunks, errs := client.AI.Chat.Completions.CreateStream(ctx, insforge.ChatCompletionRequest{
Model: "openai/gpt-4o",
Messages: []insforge.ChatMessage{{Role: "user", Content: "Tell me a story"}},
Temperature: &temp,
})
for chunk := range chunks {
if len(chunk.Choices) > 0 {
fmt.Print(chunk.Choices[0].Delta.Content)
}
}
if err := <-errs; err != nil {
log.Fatal(err)
}

// Embeddings
result := client.AI.Embeddings.Create(ctx, insforge.EmbeddingsRequest{
Model: "openai/text-embedding-3-small",
Input: "Hello world",
})

// Image generation
n := 1
result := client.AI.Images.Generate(ctx, insforge.ImageGenerationRequest{
Model: "openai/dall-e-3",
Prompt: "A sunset over the ocean",
Size: "1024x1024",
N: &n,
})
```

### `client.Realtime`

```go
// Connect
err := client.Realtime.Connect(ctx)

// Subscribe
result, err := client.Realtime.Subscribe(ctx, "chat:room-1")

// Listen for events
client.Realtime.On("chat:room-1", func(data interface{}) {
fmt.Println("Received:", data)
})

// Publish
err = client.Realtime.Publish(ctx, "chat:room-1", "message", map[string]interface{}{
"text": "Hello!",
})

// Unsubscribe
err = client.Realtime.Unsubscribe("chat:room-1")

// Disconnect
err = client.Realtime.Disconnect()
```
# insforge-go

### `client.Functions`

```go
result := client.Functions.Invoke(ctx, "my-function", &insforge.InvokeOptions{
Body: map[string]interface{}{"key": "value"},
Method: "POST",
})
```

### `client.Emails`

```go
result := client.Emails.Send(ctx, insforge.SendEmailRequest{
To: "recipient@example.com",
Subject: "Hello",
HTML: "<p>Hello from InsForge!</p>",
})
```

## Error Handling

All SDK methods return a `Result[T]` value containing `Data T` and `Error *InsForgeError`:

```go
result := client.Auth.SignUp(ctx, "a@b.com", "pass")
if result.Error != nil {
fmt.Println(result.Error.Message) // Human-readable message
fmt.Println(result.Error.StatusCode) // HTTP status code
fmt.Println(result.Error.Code) // Error code string
return
}
fmt.Println(result.Data)
```

## License

Apache-2.0
7 changes: 7 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module github.com/InsForge/insforge-go

go 1.21

require (
github.com/gorilla/websocket v1.5.1
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
Loading