From 9b34a8232383160403344e314a487518f99f48a8 Mon Sep 17 00:00:00 2001 From: Danny McGee Date: Thu, 7 Mar 2024 19:26:01 -0500 Subject: [PATCH] Simple API wrapper --- package-lock.json | 32 ++++++++------------ package.json | 4 +-- studio-frontend/src/app/app.element.ts | 42 +++++++++----------------- studio-web/src/index.ts | 1 + studio-web/src/lib/storyteller-api.ts | 29 ++++++++++++++++++ 5 files changed, 58 insertions(+), 50 deletions(-) create mode 100644 studio-web/src/lib/storyteller-api.ts diff --git a/package-lock.json b/package-lock.json index 9d13de8..024ae5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,12 +10,12 @@ "license": "MIT", "dependencies": { "@fortawesome/fontawesome-pro": "^6.4.2", + "axios": "^1.6.7", "lit": "^2.8.0", "lodash": "^4.17.21", "react": "18.2.0", "react-dom": "18.2.0", - "tslib": "^2.3.0", - "uuid": "^9.0.1" + "tslib": "^2.3.0" }, "devDependencies": { "@nx/js": "16.9.1", @@ -4976,8 +4976,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/available-typed-arrays": { "version": "1.0.5", @@ -4992,12 +4991,11 @@ } }, "node_modules/axios": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", - "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", - "dev": true, + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", + "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", "dependencies": { - "follow-redirects": "^1.15.0", + "follow-redirects": "^1.15.4", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -5606,7 +5604,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -5950,7 +5947,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -6531,10 +6527,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", - "dev": true, + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", "funding": [ { "type": "individual", @@ -6591,7 +6586,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -8041,7 +8035,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -8050,7 +8043,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -8834,8 +8826,7 @@ "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/psl": { "version": "1.9.0", @@ -10202,6 +10193,7 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" diff --git a/package.json b/package.json index 65ddb8a..e2e5c35 100644 --- a/package.json +++ b/package.json @@ -42,11 +42,11 @@ }, "dependencies": { "@fortawesome/fontawesome-pro": "^6.4.2", + "axios": "^1.6.7", "lit": "^2.8.0", "lodash": "^4.17.21", "react": "18.2.0", "react-dom": "18.2.0", - "tslib": "^2.3.0", - "uuid": "^9.0.1" + "tslib": "^2.3.0" } } diff --git a/studio-frontend/src/app/app.element.ts b/studio-frontend/src/app/app.element.ts index 922bda2..0c6627a 100644 --- a/studio-frontend/src/app/app.element.ts +++ b/studio-frontend/src/app/app.element.ts @@ -1,4 +1,4 @@ -import { drag, on } from "@storyteller/framework"; +import { drag, on, provide } from "@storyteller/framework"; import * as studio from "@storyteller/studio"; import { type SceneSavedEvent, @@ -9,6 +9,7 @@ import { import { ButtonElement } from "@storyteller/studio-ui/button"; import { SceneHierarchyElement, + StorytellerApi, StudioURLParams, } from "@storyteller/studio-web"; import { match } from "@storyteller/utility"; @@ -17,7 +18,6 @@ import { customElement, state } from "lit/decorators.js"; import { classMap } from "lit/directives/class-map.js"; import { createRef, ref } from "lit/directives/ref.js"; import { styleMap } from "lit/directives/style-map.js"; -import { v4 as uuid } from "uuid"; import "@storyteller/studio-ui/button"; import "@storyteller/studio-ui/icon"; @@ -40,6 +40,10 @@ import "./blocking.element"; import "./app.element.scss"; @customElement("app-root") +@provide({ + token: StorytellerApi, + provide() { return this.api; } +}) export class AppElement extends LitElement { @state() showHelp = false; @state() showInspector = false; @@ -49,6 +53,7 @@ export class AppElement extends LitElement { @state() inspectorWidth = 320; @state() hierarchyHeight?: number; + private api = new StorytellerApi(); #enableAnimTimeline = false; // TODO #addToSceneButtonRef = createRef(); @@ -63,34 +68,15 @@ export class AppElement extends LitElement { @on("scene-saved") async onSceneSaved({ detail: scene }: SceneSavedEvent): Promise { - const file = new File([scene], "scene.scn.ron", { type: "text/ron" }); - const formData = new FormData(); - - formData.append("uuid_idempotency_token", uuid()); - formData.append("file", file); - try { - const response = await fetch("https://api.fakeyou.com/v1/engine/create_scene", { - method: "POST", - credentials: "include", - headers: { "Accept": "text/plain" }, - body: formData, - }); + const file = new File([scene], "scene.scn.ron", { type: "text/ron" }); + const token = await this.api.createScene(file); - if (response.ok) { - const resultJson: { - success: boolean; - media_file_token: string; - } = await response.json(); - - if (resultJson.success) { - this.dispatchEvent(new CustomEvent("scene-uploaded", { - detail: resultJson.media_file_token, - bubbles: true, - composed: true, - })); - } - } + this.dispatchEvent(new CustomEvent("scene-uploaded", { + detail: token, + bubbles: true, + composed: true, + })); } catch (err) { console.error(err); diff --git a/studio-web/src/index.ts b/studio-web/src/index.ts index cb9fca3..99ace80 100644 --- a/studio-web/src/index.ts +++ b/studio-web/src/index.ts @@ -6,6 +6,7 @@ export * from "./lib/inspector/inspector.types"; export * from "./lib/loading.element"; export * from "./lib/scene-data-provider.element"; export * from "./lib/scene-hierarchy.element"; +export * from "./lib/storyteller-api"; export * from "./lib/studio.element"; export * from "./lib/transform-toolbar.element"; export * from "./lib/url-params"; diff --git a/studio-web/src/lib/storyteller-api.ts b/studio-web/src/lib/storyteller-api.ts new file mode 100644 index 0000000..714249d --- /dev/null +++ b/studio-web/src/lib/storyteller-api.ts @@ -0,0 +1,29 @@ +import axios from "axios"; + +export type MediaToken = string; + +export class StorytellerApi { + #api = axios.create({ + baseURL: "https://api.fakeyou.com", + withCredentials: true, + }); + + async createScene(file: File): Promise { + type Response = { + success: boolean; + media_file_token: MediaToken; + } + + const response = await this.#api.postForm("v1/engine/create_scene", { + uuid_idempotency_token: crypto.randomUUID(), + file, + }, { + headers: { Accept: "text/plain" }, + }); + + if (response.status === 200 && response.data.success) + return response.data.media_file_token; + + throw new Error(`API responded with status ${response.status}: "${response.statusText}"`); + } +}