diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..18409cc --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,27 @@ +name: test + +on: + push: + branches: + - master + - main + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: oven-sh/setup-bun@v1 + - uses: erlef/setup-beam@v1 + with: + otp-version: "26.0.2" + gleam-version: "0.34.1" + rebar3-version: "3" + - run: bun i --frozen-lockfile + - run: gleam deps download + - run: bun run build + - uses: actions/upload-artifact@v4 + with: + name: sdk + path: dist/ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..85d14a9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.beam +*.ez +/build +erl_crash.dump +/dist +node_modules \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..1e5ae4f --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# supso_sdk + +[![Package Version](https://img.shields.io/hexpm/v/supso_sdk)](https://hex.pm/packages/supso_sdk) +[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/supso_sdk/) + +```sh +gleam add supso_sdk +``` + +```gleam +import supso_sdk + +pub fn main() { + // TODO: An example of the project in use +} +``` + +Further documentation can be found at . + +## Development + +```sh +gleam run # Run the project +gleam test # Run the tests +gleam shell # Run an Erlang shell +``` diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000..07d746e Binary files /dev/null and b/bun.lockb differ diff --git a/gleam.toml b/gleam.toml new file mode 100644 index 0000000..afc50ae --- /dev/null +++ b/gleam.toml @@ -0,0 +1,23 @@ +name = "supso_sdk" +version = "1.0.0" + +# Fill out these fields if you intend to generate HTML documentation or publish +# your project to the Hex package manager. +# +description = "SDK client for supso.co" +licences = ["Apache-2.0"] +repository = { type = "github", user = "palladians", repo = "supso_sdk" } +links = [{ title = "Website", href = "https://supso.co" }] +# +# For a full reference of all the available options, you can have a look at +# https://gleam.run/writing-gleam/gleam-toml/. + +[dependencies] +gleam_stdlib = "~> 0.34 or ~> 1.0" +gleam_http = "~> 3.5" +gleam_javascript = "~> 0.7" +gleam_json = "~> 0.7" +gleam_fetch = "~> 0.3" + +[dev-dependencies] +gleeunit = "~> 1.0" diff --git a/manifest.toml b/manifest.toml new file mode 100644 index 0000000..a8d9376 --- /dev/null +++ b/manifest.toml @@ -0,0 +1,20 @@ +# This file was generated by Gleam +# You typically do not need to edit this file + +packages = [ + { name = "gleam_fetch", version = "0.3.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_http", "gleam_javascript"], otp_app = "gleam_fetch", source = "hex", outer_checksum = "24F83C6EF5BC274EF4D712B374D7CDB795136883DA64E2BA6435AF8E6C57E6E2" }, + { name = "gleam_http", version = "3.5.3", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "C2FC3322203B16F897C1818D9810F5DEFCE347F0751F3B44421E1261277A7373" }, + { name = "gleam_javascript", version = "0.7.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_javascript", source = "hex", outer_checksum = "EEA30D1ABF62B06FC378764D598DF041303CFA33A6586BFF4C4BFEFFA83DBDBE" }, + { name = "gleam_json", version = "0.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "CB405BD93A8828BCD870463DE29375E7B2D252D9D124C109E5B618AAC00B86FC" }, + { name = "gleam_stdlib", version = "0.34.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "1FB8454D2991E9B4C0C804544D8A9AD0F6184725E20D63C3155F0AEB4230B016" }, + { name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" }, + { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" }, +] + +[requirements] +gleam_fetch = { version = "~> 0.3" } +gleam_http = { version = "~> 3.5" } +gleam_javascript = { version = "~> 0.7" } +gleam_json = { version = "~> 0.7" } +gleam_stdlib = { version = "~> 0.34 or ~> 1.0" } +gleeunit = { version = "~> 1.0" } diff --git a/package.json b/package.json new file mode 100644 index 0000000..0557251 --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "supso_sdk", + "module": "index.ts", + "type": "module", + "scripts": { + "build:gleam": "gleam build --target javascript", + "build:bun": "bun build build/dev/javascript/supso_sdk/supso_sdk.mjs --outdir dist", + "build": "bun run build:gleam && bun run build:bun", + "test": "gleam test --target javascript" + }, + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + } +} diff --git a/src/supso_sdk.gleam b/src/supso_sdk.gleam new file mode 100644 index 0000000..923ea58 --- /dev/null +++ b/src/supso_sdk.gleam @@ -0,0 +1,63 @@ +import gleam/fetch +import gleam/uri +import gleam/http/request +import gleam/http.{Post} +import gleam/json.{object, string} + +pub type ApiEndpoint { + LogEvent + FeatureFlags +} + +pub type ClientProps { + ClientProps(app_url: String, access_token: String) +} + +pub type Event { + Event(project_id: String, channel: String, event: String) +} + +pub type Client { + Client(props: ClientProps) +} + +fn event_to_json(event: Event) { + object([ + #("projectId", string(event.project_id)), + #("channel", string(event.channel)), + #("event", string(event.event)), + ]) + |> json.to_string +} + +pub fn get_feature_flags(client: Client, project_id: String) { + let assert Ok(app_uri) = uri.parse(client.props.app_url) + let assert Ok(feature_flags_request) = request.from_uri(app_uri) + let feature_flags_request = + feature_flags_request + |> request.set_path("/api/feature_flags/" <> project_id) + |> request.prepend_header( + "authorization", + "Bearer " <> client.props.access_token, + ) + fetch.send(feature_flags_request) +} + +pub fn log_event(client: Client, event: Event) { + let assert Ok(app_uri) = uri.parse(client.props.app_url) + let assert Ok(log_event_request) = request.from_uri(app_uri) + let log_event_request = + log_event_request + |> request.set_path("/api/log") + |> request.set_method(Post) + |> request.set_body(event_to_json(event)) + |> request.prepend_header( + "authorization", + "Bearer " <> client.props.access_token, + ) + fetch.send(log_event_request) +} + +pub fn connect(props: ClientProps) -> Client { + Client(props) +} diff --git a/test/supso_sdk_test.gleam b/test/supso_sdk_test.gleam new file mode 100644 index 0000000..d68c824 --- /dev/null +++ b/test/supso_sdk_test.gleam @@ -0,0 +1,41 @@ +import gleeunit +import gleeunit/should +import supso_sdk +import gleam/fetch +import gleam/string +import gleam/javascript/promise + +pub const client_props = supso_sdk.ClientProps( + app_url: "http://localhost:5173", + access_token: "45e45ee6-e769-4c6c-9a28-8e4d123339f7", +) + +pub fn main() { + gleeunit.main() +} + +pub fn feature_flags_test() { + client_props + |> supso_sdk.connect + |> supso_sdk.get_feature_flags("6827f121-458c-4421-b8d1-edb9d5bd0ee8") + |> promise.try_await(fetch.read_text_body) + |> promise.await(fn(resp) { + let assert Ok(resp) = resp + should.be_true(string.length(resp.body) > 0) + promise.resolve(Ok(Nil)) + }) +} + +pub fn log_event_test() { + let event = + supso_sdk.Event(project_id: "6827f121-458c-4421-b8d1-edb9d5bd0ee8", channel: "test", event: "test") + client_props + |> supso_sdk.connect + |> supso_sdk.log_event(event) + |> promise.try_await(fetch.read_text_body) + |> promise.await(fn(resp) { + let assert Ok(resp) = resp + should.be_true(string.length(resp.body) > 0) + promise.resolve(Ok(Nil)) + }) +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..dcd8fc5 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "lib": ["ESNext"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + /* Linting */ + "skipLibCheck": true, + "strict": true, + "noFallthroughCasesInSwitch": true, + "forceConsistentCasingInFileNames": true + } +}