@codesandbox/api
Version:
The CodeSandbox API
78 lines • 3.48 kB
JavaScript
import * as withAbsintheSocket from "@absinthe/socket";
import { Socket as PhoenixSocket } from "phoenix";
import { createClient } from "./generated_gql";
const SUBSCRIPTION_HEARTBEAT_INTERVAL = 10000;
export class GQLApi {
constructor(options) {
const WEBSOCKET_URL = new URL(`${options.apiUrl}/socket`);
const webSocketProtocol = WEBSOCKET_URL.protocol === "http:" ? "ws:" : "wss:";
WEBSOCKET_URL.protocol = webSocketProtocol;
let socketPromise;
const client = createClient({
onRequest: (query, variables, headers) => {
return options
.request({
method: "POST",
data: { query, variables },
path: "/graphql",
headers,
})
.then(({ data }) => data);
},
onSubscribe: (query, cb, variables) => {
const currentSocketPromise = socketPromise;
if (!currentSocketPromise) {
// This is not really a possible scenario as we always create a socket
// when starting the first subscription
return () => { };
}
const notifierPromise = currentSocketPromise.then((socket) => {
const notifier = withAbsintheSocket.send(socket, {
operation: query,
variables: Object.assign({}, variables),
});
withAbsintheSocket.observe(socket, notifier, {
// eslint-disable-next-line
onError: console.error,
onResult: (result) => cb(result.data),
});
return notifier;
});
return () => {
Promise.all([currentSocketPromise, notifierPromise]).then(([socket, notifier]) => {
withAbsintheSocket.cancel(socket, notifier);
});
};
},
includeTypeNames: false,
cacheQueries: false,
});
this.query = client.query.bind(client);
// Not sure why TS is so angry at the parameters here
// eslint-disable-next-line
// @ts-ignore
this.subscribe = (...args) => {
// Creating the socket is ASYNC as we potentially need to call an endpoint to get the guardian token
if (!socketPromise) {
socketPromise = this.getSubscriptionSocket(WEBSOCKET_URL.toString(), options.session);
}
return client.subscribe(...args);
};
}
async getSubscriptionSocket(websocketUrl, session) {
const getToken = async () => await (session.bearerToken || session.getGuardianToken());
let token = await getToken();
const phoenixSocketOpts = {
params: () => ({ guardian_token: token }),
heartbeatIntervalMs: SUBSCRIPTION_HEARTBEAT_INTERVAL,
};
const phoenixSocket = new PhoenixSocket(websocketUrl, phoenixSocketOpts);
// Whenever the socket errors it is most likely related to an expired token. We go and grab a new token
// and update it
phoenixSocket.onError(async () => {
token = await getToken();
});
return withAbsintheSocket.create(phoenixSocket);
}
}
//# sourceMappingURL=GQLApi.js.map