diff --git a/README.ja.md b/README.ja.md index 48db4c9..f923346 100644 --- a/README.ja.md +++ b/README.ja.md @@ -19,7 +19,7 @@ auto-registration、token lifecycle、request signature verification を担当 ## このアプリで確認できること -- `github.com/channel-io/app-sdk/go` `v0.14.0` +- `go.mod` に固定された `github.com/channel-io/app-sdk/go` version - SDK builder で登録する `command` Extension - Typed app Function と生成される JSON Schema - SDK-managed app/channel token cache と refresh @@ -39,10 +39,9 @@ silent close せず error state を表示します。 - **WAM**: React UI は `/resource/wam/tutorial` で配信します。`useCallFunction` は app server、`useNativeFunction` は現在の manager として Channel を呼びます。 - **認証**: SDK server が inbound signature を検証し、`native.TokenManager` が bot path の channel token を cache します。Server は許可済み group-chat target に短期 signature を付けて WAM に渡し、manager authorization は Channel host が管理します。 -Go SDK は token lifecycle を管理しますが、まだ `writeGroupMessage` typed proxy wrapper を -提供していません。`internal/tutorial/native_message.go` はこの native Function だけを分離した -transport adapter です。その他の token repository、command registrar、Function router は SDK -が担当します。 +Bot path は `native.TokenManager` で channel token を取得し、 +`native.ProxyAPI.WriteGroupMessage` を呼びます。App は Native Function HTTP transport を直接 +実装しません。 ## SDK contract @@ -142,12 +141,12 @@ cmd/main.go SDK server と Extension auto-registration cmd/function_endpoint.go bare Function Endpoint compatibility route internal/tutorial/app.go command metadata と typed app Function internal/tutorial/contracts.go public WAM contract の Go type と name -internal/tutorial/native_message.go 1 つの native transport adapter +internal/tutorial/native_message.go SDK token manager と typed ProxyAPI call contracts/ language-neutral WAM wire schema wam/src/contracts.ts TypeScript view と runtime validation wam/src/pages/Send/Send.tsx app/native call 用 WAM SDK hook ``` 現在の contract は SDK guide と reference で確認し、完全な Go server/WAM implementation は -この repository で確認してください。SDK Quickstart もこの tutorial を参照し、Go native -transport gap は feature-parity 文書で明記します。 +この repository で確認してください。SDK Quickstart もこの tutorial を runnable Go example +として参照します。 diff --git a/README.ko.md b/README.ko.md index 14c69aa..3d50a6a 100644 --- a/README.ko.md +++ b/README.ko.md @@ -19,7 +19,7 @@ auto-registration, token lifecycle, request signature 검증을 담당합니다. ## 이 앱에서 확인할 수 있는 것 -- `github.com/channel-io/app-sdk/go` `v0.14.0` +- `go.mod`에 고정된 `github.com/channel-io/app-sdk/go` 버전 - SDK builder로 등록하는 `command` Extension - Typed app Function과 생성되는 JSON Schema - SDK가 관리하는 app/channel token cache와 refresh @@ -39,9 +39,9 @@ manager 권한으로 team-chat message를 보냅니다. 지원하지 않는 chat - **WAM**: React UI는 `/resource/wam/tutorial`에서 제공됩니다. `useCallFunction`은 app server를, `useNativeFunction`은 현재 manager 주체로 Channel을 호출합니다. - **인증**: SDK server가 inbound signature를 검증하고 `native.TokenManager`가 bot 경로의 channel token을 cache합니다. Server는 허용된 group-chat target에 짧은 signature를 붙여 WAM에 전달하며 manager authorization은 Channel host가 관리합니다. -Go SDK는 token lifecycle을 관리하지만 아직 `writeGroupMessage` typed proxy wrapper를 제공하지 -않습니다. `internal/tutorial/native_message.go`는 이 native Function 하나만 격리한 transport -adapter입니다. 나머지 token repository, command registrar, Function router는 SDK가 담당합니다. +Bot 경로는 `native.TokenManager`로 channel token을 얻고 +`native.ProxyAPI.WriteGroupMessage`를 호출합니다. 앱이 Native Function HTTP transport를 직접 +구현하지 않습니다. ## SDK 계약 @@ -140,12 +140,11 @@ cmd/main.go SDK server와 Extension auto-registration cmd/function_endpoint.go bare Function Endpoint compatibility route internal/tutorial/app.go command metadata와 typed app Function internal/tutorial/contracts.go public WAM contract의 Go type과 name -internal/tutorial/native_message.go 하나의 native transport adapter +internal/tutorial/native_message.go SDK token manager와 typed ProxyAPI 호출 contracts/ 언어 중립 WAM wire schema wam/src/contracts.ts TypeScript view와 runtime validation wam/src/pages/Send/Send.tsx app/native call용 WAM SDK hook ``` 현재 계약은 SDK guide와 reference에서 확인하고, 완성된 Go server/WAM 구현은 이 저장소에서 -확인하세요. SDK Quickstart도 이 튜토리얼을 연결하며 Go native transport gap은 기능 동등성 -문서에서 명시합니다. +확인하세요. SDK Quickstart도 이 튜토리얼을 실행 가능한 Go 예제로 연결합니다. diff --git a/README.md b/README.md index 9ebdca6..d472dbb 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ design guidance: ## What this app demonstrates -- `github.com/channel-io/app-sdk/go` `v0.14.0` +- the `github.com/channel-io/app-sdk/go` version pinned in `go.mod` - a `command` extension registered through the SDK builder - typed app functions and generated JSON schemas - SDK-managed app/channel token caching and refresh @@ -47,10 +47,8 @@ Concepts in this repository map to concrete code as follows: - **WAM**: the React UI is served at `/resource/wam/tutorial`; `useCallFunction` calls the app server and `useNativeFunction` acts as the current manager. - **Authentication**: the SDK server verifies inbound signatures, `native.TokenManager` caches the channel token used by the bot path, the server signs the allowed group-chat target before giving it to the WAM, and the Channel host owns manager authorization. -The Go SDK currently owns the token lifecycle but does not yet expose a typed proxy wrapper for -`writeGroupMessage`. `internal/tutorial/native_message.go` is therefore a deliberately small -transport adapter for that one native function; the rest of the old hand-written AppStore client, -token repository, command registrar, and function router has been removed. +The bot path obtains a channel token through `native.TokenManager` and calls +`native.ProxyAPI.WriteGroupMessage`; the app does not implement Native Function HTTP transport. ## SDK contract alignment @@ -151,12 +149,11 @@ cmd/main.go SDK server and extension auto-registration cmd/function_endpoint.go bare Function Endpoint compatibility route internal/tutorial/app.go command metadata and typed app functions internal/tutorial/contracts.go Go types and names for the public WAM contract -internal/tutorial/native_message.go one native transport adapter +internal/tutorial/native_message.go SDK token manager and typed ProxyAPI call contracts/ language-neutral WAM wire schema wam/src/contracts.ts TypeScript view and runtime validation of that schema wam/src/pages/Send/Send.tsx WAM SDK hooks for app/native calls ``` Use the SDK guides and references for the current contract, and use this repository for its complete -Go server-and-WAM implementation. The SDK quickstart links here and calls out the one native -transport gap explicitly. +Go server-and-WAM implementation. The SDK Quickstart links here as the runnable Go example. diff --git a/cmd/main.go b/cmd/main.go index 0c37895..970bbaa 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -31,7 +31,7 @@ func main() { AppID: cfg.AppID, AppSecret: cfg.AppSecret, BotName: cfg.BotName, - }, tutorial.NewNativeMessageSender(tokenManager, cfg.AppStoreURL)) + }, tutorial.NewNativeMessageSender(tokenManager, nativeClient)) if err != nil { log.Fatal(err) } diff --git a/go.mod b/go.mod index 6797df2..bb9bba6 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/channel-io/app-tutorial go 1.25.0 require ( - github.com/channel-io/app-sdk/go v0.14.0 + github.com/channel-io/app-sdk/go v0.14.1-0.20260723153640-6dfd90dad8a1 github.com/gin-gonic/gin v1.10.1 google.golang.org/protobuf v1.36.11 ) diff --git a/go.sum b/go.sum index 53640a1..4d72c5e 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/channel-io/app-sdk/go v0.14.0 h1:lmtHnhPXN3C4Pix+GGUk7v6tmpc1ThMz+kgEeIsVs9A= -github.com/channel-io/app-sdk/go v0.14.0/go.mod h1:A/ATvjAeGsrttLIW6hn3ot63MjZ/kUZDw1FCGdPVNNk= +github.com/channel-io/app-sdk/go v0.14.1-0.20260723153640-6dfd90dad8a1 h1:9UqsO45sjkfeWbHhsUDOXom1fQ9qU6fqfGwFxPOMB5s= +github.com/channel-io/app-sdk/go v0.14.1-0.20260723153640-6dfd90dad8a1/go.mod h1:A/ATvjAeGsrttLIW6hn3ot63MjZ/kUZDw1FCGdPVNNk= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= diff --git a/internal/tutorial/native_message.go b/internal/tutorial/native_message.go index 14beba3..39189f7 100644 --- a/internal/tutorial/native_message.go +++ b/internal/tutorial/native_message.go @@ -1,29 +1,19 @@ package tutorial import ( - "bytes" "context" - "encoding/json" "fmt" - "net/http" - "strings" - "time" "github.com/channel-io/app-sdk/go/native" ) type NativeMessageSender struct { - tokens *native.TokenManager - appStoreURL string - httpClient *http.Client + tokens *native.TokenManager + client *native.Client } -func NewNativeMessageSender(tokens *native.TokenManager, appStoreURL string) *NativeMessageSender { - return &NativeMessageSender{ - tokens: tokens, - appStoreURL: strings.TrimRight(appStoreURL, "/"), - httpClient: &http.Client{Timeout: 15 * time.Second}, - } +func NewNativeMessageSender(tokens *native.TokenManager, client *native.Client) *NativeMessageSender { + return &NativeMessageSender{tokens: tokens, client: client} } func (s *NativeMessageSender) SendGroupMessage( @@ -38,54 +28,21 @@ func (s *NativeMessageSender) SendGroupMessage( return fmt.Errorf("get channel token: %w", err) } - payload := map[string]any{ - "method": "writeGroupMessage", - "params": map[string]any{ - "channelId": channelID, - "groupId": groupID, - "rootMessageId": input.RootMessageID, - "broadcast": input.Broadcast, - "dto": map[string]any{ - "plainText": message, - "botName": botName, + _, err = s.client.CreateProxyAPI(token.AccessToken).WriteGroupMessage( + ctx, + native.WriteGroupMessageParams{ + ChannelID: channelID, + GroupID: groupID, + RootMessageID: input.RootMessageID, + Broadcast: input.Broadcast, + DTO: native.WriteMessageDTO{ + PlainText: message, + BotName: botName, }, }, - } - body, err := json.Marshal(payload) - if err != nil { - return err - } - req, err := http.NewRequestWithContext( - ctx, - http.MethodPut, - s.appStoreURL+"/general/v1/native/functions", - bytes.NewReader(body), ) if err != nil { - return err - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("x-access-token", token.AccessToken) - - resp, err := s.httpClient.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - if resp.StatusCode < 200 || resp.StatusCode >= 300 { - return fmt.Errorf("native function returned HTTP %d", resp.StatusCode) - } - - var result struct { - Error *struct { - Message string `json:"message"` - } `json:"error,omitempty"` - } - if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { - return err - } - if result.Error != nil { - return fmt.Errorf("native function error: %s", result.Error.Message) + return fmt.Errorf("write group message: %w", err) } return nil } diff --git a/wam/package.json b/wam/package.json index b40846a..5d9d614 100644 --- a/wam/package.json +++ b/wam/package.json @@ -15,7 +15,7 @@ "@channel.io/app-sdk-wam": "0.17.2", "@channel.io/app-sdk-wam-ui": "0.4.0", "@channel.io/bezier-icons": "0.60.0", - "@channel.io/bezier-react": "4.0.0-next.13", + "@channel.io/bezier-react": "4.0.0-next.14", "react": "^18.2.0", "react-dom": "^18.2.0", "styled-components": "^6.4.3" diff --git a/wam/yarn.lock b/wam/yarn.lock index 94d199b..fa996ed 100644 --- a/wam/yarn.lock +++ b/wam/yarn.lock @@ -318,9 +318,9 @@ __metadata: languageName: node linkType: hard -"@channel.io/bezier-react@npm:4.0.0-next.13": - version: 4.0.0-next.13 - resolution: "@channel.io/bezier-react@npm:4.0.0-next.13" +"@channel.io/bezier-react@npm:4.0.0-next.14": + version: 4.0.0-next.14 + resolution: "@channel.io/bezier-react@npm:4.0.0-next.14" dependencies: "@channel.io/bezier-tokens": "npm:1.0.0-next.5" "@radix-ui/react-checkbox": "npm:^1.1.3" @@ -347,7 +347,7 @@ __metadata: peerDependenciesMeta: "@channel.io/bezier-icons": optional: true - checksum: 10c0/edb77b9ae10c51f982e98ea78d4b7ccde4c0d3c411b4182734ee1474c1bab485f1ecbe9d3e891136698287dd23021472af5693e471500c314f69073dc436ad0d + checksum: 10c0/8414ac28827497b51803990daa5484f5a4d56e77d8a1a7944df4a84d357777e11dbc21f014404f62c89605af76e1b69a9770f0bbefdbd0d0416961244e1d84d8 languageName: node linkType: hard @@ -1907,7 +1907,7 @@ __metadata: "@channel.io/app-sdk-wam": "npm:0.17.2" "@channel.io/app-sdk-wam-ui": "npm:0.4.0" "@channel.io/bezier-icons": "npm:0.60.0" - "@channel.io/bezier-react": "npm:4.0.0-next.13" + "@channel.io/bezier-react": "npm:4.0.0-next.14" "@types/react": "npm:^18.2.56" "@types/react-dom": "npm:^18.2.19" "@typescript-eslint/eslint-plugin": "npm:^7.0.2"