@supernova-studio/client 0.54.19 → 0.54.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supernova-studio/client",
3
- "version": "0.54.19",
3
+ "version": "0.54.21",
4
4
  "description": "Supernova Data Models",
5
5
  "source": "src/index.ts",
6
6
  "main": "dist/index.js",
@@ -0,0 +1,26 @@
1
+ import { WorkspacesEndpoint } from "./endpoints";
2
+ import { DesignSystemsEndpoint } from "./endpoints/design-systems";
3
+ import { UsersEndpoint } from "./endpoints/users";
4
+ import { RequestExecutor } from "./transport/request-executor";
5
+
6
+ type SupernovaApiClientConfig = {
7
+ host: string;
8
+ accessToken: string;
9
+ };
10
+
11
+ export class SupernovaApiClient {
12
+ readonly users: UsersEndpoint;
13
+ readonly workspaces: WorkspacesEndpoint;
14
+ readonly designSystems: DesignSystemsEndpoint;
15
+
16
+ constructor(config: SupernovaApiClientConfig) {
17
+ const requestExecutor = new RequestExecutor({
18
+ host: config.host,
19
+ accessToken: config.accessToken,
20
+ });
21
+
22
+ this.users = new UsersEndpoint(requestExecutor);
23
+ this.workspaces = new WorkspacesEndpoint(requestExecutor);
24
+ this.designSystems = new DesignSystemsEndpoint(requestExecutor);
25
+ }
26
+ }
@@ -0,0 +1,20 @@
1
+ import { z } from "zod";
2
+ import { DTOBrand, DTODesignSystem, DTODesignSystemVersion } from "../design-systems";
3
+ import { DTOUserWorkspaceMembership } from "../workspaces";
4
+
5
+ export const DTOAppBootstrapDataQuery = z.object({
6
+ preferredWorkspaceId: z.string().optional(),
7
+ preferredDesignSystemId: z.string().optional(),
8
+ preferredVersionId: z.string().optional(),
9
+ preferredBrandId: z.string().optional(),
10
+ });
11
+
12
+ export const DTOAppBootstrapDataResponse = z.object({
13
+ workspaceMembership: DTOUserWorkspaceMembership.optional(),
14
+ designSystem: DTODesignSystem.optional(),
15
+ version: DTODesignSystemVersion.optional(),
16
+ brand: DTOBrand.optional(),
17
+ });
18
+
19
+ export type DTOAppBootstrapDataQuery = z.infer<typeof DTOAppBootstrapDataQuery>;
20
+ export type DTOAppBootstrapDataResponse = z.infer<typeof DTOAppBootstrapDataResponse>;
@@ -0,0 +1 @@
1
+ export * from "./app-bootstrap-data";
@@ -25,8 +25,8 @@ export type DTODesignSystemMembersUpdateResponse = z.infer<typeof DTODesignSyste
25
25
  //
26
26
 
27
27
  export const DTODesignSystemMembersUpdatePayload = z.object({
28
- inviteUserIds: z.string().array(),
29
- removeUserIds: z.string().array(),
28
+ inviteUserIds: z.string().array().optional(),
29
+ removeUserIds: z.string().array().optional(),
30
30
  });
31
31
 
32
32
  export type DTODesignSystemMembersUpdatePayload = z.infer<typeof DTODesignSystemMembersUpdatePayload>;
@@ -1,4 +1,5 @@
1
1
  export * from "./aux";
2
+ export * from "./bff";
2
3
  export * from "./design-systems";
3
4
  export * from "./documentation";
4
5
  export * from "./elements";
@@ -18,5 +18,10 @@ export const DTOUser = z.object({
18
18
  profile: DTOUserProfile,
19
19
  });
20
20
 
21
+ export const DTOUserGetResponse = z.object({
22
+ user: DTOUser,
23
+ });
24
+
21
25
  export type DTOUserProfile = z.infer<typeof DTOUserProfile>;
22
26
  export type DTOUser = z.infer<typeof DTOUser>;
27
+ export type DTOUserGetResponse = z.infer<typeof DTOUserGetResponse>;
@@ -1,5 +1,6 @@
1
1
  export * from "./git";
2
2
  export * from "./integrations";
3
+ export * from "./invitations";
3
4
  export * from "./membership";
4
5
  export * from "./npm-registry";
5
6
  export * from "./workspace";
@@ -0,0 +1,15 @@
1
+ import { WorkspaceRoleSchema } from "@supernova-studio/model";
2
+ import { z } from "zod";
3
+
4
+ export const DTOWorkspaceInvitationInput = z.object({
5
+ email: z.string().email(),
6
+ role: WorkspaceRoleSchema,
7
+ });
8
+
9
+ export const DTOWorkspaceInvitationsListInput = z.object({
10
+ invites: DTOWorkspaceInvitationInput.array().max(100),
11
+ designSystemId: z.string().optional(),
12
+ });
13
+
14
+ export type DTOWorkspaceInvitationInput = z.infer<typeof DTOWorkspaceInvitationInput>;
15
+ export type DTOWorkspaceInvitationsListInput = z.infer<typeof DTOWorkspaceInvitationsListInput>;
@@ -14,3 +14,18 @@ export const DTOWorkspace = z.object({
14
14
  });
15
15
 
16
16
  export type DTOWorkspace = z.infer<typeof DTOWorkspace>;
17
+
18
+ //
19
+ // Write
20
+ //
21
+
22
+ export const DTOWorkspaceCreateInput = z.object({
23
+ name: z.string(),
24
+ });
25
+
26
+ export const DTOWorkspaceCreateResponse = z.object({
27
+ workspace: DTOWorkspace,
28
+ });
29
+
30
+ export type DTOWorkspaceCreateInput = z.infer<typeof DTOWorkspaceCreateInput>;
31
+ export type DTOWorkspaceCreateResponse = z.infer<typeof DTOWorkspaceCreateResponse>;
@@ -0,0 +1,36 @@
1
+ import { z } from "zod";
2
+ import {
3
+ DTODesignSystemCreateInput,
4
+ DTODesignSystemCreateResponse,
5
+ DTODesignSystemMembersUpdatePayload,
6
+ DTODesignSystemMembersUpdateResponse,
7
+ DTODesignSystemsListResponse,
8
+ } from "../dto";
9
+ import { RequestExecutor } from "../transport/request-executor";
10
+
11
+ export class DesignSystemsEndpoint {
12
+ constructor(private readonly requestExecutor: RequestExecutor) {}
13
+
14
+ create(body: DTODesignSystemCreateInput) {
15
+ return this.requestExecutor.json("/design-systems", DTODesignSystemCreateResponse, { method: "POST", body });
16
+ }
17
+
18
+ list(wsId: string) {
19
+ return this.requestExecutor.json(`/workspaces/${wsId}/design-systems`, DTODesignSystemsListResponse);
20
+ }
21
+
22
+ get(dsId: string) {
23
+ return this.requestExecutor.json(`/design-systems/${dsId}`, z.any());
24
+ }
25
+
26
+ delete(dsId: string) {
27
+ return this.requestExecutor.json(`/design-systems/${dsId}`, z.any(), { method: "DELETE" });
28
+ }
29
+
30
+ editMembers(dsId: string, body: DTODesignSystemMembersUpdatePayload) {
31
+ return this.requestExecutor.json(`/design-systems/${dsId}/members`, DTODesignSystemMembersUpdateResponse, {
32
+ method: "POST",
33
+ body,
34
+ });
35
+ }
36
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./design-systems";
2
+ export * from "./users";
3
+ export * from "./workspaces";
@@ -0,0 +1,10 @@
1
+ import { DTOUserGetResponse } from "../dto";
2
+ import { RequestExecutor } from "../transport/request-executor";
3
+
4
+ export class UsersEndpoint {
5
+ constructor(private readonly requestExecutor: RequestExecutor) {}
6
+
7
+ getMe() {
8
+ return this.requestExecutor.json("/users/me", DTOUserGetResponse);
9
+ }
10
+ }
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ import { DTOWorkspaceCreateInput, DTOWorkspaceCreateResponse, DTOWorkspaceInvitationsListInput } from "../dto";
3
+ import { RequestExecutor } from "../transport/request-executor";
4
+
5
+ export class WorkspacesEndpoint {
6
+ constructor(private readonly requestExecutor: RequestExecutor) {}
7
+
8
+ create(body: DTOWorkspaceCreateInput) {
9
+ return this.requestExecutor.json("/workspaces", DTOWorkspaceCreateResponse, {
10
+ method: "POST",
11
+ body: {
12
+ ...body,
13
+ product: "free",
14
+ priceId: "yearly",
15
+ },
16
+ });
17
+ }
18
+
19
+ delete(workspaceId: string) {
20
+ return this.requestExecutor.json(`/workspaces/${workspaceId}`, z.any(), { method: "DELETE" });
21
+ }
22
+
23
+ invite(workspaceId: string, body: DTOWorkspaceInvitationsListInput) {
24
+ return this.requestExecutor.json(`/workspaces/${workspaceId}/members`, z.any(), { method: "POST", body });
25
+ }
26
+ }
package/src/api/index.ts CHANGED
@@ -1,3 +1,6 @@
1
1
  export * from "./conversion";
2
2
  export * from "./dto";
3
+ export * from "./endpoints";
3
4
  export * from "./payloads";
5
+ export * from "./transport";
6
+ export * from "./client";
@@ -0,0 +1,2 @@
1
+ export * from "./request-executor-error";
2
+ export * from "./request-executor";
@@ -0,0 +1,18 @@
1
+ export type RequestExecutorErrorType = "ServerError" | "ResponseParsingError";
2
+
3
+ export class RequestExecutorError extends Error {
4
+ static serverError(endpoint: string, status: number, bodyText: string) {
5
+ return new RequestExecutorError("ServerError", `Endpoint ${endpoint} returned ${status}\n${bodyText}`);
6
+ }
7
+
8
+ static responseParsingError(endpoint: string, cause: Error) {
9
+ return new RequestExecutorError("ResponseParsingError", `Endpoint ${endpoint} returned incompatible JSON`, cause);
10
+ }
11
+
12
+ readonly type: RequestExecutorErrorType;
13
+
14
+ private constructor(type: RequestExecutorErrorType, message: string, cause?: unknown) {
15
+ super(`${type}: ${message}`, { cause });
16
+ this.type = type;
17
+ }
18
+ }
@@ -0,0 +1,72 @@
1
+ import fetch, { RequestInit } from "node-fetch";
2
+ import { z, ZodSchema, ZodTypeDef } from "zod";
3
+ import { RequestExecutorError } from "./request-executor-error";
4
+
5
+ export type RequestExecutorConfig = {
6
+ host: string;
7
+ accessToken?: string;
8
+ };
9
+
10
+ export type RequestExecutorJSONRequest = Omit<RequestInit, "body"> & {
11
+ body?: object;
12
+ };
13
+
14
+ const ResponseWrapper = z.object({
15
+ result: z.record(z.any()),
16
+ });
17
+
18
+ export class RequestExecutor {
19
+ private readonly testServerConfig: RequestExecutorConfig;
20
+
21
+ constructor(testServerConfig: RequestExecutorConfig) {
22
+ this.testServerConfig = testServerConfig;
23
+ }
24
+
25
+ async json<O, I>(path: string, schema: ZodSchema<O, ZodTypeDef, I>, requestInit: RequestExecutorJSONRequest = {}) {
26
+ // Headers
27
+ const defaultHeaders: Record<string, string> = {
28
+ Accept: "application/json",
29
+ };
30
+
31
+ if (requestInit.body) defaultHeaders["Content-Type"] = "application/json";
32
+ if (this.testServerConfig.accessToken) {
33
+ defaultHeaders["Authorization"] = `Bearer ${this.testServerConfig.accessToken}`;
34
+ }
35
+
36
+ // Body
37
+ let body: string | undefined;
38
+ if (requestInit.body && typeof requestInit.body === "object") body = JSON.stringify(requestInit.body);
39
+
40
+ const response = await fetch(this.fullUrl(path), {
41
+ ...requestInit,
42
+ headers: {
43
+ ...requestInit.headers,
44
+ ...defaultHeaders,
45
+ },
46
+ body: body,
47
+ });
48
+
49
+ const endpoint = `${requestInit.method ?? "GET"} ${path}`;
50
+
51
+ if (!response.ok) {
52
+ const bodyString = await response.text();
53
+ throw RequestExecutorError.serverError(endpoint, response.status, bodyString);
54
+ }
55
+
56
+ const wrapperParseResult = ResponseWrapper.safeParse(await response.json());
57
+ if (!wrapperParseResult.success) {
58
+ throw RequestExecutorError.responseParsingError(endpoint, wrapperParseResult.error);
59
+ }
60
+
61
+ const responseParseResult = schema.safeParse(wrapperParseResult.data.result);
62
+ if (!responseParseResult.success) {
63
+ throw RequestExecutorError.responseParsingError(endpoint, responseParseResult.error);
64
+ }
65
+
66
+ return responseParseResult.data;
67
+ }
68
+
69
+ private fullUrl(path: string): string {
70
+ return `https://${this.testServerConfig.host}/api/v2${path}`;
71
+ }
72
+ }