{"id":51070648,"url":"https://github.com/exanubes/appsync","last_synced_at":"2026-06-23T10:01:39.312Z","repository":{"id":360534632,"uuid":"1212706566","full_name":"exanubes/appsync","owner":"exanubes","description":"Go client library for AWS AppSync Events over WebSocket with API key, IAM, Lambda authorizer, Cognito, OIDC, publish, and subscribe support.","archived":false,"fork":false,"pushed_at":"2026-06-06T19:55:13.000Z","size":175,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-06T21:10:17.037Z","etag":null,"topics":["appsync","appsync-events","aws","aws-appsync","cognito","events","go","golang","iam","oidc","pubsub","serverless","websocket"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/exanubes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-16T16:43:13.000Z","updated_at":"2026-06-06T19:55:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/exanubes/appsync","commit_stats":null,"previous_names":["exanubes/appsync"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/exanubes/appsync","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exanubes%2Fappsync","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exanubes%2Fappsync/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exanubes%2Fappsync/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exanubes%2Fappsync/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/exanubes","download_url":"https://codeload.github.com/exanubes/appsync/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exanubes%2Fappsync/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34684686,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-23T02:00:07.161Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["appsync","appsync-events","aws","aws-appsync","cognito","events","go","golang","iam","oidc","pubsub","serverless","websocket"],"created_at":"2026-06-23T10:01:37.447Z","updated_at":"2026-06-23T10:01:39.300Z","avatar_url":"https://github.com/exanubes.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Go Reference](https://pkg.go.dev/badge/github.com/exanubes/appsync.svg)](https://pkg.go.dev/github.com/exanubes/appsync)\n[![Go Report Card](https://goreportcard.com/badge/github.com/exanubes/appsync)](https://goreportcard.com/report/github.com/exanubes/appsync)\n[![License](https://img.shields.io/github/license/exanubes/appsync)](LICENSE)\n[![Unit tests](https://github.com/exanubes/appsync/actions/workflows/tests.yaml/badge.svg)](https://github.com/exanubes/appsync/actions/workflows/tests.yaml)\n\n# appsync — AWS AppSync Events WebSocket client for Go\n\n`appsync` is a Go client library for the AWS AppSync Events WebSocket API.\nIt supports connecting to AppSync Event APIs, subscribing to channels, publishing events,\nand authorizing requests with API key, IAM, Lambda authorizer, Cognito User Pools, OIDC, or a custom authorizer.\n\n## Table of contents\n\n- [Installation](#installation)\n- [Core concepts](#core-concepts)\n- [Endpoints](#endpoints)\n- [Quick start](#quick-start)\n- [Built-in authorizers](#built-in-authorizers)\n  - [API key](#api-key)\n  - [IAM](#iam)\n  - [Token-based authorization](#token-based-authorization)\n- [Authorizers](#authorizers)\n- [Publishing events](#publishing-events)\n- [Subscribing to events](#subscribing-to-events)\n- [Closing resources](#closing-resources)\n- [Custom authorizers](#custom-authorizers)\n- [Backpressure configuration](#backpressure-configuration)\n- [Public errors](#public-errors)\n- [Examples](#examples)\n- [Limitations](#limitations)\n- [Tips](#tips)\n- [Status](#status)\n- [License](#license)\n\n## Installation\n\n```bash\ngo get github.com/exanubes/appsync\n```\n\n```go\nimport (\n\t\"github.com/exanubes/appsync\"\n\t\"github.com/exanubes/appsync/authorizer\"\n)\n```\n\n## Core concepts\n\nThe root package exposes two main abstractions:\n\n```go\ntype Client interface {\n    Publish(context.Context, PublishCommandInput) (*PublishCommandOutput, error)\n    Subscribe(context.Context, SubscribeCommandInput) (Subscription, error)\n    Close(context.Context) error\n}\n\ntype Subscription interface {\n    Close(context.Context) error\n    Next(context.Context) (*NextMessageOutput, error)\n    DecodeNext(context.Context, any) error\n}\n```\n\nUse `appsync.Connect` to establish one WebSocket connection. Use the returned `Client` to subscribe to channels and \npublish events. A `Subscription` receives events from one channel.\n\nThe AppSync Events WebSocket subprotocol value is exported as:\n\n```go\nappsync.ProtocolEvents // \"aws-appsync-event-ws\"\n```\n\nPass it through `ConnectionOptions.Subprotocols` when connecting.\n\n## Endpoints\n\nThe library uses two AppSync Events endpoints:\n\n- the WebSocket realtime endpoint, used by the client to establish the connection;\n- the HTTP event endpoint, used by authorizers to build the authorization headers expected by AppSync.\n\nExample shape:\n\n```go\nhttpEndpoint := \"https://xxxxxxxxxxxxxxxxxxxx.appsync-api.us-east-1.amazonaws.com/event\"\nwsEndpoint := \"wss://xxxxxxxxxxxxxxxxxxxx.appsync-realtime-api.us-east-1.amazonaws.com/event/realtime\"\n```\n\n\n\nThe authorizer uses the HTTP endpoint to create the authorization data expected by AppSync. The client uses the WebSocket endpoint to connect.\n\n## Quick start\n\n```go\nfunc publish(ctx context.Context) error {\n    httpEndpoint := \"https://xxxxxxxxxxxxxxxxxxxx.appsync-api.us-east-1.amazonaws.com/event\"\n    wsEndpoint := \"wss://xxxxxxxxxxxxxxxxxxxx.appsync-realtime-api.us-east-1.amazonaws.com/event/realtime\"\n\n\tauthz, err := authorizer.ApiKey(authorizer.ApiKeyAuthorizerConfig{\n\t\tApiKey:   \"your-api-key\",\n\t\tEndpoint: httpEndpoint,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tclient, err := appsync.Connect(ctx, appsync.ConnectionOptions{\n\t\tEndpoint:     wsEndpoint,\n\t\tSubprotocols: []string{appsync.ProtocolEvents},\n\t\tAuthorizers:  appsync.Authorizers{Default: authz},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer client.Close(context.Background())\n\n\t_, err = client.Publish(ctx, appsync.PublishCommandInput{\n\t\tChannel: \"default/notifications\",\n\t\tEvents:  [][]byte{[]byte(`{\"message\":\"hello\"}`)},\n\t})\n\treturn err\n}\n```\n\n## Built-in authorizers\n\nThe `authorizer` package includes built-in implementations for common AppSync Events authorization modes.\n\n### API key\n\nUse `authorizer.ApiKey` when your AppSync Events API is configured for API key authorization.\n\n```go\nauthz, err := authorizer.ApiKey(authorizer.ApiKeyAuthorizerConfig{\n    ApiKey:   \"your-api-key\",\n    Endpoint: httpEndpoint,\n})\nif err != nil {\n    return err\n}\n```\n\n### IAM\n\nUse `authorizer.IAM` when your AppSync Events API is configured for IAM authorization.\n\n```go\nauthz, err := authorizer.IAM(authorizer.IAMAuthorizerConfig{\n    Region:   \"eu-central-1\",\n    Endpoint: httpEndpoint,\n})\nif err != nil {\n    return err\n}\n```\n\nIAM authorization uses the AWS SDK credential resolution. Environment credentials,\nshared config/profile credentials, SSO, STS credentials, AssumeRole, ECS/EC2 role\ncredentials, and Lambda role credentials can be used when they are resolvable by\nthe AWS SDK configuration used by the authorizer.\n\n### Token-based authorization\n\nUse `authorizer.Token` for AppSync authorization modes where AppSync expects an `Authorization` token, including Lambda \nauthorizers, Cognito User Pool tokens, and OpenID Connect tokens.\n\n```go\nauthz, err := authorizer.Token(authorizer.TokenAuthorizerConfig{\n    AuthToken: token,\n    Endpoint:  httpEndpoint,\n})\nif err != nil {\n    return err\n}\n```\n\nExamples:\n\n```go\n// Lambda authorizer token\nauthz, err := authorizer.Token(authorizer.TokenAuthorizerConfig{\n    AuthToken: \"custom-token\",\n    Endpoint:  httpEndpoint,\n})\n\n// Cognito User Pool ID token\nauthz, err := authorizer.Token(authorizer.TokenAuthorizerConfig{\n    AuthToken: cognitoIDToken,\n    Endpoint:  httpEndpoint,\n})\n\n// OIDC token\nauthz, err := authorizer.Token(authorizer.TokenAuthorizerConfig{\n    AuthToken: oidcToken,\n    Endpoint:  httpEndpoint,\n})\n```\n\n## Authorizers\n\n`ConnectionOptions.Authorizers` controls which authorizer is used for each operation type.\n\n```go\ntype Authorizers struct {\n    Default   authorizer.Authorizer\n    Connect   authorizer.Authorizer\n    Publish   authorizer.Authorizer\n    Subscribe authorizer.Authorizer\n}\n```\n\nFallback resolution: if a specific field (`Connect`, `Publish`, or `Subscribe`) is `nil`, `Default` is used.\n\n**Single authorizer for all operations (most common):**\n\n```go\nclient, err := appsync.Connect(ctx, appsync.ConnectionOptions{\n    Endpoint:     wsEndpoint,\n    Subprotocols: []string{appsync.ProtocolEvents},\n    Authorizers:  appsync.Authorizers{Default: authz},\n})\n```\n\n**Different authorizers per operation:**\n\n```go\nclient, err := appsync.Connect(ctx, appsync.ConnectionOptions{\n    Endpoint:     wsEndpoint,\n    Subprotocols: []string{appsync.ProtocolEvents},\n    Authorizers: appsync.Authorizers{\n        Connect:   connectAuthz,\n        Publish:   publishAuthz,\n        Subscribe: subscribeAuthz,\n    },\n})\n```\n\n**Subscribe-only or publish-only clients:**\n\nAuthorizers for `Publish` and `Subscribe` are resolved at the point of use. If an operation is never called, its authorizer never needs to be configured. This makes it possible to follow the principle of least privilege by omitting `Default` and only configuring the authorizer for the operations the client actually uses.\n\nSubscribe-only client — no publish authorizer configured:\n\n```go\nclient, err := appsync.Connect(ctx, appsync.ConnectionOptions{\n    Endpoint:     wsEndpoint,\n    Subprotocols: []string{appsync.ProtocolEvents},\n    Authorizers: appsync.Authorizers{\n        Connect:   connectAuthz,\n        Subscribe: subscribeAuthz,\n    },\n})\n```\n\nPublish-only client — no subscribe authorizer configured:\n\n```go\nclient, err := appsync.Connect(ctx, appsync.ConnectionOptions{\n    Endpoint:     wsEndpoint,\n    Subprotocols: []string{appsync.ProtocolEvents},\n    Authorizers: appsync.Authorizers{\n        Connect:  connectAuthz,\n        Publish:  publishAuthz,\n    },\n})\n```\n\n## Publishing events\n\n`Publish` sends one or more events to a channel. `Events` is a slice of raw byte slices — one entry per event.\n\n```go\npayload := []byte(`{\"message\":\"hello\"}`)\n\nresult, err := client.Publish(ctx, appsync.PublishCommandInput{\n    Channel: \"default/notifications\",\n    Events:  [][]byte{payload},\n})\nif err != nil {\n    return err\n}\n```\n\nThe library does not require a Go struct, but AppSync event payloads are commonly JSON. If you want structured data, marshal it before publishing.\n\n### Batch publishing\n\nPass multiple events in a single call:\n\n```go\nevents := [][]byte{\n    []byte(`{\"message\":\"first\"}`),\n    []byte(`{\"message\":\"second\"}`),\n    []byte(`{\"message\":\"third\"}`),\n}\n\nresult, err := client.Publish(ctx, appsync.PublishCommandInput{\n    Channel: \"default/notifications\",\n    Events:  events,\n})\nif err != nil {\n    return err\n}\n```\n\n### Handling per-event failures\n\n`PublishCommandOutput` reports which events failed individually. The top-level `error` is non-nil only for fatal transport failures that prevent any events from being sent. Individual failures are in `result.Errors`:\n\n```go\nif !result.Success {\n    for _, failed := range result.Errors {\n        log.Printf(\"event failed: payload=%s err=%v\", failed.Payload, failed.Err)\n    }\n}\n```\n\nThe optional `Authorizer` field overrides `Authorizers.Publish` for a single call:\n\n```go\nresult, err := client.Publish(ctx, appsync.PublishCommandInput{\n    Channel:    \"default/notifications\",\n    Events:     [][]byte{payload},\n    Authorizer: perRequestAuthz,\n})\n```\n\n## Subscribing to events\n\nUse `Subscribe` to create a channel subscription.\n\n```go\nsub, err := client.Subscribe(ctx, appsync.SubscribeCommandInput{\n    Channel: \"default/notifications\",\n})\nif err != nil {\n    return err\n}\ndefer sub.Close(context.Background())\n```\n\nThe optional `Authorizer` field overrides `Authorizers.Subscribe` for a single call:\n\n```go\nsub, err := client.Subscribe(ctx, appsync.SubscribeCommandInput{\n    Channel:    \"default/notifications\",\n    Authorizer: perRequestAuthz,\n})\n```\n\nRead event messages with `Next`:\n\n```go\nmessage, err := sub.Next(ctx)\nif err != nil {\n    return err\n}\n\nfmt.Printf(\"raw payload: %s\\n\", message.Data)\n```\n\nDecode JSON payloads with `DecodeNext`:\n\n```go\ntype Notification struct {\n    Message string `json:\"message\"`\n}\n\nvar notification Notification\nif err := sub.DecodeNext(ctx, \u0026notification); err != nil {\n    return err\n}\n```\n\n`Next` and `DecodeNext` block until one of these happens:\n\n- a message arrives,\n- the context is cancelled or reaches its deadline,\n- the subscription is closed.\n\nUse context deadlines on read operations if the caller cannot block indefinitely.\n\n## Closing resources\n\nClose subscriptions when you no longer need channel events:\n\n```go\nif err := sub.Close(ctx); err != nil {\n    return err\n}\n```\n\nClose the client when the WebSocket connection is no longer needed:\n\n```go\nif err := client.Close(ctx); err != nil {\n    return err\n}\n```\n\nClosing the client closes the WebSocket connection and all open subscriptions created on it.\n\nA closed subscription returns `appsync.ErrSubscriptionClosed` from later reads. Calling `Close` on an already closed \nsubscription can also return `appsync.ErrSubscriptionClosed`.\n\n## Custom authorizers\n\nImplement `authorizer.Authorizer` when the built-in authorizers do not fit your authorization model.\n\n```go\ntype Authorizer interface {\n    Authorize(context.Context, AuthorizeCommandInput) (*AuthorizeCommandOutput, error)\n}\n\ntype AuthorizeCommandInput struct {\n    Channel string\n    Payload []byte\n}\n\ntype AuthorizeCommandOutput struct {\n    Signature map[string]string\n}\n```\n\nThe returned `Signature` map should contain the authorization fields AppSync expects. The library uses that map for the \nWebSocket connection handshake and for outgoing subscribe, publish, and unsubscribe operations.\n\nA single `Client` uses the same authorizer for all of those operations.\n\nImportant: `Authorize` must handle empty input. The library calls it in multiple situations:\n\n| Operation         | `Channel`            | `Payload`       |\n|-------------------|----------------------|-----------------|\n| Connect handshake | empty                | nil             |\n| Subscribe         | subscription channel | nil             |\n| Publish           | destination channel  | publish payload |\n| Unsubscribe       | empty                | nil             |\n\nA minimal static custom authorizer can look like this:\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"net/url\"\n\n    \"github.com/exanubes/appsync/authorizer\"\n)\n\ntype StaticAuthorizer struct {\n    token string\n    host  string\n}\n\nfunc NewStaticAuthorizer(endpoint string, token string) (*StaticAuthorizer, error) {\n    parsed, err := url.Parse(endpoint)\n    if err != nil {\n        return nil, err\n    }\n\n    return \u0026StaticAuthorizer{\n        token: token,\n        host:  parsed.Host,\n    }, nil\n}\n\nfunc (authz *StaticAuthorizer) Authorize(\n    ctx context.Context,\n    input authorizer.AuthorizeCommandInput,\n) (*authorizer.AuthorizeCommandOutput, error) {\n    return \u0026authorizer.AuthorizeCommandOutput{\n        Signature: map[string]string{\n            \"Authorization\": authz.token,\n            \"host\":          authz.host,\n        },\n    }, nil\n}\n```\n\nThen pass it to `appsync.Connect`:\n\n```go\nauthz, err := NewStaticAuthorizer(httpEndpoint, token)\nif err != nil {\n    return err\n}\n\nclient, err := appsync.Connect(ctx, appsync.ConnectionOptions{\n    Endpoint:     wsEndpoint,\n    Subprotocols: []string{appsync.ProtocolEvents},\n    Authorizers:  appsync.Authorizers{Default: authz},\n})\n```\n\n### Custom authorizer with per-message signing\n\nSome authorization schemes need the channel and payload to compute a signature. `AuthorizeCommandInput` exposes both values.\n\n```go\nfunc (authz *SigningAuthorizer) Authorize(\n    ctx context.Context,\n    input authorizer.AuthorizeCommandInput,\n) (*authorizer.AuthorizeCommandOutput, error) {\n    signature, err := authz.sign(ctx, input.Channel, input.Payload)\n    if err != nil {\n        return nil, err\n    }\n\n    return \u0026authorizer.AuthorizeCommandOutput{\n        Signature: map[string]string{\n            \"Authorization\": signature,\n            \"host\":          authz.host,\n        },\n    }, nil\n}\n```\n\nFor connection and unsubscribe calls, `input.Channel` is empty and `input.Payload` is nil. The signing function must treat that as a valid case.\n\n## Backpressure configuration\n\n`ConnectionOptions.Backpressure` controls internal buffer sizes.\n\n```go\nclient, err := appsync.Connect(ctx, appsync.ConnectionOptions{\n    Endpoint:     wsEndpoint,\n    Subprotocols: []string{appsync.ProtocolEvents},\n    Authorizers:  appsync.Authorizers{Default: authz},\n    Backpressure: appsync.Backpressure{\n        ConnectionInbound:  100,\n        ConnectionOutbound: 100,\n        SubscriptionEvents: 100,\n    },\n})\n```\n\nFields:\n\n| Field                | Meaning                                                                    |\n|----------------------|----------------------------------------------------------------------------|\n| `ConnectionInbound`  | Buffer for messages received from the WebSocket connection before routing. |\n| `ConnectionOutbound` | Buffer for messages waiting to be written to the WebSocket connection.     |\n| `SubscriptionEvents` | Buffer for events waiting to be consumed by a subscription.                |\n\nZero values use the library default of `100`. Setting a field to `0` does not create an unbuffered channel.\n\nLarge buffers can increase memory usage, especially with many subscriptions or large payloads. There is no global \nmemory cap exposed by the public API.\n\nIf a subscription event buffer stays full, event delivery can fail with `appsync.ErrSubscriptionInboxFull`.\n\n## Public errors\n\nThe root package exposes sentinel errors that callers can check with `errors.Is`:\n\n- `appsync.ErrEmptyUrl`\n- `appsync.ErrHandshakeTimeout`\n- `appsync.ErrDuplicateMessage`\n- `appsync.ErrSubscriptionInboxFull`\n- `appsync.ErrSubscriptionClosed`\n- `appsync.ErrSubscriptionNotFound`\n- `appsync.ErrHeartbeatTimeout`\n- `appsync.ErrConnectionClosed`\n\nTypical handling:\n\n```go\nmessage, err := sub.Next(ctx)\nif err != nil {\n    switch {\n    case errors.Is(err, context.Canceled), errors.Is(err, context.DeadlineExceeded):\n        return err\n    case errors.Is(err, appsync.ErrSubscriptionClosed):\n        return nil\n    default:\n        return err\n    }\n}\n\nfmt.Printf(\"received: %s\\n\", message.Data)\n```\n\nRelevant behavior:\n\n- `ErrHandshakeTimeout` means the WebSocket connection was opened, but AppSync did not acknowledge the connection initialization in time.\n- `ErrHeartbeatTimeout` means keep-alive messages stopped arriving within the expected connection timeout window.\n- `ErrSubscriptionClosed` means the subscription is no longer active.\n- `ErrSubscriptionInboxFull` means the subscriber did not consume events fast enough for its configured buffer.\n- `ErrConnectionClosed` means the connection is no longer live either because it was manually closed or because there \nwas an error which will be joined with this error\n- Context cancellation and deadlines are propagated from public methods where applicable.\n- `Publish` per-event failures are not returned as the top-level `error`. Check `PublishCommandOutput.Success` and `PublishCommandOutput.Errors` for individual event failures. The top-level `error` signals a fatal transport failure only.\n\n## Examples\n\nRunnable examples are available in:\n\n- [`examples/api-key`](examples/api-key)\n- [`examples/iam`](examples/iam)\n- [`examples/token`](examples/token)\n- [`examples/custom-authorizer`](examples/custom-authorizer)\n- [`examples/multi-authorizer`](examples/multi-authorizer)\n\n## Tips\n\n### Use one client per WebSocket connection\n\nA `Client` represents one active AppSync WebSocket connection. Multiple subscriptions can be created from the same client.\n\n### Always close what you open\n\nClose individual subscriptions when a channel is no longer needed. Close the client when shutting down the process or \ncomponent that owns the connection.\n\n### Put deadlines on blocking calls\n\n`Connect`, `Publish`, `Subscribe`, `Subscription.Close`, `Subscription.Next`, `Subscription.DecodeNext`, and \n`Client.Close` all accept `context.Context`. Use deadlines when the caller has a bounded lifecycle.\n\n### Treat payloads as application-owned bytes\n\nThe library accepts and returns payloads as `[]byte`. It does not impose an application schema. Use `json.Marshal` and `DecodeNext` \nwhen your event contract is JSON.\n\n### Keep custom authorizers side-effect safe\n\nA custom authorizer may be called for every connect, subscribe, publish, and unsubscribe operation. Avoid expensive \nwork where possible, cache stable data safely, and refresh credentials/tokens deliberately when your auth model \nrequires it.\n\n## Status\n\nThe API is the desired shape and it \"works for me\", however, since the library does not yet support the full Appsync \nEvents API featureset, I've decided to have it as a v0 in case somebody actually uses this and I need to break the API\nin the future for some reason.\n\nMissing features:\n\n- HTTP Publish\n- something else I missed probably\n\n## License\n\nThis project is licensed under the MIT License. See [LICENSE](LICENSE) for details.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexanubes%2Fappsync","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fexanubes%2Fappsync","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexanubes%2Fappsync/lists"}