@superblocksteam/sdk 2.0.0-next.13 → 2.0.0-next.130

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.
Files changed (55) hide show
  1. package/dist/application-build.d.mts +12 -0
  2. package/dist/application-build.d.mts.map +1 -0
  3. package/dist/application-build.mjs +113 -0
  4. package/dist/application-build.mjs.map +1 -0
  5. package/dist/cli-replacement/automatic-upgrades.d.ts.map +1 -1
  6. package/dist/cli-replacement/automatic-upgrades.js +19 -5
  7. package/dist/cli-replacement/automatic-upgrades.js.map +1 -1
  8. package/dist/cli-replacement/dev.d.mts.map +1 -1
  9. package/dist/cli-replacement/dev.mjs +7 -0
  10. package/dist/cli-replacement/dev.mjs.map +1 -1
  11. package/dist/client.d.ts +2 -1
  12. package/dist/client.d.ts.map +1 -1
  13. package/dist/client.js +7 -5
  14. package/dist/client.js.map +1 -1
  15. package/dist/dev-utils/dev-server.d.mts.map +1 -1
  16. package/dist/dev-utils/dev-server.mjs +30 -8
  17. package/dist/dev-utils/dev-server.mjs.map +1 -1
  18. package/dist/dev-utils/dev-tracer.d.ts.map +1 -1
  19. package/dist/dev-utils/dev-tracer.js +19 -0
  20. package/dist/dev-utils/dev-tracer.js.map +1 -1
  21. package/dist/dev-utils/vite-plugin-react-transform.d.mts.map +1 -1
  22. package/dist/dev-utils/vite-plugin-react-transform.mjs +1 -0
  23. package/dist/dev-utils/vite-plugin-react-transform.mjs.map +1 -1
  24. package/dist/dev-utils/vite-plugin-sb-cdn.d.mts.map +1 -1
  25. package/dist/dev-utils/vite-plugin-sb-cdn.mjs +28 -7
  26. package/dist/dev-utils/vite-plugin-sb-cdn.mjs.map +1 -1
  27. package/dist/index.d.ts +1 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +1 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/socket/handlers.d.ts +2 -2
  32. package/dist/socket/handlers.d.ts.map +1 -1
  33. package/dist/socket/handlers.js.map +1 -1
  34. package/dist/socket/index.d.ts +1 -11
  35. package/dist/socket/index.d.ts.map +1 -1
  36. package/dist/socket/index.js +11 -43
  37. package/dist/socket/index.js.map +1 -1
  38. package/dist/vite-plugin-inject-sb-ids-transform.d.mts +15 -0
  39. package/dist/vite-plugin-inject-sb-ids-transform.d.mts.map +1 -0
  40. package/dist/vite-plugin-inject-sb-ids-transform.mjs +86 -0
  41. package/dist/vite-plugin-inject-sb-ids-transform.mjs.map +1 -0
  42. package/package.json +16 -7
  43. package/src/application-build.mts +160 -0
  44. package/src/cli-replacement/automatic-upgrades.ts +22 -8
  45. package/src/cli-replacement/dev.mts +10 -0
  46. package/src/client.ts +13 -4
  47. package/src/dev-utils/dev-server.mts +39 -8
  48. package/src/dev-utils/dev-tracer.ts +18 -0
  49. package/src/dev-utils/vite-plugin-react-transform.mts +1 -0
  50. package/src/dev-utils/vite-plugin-sb-cdn.mts +35 -7
  51. package/src/index.ts +2 -0
  52. package/src/socket/handlers.ts +109 -105
  53. package/src/socket/index.ts +21 -101
  54. package/src/vite-plugin-inject-sb-ids-transform.mts +104 -0
  55. package/tsconfig.tsbuildinfo +1 -1
@@ -5,6 +5,7 @@ import type {
5
5
  ApiToVerify,
6
6
  ClientMethods,
7
7
  ServerMethods,
8
+ RequestContextBase,
8
9
  } from "@superblocksteam/shared";
9
10
  import type { Signature } from "@superblocksteam/util";
10
11
 
@@ -29,18 +30,49 @@ export function createRequestHandlers({
29
30
  token: string;
30
31
  agentUrl?: string;
31
32
  }) {
32
- const requestHandlers: MethodHandlers<ClientMethods, ServerMethods, unknown> =
33
- {
34
- v1: {
35
- signing: {
36
- signApplication: [
37
- async ({
33
+ const requestHandlers: MethodHandlers<
34
+ ClientMethods,
35
+ ServerMethods,
36
+ RequestContextBase
37
+ > = {
38
+ v1: {
39
+ signing: {
40
+ signApplication: [
41
+ async ({
42
+ branchName,
43
+ toSign,
44
+ }: {
45
+ branchName: string;
46
+ toSign: AppToSign;
47
+ }) => {
48
+ if (!agentUrl) {
49
+ throw new Error(
50
+ "Agent url not specified. This shouldn't happen.",
51
+ );
52
+ }
53
+ const signature = await signResource({
54
+ agentUrl,
55
+ token: token,
38
56
  branchName,
39
- toSign,
40
- }: {
41
- branchName: string;
42
- toSign: AppToSign;
43
- }) => {
57
+ resource: {
58
+ literal: {
59
+ data: toSign.rootHash,
60
+ },
61
+ },
62
+ });
63
+ return { signature: signature };
64
+ },
65
+ ],
66
+ signApis: [
67
+ async ({
68
+ branchName,
69
+ toSign,
70
+ }: {
71
+ branchName: string;
72
+ toSign: ApiToSign[];
73
+ }) => {
74
+ const signatures: Signature[] = [];
75
+ for (const { apiPb } of toSign) {
44
76
  if (!agentUrl) {
45
77
  throw new Error(
46
78
  "Agent url not specified. This shouldn't happen.",
@@ -50,105 +82,77 @@ export function createRequestHandlers({
50
82
  agentUrl,
51
83
  token: token,
52
84
  branchName,
53
- resource: {
54
- literal: {
55
- data: toSign.rootHash,
56
- },
57
- },
85
+ resource: { api: apiPb as any },
58
86
  });
59
- return { signature: signature };
60
- },
61
- ],
62
- signApis: [
63
- async ({
64
- branchName,
65
- toSign,
66
- }: {
67
- branchName: string;
68
- toSign: ApiToSign[];
69
- }) => {
70
- const signatures: Signature[] = [];
71
- for (const { apiPb } of toSign) {
72
- if (!agentUrl) {
73
- throw new Error(
74
- "Agent url not specified. This shouldn't happen.",
75
- );
76
- }
77
- const signature = await signResource({
78
- agentUrl,
79
- token: token,
80
- branchName,
81
- resource: { api: apiPb as any },
82
- });
83
- signatures.push(signature);
87
+ signatures.push(signature);
88
+ }
89
+ return { signatures };
90
+ },
91
+ ],
92
+ verifyApplication: [
93
+ async ({
94
+ branchName,
95
+ toVerify,
96
+ }: {
97
+ branchName: string;
98
+ toVerify: AppToVerify;
99
+ }) => {
100
+ try {
101
+ if (!agentUrl) {
102
+ throw new Error(
103
+ "Agent url not specified. This shouldn't happen.",
104
+ );
84
105
  }
85
- return { signatures };
86
- },
87
- ],
88
- verifyApplication: [
89
- async ({
90
- branchName,
91
- toVerify,
92
- }: {
93
- branchName: string;
94
- toVerify: AppToVerify;
95
- }) => {
96
- try {
97
- if (!agentUrl) {
98
- throw new Error(
99
- "Agent url not specified. This shouldn't happen.",
100
- );
101
- }
102
- await verifyResources({
103
- agentUrl,
104
- token,
105
- branchName,
106
- resources: [
107
- {
108
- literal: {
109
- data: toVerify.rootHash,
110
- signature: toVerify.signature,
111
- },
106
+ await verifyResources({
107
+ agentUrl,
108
+ token,
109
+ branchName,
110
+ resources: [
111
+ {
112
+ literal: {
113
+ data: toVerify.rootHash,
114
+ signature: toVerify.signature,
112
115
  },
113
- ],
114
- });
115
- return { ok: true };
116
- } catch {
117
- return { ok: false };
118
- }
119
- },
120
- ],
116
+ },
117
+ ],
118
+ });
119
+ return { ok: true };
120
+ } catch {
121
+ return { ok: false };
122
+ }
123
+ },
124
+ ],
121
125
 
122
- verifyApi: [
123
- async ({
124
- branchName,
125
- toVerify,
126
- }: {
127
- branchName: string;
128
- toVerify: ApiToVerify[];
129
- }) => {
130
- try {
131
- if (!agentUrl) {
132
- throw new Error(
133
- "Agent url not specified. This shouldn't happen.",
134
- );
135
- }
136
- await verifyResources({
137
- agentUrl,
138
- token,
139
- branchName,
140
- resources: toVerify.map(({ apiPb }) => ({
141
- api: apiPb as any,
142
- })),
143
- });
144
- return { ok: true };
145
- } catch {
146
- return { ok: false };
126
+ verifyApi: [
127
+ async ({
128
+ branchName,
129
+ toVerify,
130
+ }: {
131
+ branchName: string;
132
+ toVerify: ApiToVerify[];
133
+ }) => {
134
+ try {
135
+ if (!agentUrl) {
136
+ throw new Error(
137
+ "Agent url not specified. This shouldn't happen.",
138
+ );
147
139
  }
148
- },
149
- ],
150
- },
140
+ await verifyResources({
141
+ agentUrl,
142
+ token,
143
+ branchName,
144
+ resources: toVerify.map(({ apiPb }) => ({
145
+ api: apiPb as any,
146
+ })),
147
+ });
148
+ return { ok: true };
149
+ } catch {
150
+ return { ok: false };
151
+ }
152
+ },
153
+ ],
151
154
  },
152
- };
155
+ },
156
+ };
153
157
  return requestHandlers;
154
158
  }
@@ -1,14 +1,16 @@
1
- import { createISocketClient, ISocket } from "@superblocksteam/shared";
2
- import WebSocket from "ws";
1
+ import {
2
+ connectWebSocket,
3
+ createISocketClient,
4
+ ISocketWithClientAuth,
5
+ } from "@superblocksteam/shared";
6
+ import tracer from "../dev-utils/dev-tracer.js";
3
7
  import { createRequestHandlers } from "./handlers.js";
8
+ import type { ISocketClient } from "../types/index.js";
4
9
  import type {
5
- GenericMiddleware,
6
- ISocketClient,
7
- MethodHandlers,
10
+ ClientMethods,
8
11
  RequestContextBase,
9
- SocketTimeouts,
10
- } from "../types/index.js";
11
- import type { ClientMethods, ServerMethods } from "@superblocksteam/shared";
12
+ ServerMethods,
13
+ } from "@superblocksteam/shared";
12
14
 
13
15
  export type StdISocketRPCClient = ISocketClient<ServerMethods>;
14
16
 
@@ -39,101 +41,19 @@ export async function connectToISocketRPCServer({
39
41
  wsUrl.hostname = "127.0.0.1";
40
42
  }
41
43
 
42
- return await connectISocket<ServerMethods, ClientMethods>(
43
- wsUrl.href,
44
- authorization,
45
- requestHandlers,
46
- [],
47
- {
44
+ const ws = await connectWebSocket(wsUrl.href);
45
+ const isocket = new ISocketWithClientAuth<
46
+ ClientMethods,
47
+ ServerMethods,
48
+ RequestContextBase
49
+ >(ws, authorization, requestHandlers, [], tracer, {
50
+ timeouts: {
48
51
  connectionTimeoutInSeconds: 6 * 60, // 6 minutes
49
52
  noResponseTimeoutInSeconds: 5 * 60, // 5 minutes
50
53
  },
51
- );
52
- }
53
-
54
- // a subclass of ISocket that sends an auth token on the first request
55
- // this is useful for client-side sockets that need to authenticate
56
- // TODO(george): if we start using this for long-lived connections, we should add a way to refresh the token
57
- export class ISocketWithClientAuth<
58
- ImplementedMethods,
59
- CallableMethods,
60
- RequestContext extends RequestContextBase,
61
- > extends ISocket<ImplementedMethods, CallableMethods, RequestContext> {
62
- private readonly authorization?: string;
63
- private hasSentAuth = false;
64
-
65
- constructor(
66
- ws: WebSocket,
67
- authorization: string | undefined,
68
- requestHandlers: MethodHandlers<
69
- ImplementedMethods,
70
- CallableMethods,
71
- RequestContext
72
- >,
73
- globalMiddlewares: GenericMiddleware<CallableMethods, RequestContext>[],
74
- timeouts?: SocketTimeouts,
75
- ) {
76
- super(ws, requestHandlers, globalMiddlewares, timeouts);
77
- this.authorization = authorization;
78
- }
79
-
80
- // override `request` from the base class to send `authorization` when appropriate
81
- async request<Params, Result>(
82
- method: string,
83
- params: Params,
84
- ): Promise<Result> {
85
- // only send `authorization` on the first request
86
- const authorization = this.hasSentAuth ? undefined : this.authorization;
87
- const result = await super.request<Params, Result>(
88
- method,
89
- params,
90
- authorization,
91
- );
92
- this.hasSentAuth = true;
93
- return result;
94
- }
95
- }
96
-
97
- export async function connectISocket<
98
- CallableMethods,
99
- ImplementedMethods,
100
- RequestContext extends RequestContextBase = RequestContextBase,
101
- >(
102
- wsUrl: string,
103
- authorization: string | undefined,
104
- requestHandlers: MethodHandlers<
105
- ImplementedMethods,
106
- CallableMethods,
107
- RequestContext
108
- >,
109
- globalMiddlewares: GenericMiddleware<CallableMethods, RequestContext>[],
110
- timeouts?: SocketTimeouts,
111
- ): Promise<ISocketClient<CallableMethods>> {
112
- const ws = await connectWebSocket(wsUrl);
113
- const isocket = new ISocketWithClientAuth(
114
- ws,
115
- authorization,
116
- requestHandlers,
117
- globalMiddlewares,
118
- timeouts,
119
- );
120
- return createISocketClient(isocket);
121
- }
122
-
123
- export function connectWebSocket(wsUrl: string): Promise<WebSocket> {
124
- return new Promise((resolve, reject) => {
125
- const ws = new WebSocket(wsUrl);
126
-
127
- ws.addEventListener("open", () => {
128
- // Resolve the promise with the WebSocket instance when the connection is open
129
- resolve(ws);
130
- });
131
-
132
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
133
- // @ts-ignore
134
- ws.addEventListener("error", (error: Error) => {
135
- // Reject the promise if there's an error
136
- reject(error);
137
- });
54
+ onClose: () => {
55
+ // Noop
56
+ },
138
57
  });
58
+ return createISocketClient(isocket);
139
59
  }
@@ -0,0 +1,104 @@
1
+ import path from "node:path";
2
+ import babelGenerate from "@babel/generator";
3
+ import { parse } from "@babel/parser";
4
+ import {
5
+ supplementElementIds,
6
+ generateRootSource,
7
+ } from "@superblocksteam/vite-plugin-file-sync";
8
+ import { yellow, red } from "colorette";
9
+ import fs from "fs-extra";
10
+ import { createLogger } from "vite";
11
+ import { getLogger } from "./dev-utils/dev-logger.mjs";
12
+ import type { HydratedRoute } from "@superblocksteam/vite-plugin-file-sync";
13
+ import type { Logger, Plugin } from "vite";
14
+
15
+ const routesFileBaseName = "routes.json";
16
+
17
+ /**
18
+ * Creates a Vite plugin that injects Superblocks IDs into the application.
19
+ * This will primarily be used during builds, as the dev server leverages the
20
+ * file sync manager to inject and keep the IDs up to date.
21
+ *
22
+ * Features:
23
+ * - Injects the root component with the routes data
24
+ * - Injects Superblocks IDs into all components
25
+ *
26
+ * @param root - The root directory of the application
27
+ * @returns A Vite plugin that injects Superblocks IDs into the application's components
28
+ */
29
+ export async function injectSuperblocksIdsPlugin(root: string) {
30
+ const viteLogger = createLogger();
31
+ const logger = getLogger();
32
+ viteLogger.info = logger.info;
33
+ viteLogger.warn = (msg: string) => {
34
+ logger.warn(yellow(msg));
35
+ };
36
+ viteLogger.warnOnce = (msg: string) => {
37
+ logger.warn(yellow(msg));
38
+ };
39
+ viteLogger.error = (msg: string) => {
40
+ logger.error(red(msg));
41
+ };
42
+
43
+ viteLogger.clearScreen = () => {};
44
+
45
+ const routes: HydratedRoute[] = await getRoutes(root, viteLogger);
46
+
47
+ return {
48
+ name: "sb-inject-superblocks-ids",
49
+ enforce: "pre",
50
+
51
+ transform(code, id) {
52
+ const relativePath = path.relative(root, id);
53
+
54
+ if (relativePath === "root.tsx") {
55
+ const source = generateRootSource(code, routes);
56
+ return {
57
+ code: source,
58
+ map: null,
59
+ };
60
+ } else if (id.endsWith(".tsx")) {
61
+ const ast = parse(code, {
62
+ sourceType: "module",
63
+ sourceFilename: id,
64
+ plugins: ["jsx"],
65
+ });
66
+
67
+ supplementElementIds({
68
+ fileName: id,
69
+ ast,
70
+ shouldModifyAst: true,
71
+ });
72
+
73
+ const result = babelGenerate.default(ast);
74
+ return result.code;
75
+ }
76
+
77
+ return code;
78
+ },
79
+ } as Plugin;
80
+ }
81
+
82
+ async function getRoutes(root: string, logger: Logger) {
83
+ const routesFile = path.join(root, routesFileBaseName);
84
+ if (!(await fs.pathExists(routesFile))) {
85
+ logger.warn(`routes file not found at expected location: ${routesFile}`);
86
+ return [];
87
+ }
88
+
89
+ try {
90
+ const routesData = await fs.readFile(routesFile, "utf-8");
91
+ const routes = JSON.parse(routesData) as Record<string, { file: string }>;
92
+
93
+ return Object.entries(routes).map(([path, { file }]) => ({
94
+ path,
95
+ component: file,
96
+ }));
97
+ } catch (err) {
98
+ logger.error(
99
+ `error reading routes file: ${routesFile}. error=[${JSON.stringify(err)}]`,
100
+ );
101
+ }
102
+
103
+ return [];
104
+ }