@superblocksteam/sdk 2.0.3-next.174 → 2.0.3-next.176
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/dist/application-build.d.mts +12 -0
- package/dist/application-build.d.mts.map +1 -0
- package/dist/application-build.mjs +113 -0
- package/dist/application-build.mjs.map +1 -0
- package/dist/cli-replacement/automatic-upgrades.d.ts.map +1 -1
- package/dist/cli-replacement/automatic-upgrades.js +22 -6
- package/dist/cli-replacement/automatic-upgrades.js.map +1 -1
- package/dist/cli-replacement/dev.d.mts.map +1 -1
- package/dist/cli-replacement/dev.mjs +7 -0
- package/dist/cli-replacement/dev.mjs.map +1 -1
- package/dist/client.d.ts +2 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +7 -5
- package/dist/client.js.map +1 -1
- package/dist/dev-utils/dev-server.d.mts.map +1 -1
- package/dist/dev-utils/dev-server.mjs +30 -8
- package/dist/dev-utils/dev-server.mjs.map +1 -1
- package/dist/dev-utils/dev-tracer.d.ts.map +1 -1
- package/dist/dev-utils/dev-tracer.js +33 -1
- package/dist/dev-utils/dev-tracer.js.map +1 -1
- package/dist/dev-utils/vite-plugin-react-transform.d.mts.map +1 -1
- package/dist/dev-utils/vite-plugin-react-transform.mjs +1 -0
- package/dist/dev-utils/vite-plugin-react-transform.mjs.map +1 -1
- package/dist/dev-utils/vite-plugin-sb-cdn.d.mts.map +1 -1
- package/dist/dev-utils/vite-plugin-sb-cdn.mjs +34 -9
- package/dist/dev-utils/vite-plugin-sb-cdn.mjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/socket/handlers.d.ts +2 -2
- package/dist/socket/handlers.d.ts.map +1 -1
- package/dist/socket/handlers.js.map +1 -1
- package/dist/socket/index.d.ts +1 -11
- package/dist/socket/index.d.ts.map +1 -1
- package/dist/socket/index.js +11 -43
- package/dist/socket/index.js.map +1 -1
- package/dist/vite-plugin-inject-sb-ids-transform.d.mts +15 -0
- package/dist/vite-plugin-inject-sb-ids-transform.d.mts.map +1 -0
- package/dist/vite-plugin-inject-sb-ids-transform.mjs +86 -0
- package/dist/vite-plugin-inject-sb-ids-transform.mjs.map +1 -0
- package/package.json +16 -5
- package/src/application-build.mts +160 -0
- package/src/cli-replacement/automatic-upgrades.ts +30 -9
- package/src/cli-replacement/dev.mts +10 -0
- package/src/client.ts +13 -4
- package/src/dev-utils/dev-server.mts +39 -8
- package/src/dev-utils/dev-tracer.ts +35 -1
- package/src/dev-utils/vite-plugin-react-transform.mts +1 -0
- package/src/dev-utils/vite-plugin-sb-cdn.mts +45 -11
- package/src/index.ts +2 -0
- package/src/socket/handlers.ts +109 -105
- package/src/socket/index.ts +21 -101
- package/src/vite-plugin-inject-sb-ids-transform.mts +104 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -469,6 +469,16 @@ async function extractNeededExports(
|
|
|
469
469
|
}
|
|
470
470
|
}
|
|
471
471
|
|
|
472
|
+
const wellKnownPackages = new Map<string, string>([
|
|
473
|
+
["react", "https://esm.sh/react@18.2.0"],
|
|
474
|
+
["react-dom", "https://esm.sh/react-dom@18.2.0"],
|
|
475
|
+
["react/jsx-runtime", "https://esm.sh/react@18.2.0/jsx-runtime"],
|
|
476
|
+
["react/jsx-dev-runtime", "https://esm.sh/react@18.2.0/jsx-dev-runtime"],
|
|
477
|
+
]);
|
|
478
|
+
|
|
479
|
+
const react18CdnUrl = "https://esm.sh/react@18.2.0";
|
|
480
|
+
const reactDom18CdnUrl = "https://esm.sh/react-dom@18.2.0";
|
|
481
|
+
|
|
472
482
|
/**
|
|
473
483
|
* Creates a Vite plugin that injects an import map into the HTML.
|
|
474
484
|
* It analyzes remote modules to find their imports and maps them to local Vite modules.
|
|
@@ -558,7 +568,14 @@ export async function superblocksCdnPlugin(
|
|
|
558
568
|
const modulePreloadData = modulesToPreload.get(importUrl);
|
|
559
569
|
if (modulePreloadData) {
|
|
560
570
|
modulePreloadData.content = content;
|
|
561
|
-
|
|
571
|
+
|
|
572
|
+
// Don't calculate integrity for react 18 CDN modules
|
|
573
|
+
if (
|
|
574
|
+
!importUrl.startsWith(react18CdnUrl) &&
|
|
575
|
+
!importUrl.startsWith(reactDom18CdnUrl)
|
|
576
|
+
) {
|
|
577
|
+
modulePreloadData.integrity = await calculateIntegrity(binary);
|
|
578
|
+
}
|
|
562
579
|
}
|
|
563
580
|
|
|
564
581
|
// Process all discovered modules and add them to the preload list
|
|
@@ -570,8 +587,15 @@ export async function superblocksCdnPlugin(
|
|
|
570
587
|
if (moduleUrl.startsWith(baseUrl)) {
|
|
571
588
|
// Add the module to preload if not already added
|
|
572
589
|
if (!modulesToPreload.has(moduleUrl)) {
|
|
573
|
-
// Calculate the integrity hash
|
|
574
|
-
|
|
590
|
+
// Calculate the integrity hash for non-react 18 CDN modules
|
|
591
|
+
let integrity: string | undefined;
|
|
592
|
+
if (
|
|
593
|
+
!moduleUrl.startsWith(react18CdnUrl) &&
|
|
594
|
+
!moduleUrl.startsWith(reactDom18CdnUrl)
|
|
595
|
+
) {
|
|
596
|
+
integrity = await calculateIntegrity(moduleData.binary);
|
|
597
|
+
}
|
|
598
|
+
|
|
575
599
|
modulesToPreload.set(moduleUrl, {
|
|
576
600
|
url: moduleUrl,
|
|
577
601
|
content: moduleData.content,
|
|
@@ -669,9 +693,6 @@ export async function superblocksCdnPlugin(
|
|
|
669
693
|
{
|
|
670
694
|
name: "vite-plugin-superblocks-cdn",
|
|
671
695
|
|
|
672
|
-
// run before Vite's module resolution
|
|
673
|
-
enforce: "pre",
|
|
674
|
-
|
|
675
696
|
/**
|
|
676
697
|
* Configure Vite to properly handle CDN modules
|
|
677
698
|
* - Exclude CDN modules from optimization
|
|
@@ -735,6 +756,8 @@ export async function superblocksCdnPlugin(
|
|
|
735
756
|
|
|
736
757
|
cdnDependencyChunks.set(dep, resolved);
|
|
737
758
|
}
|
|
759
|
+
|
|
760
|
+
debug("dependencies of CDN modules", cdnDependencyChunks);
|
|
738
761
|
},
|
|
739
762
|
|
|
740
763
|
resolveId(id, importer) {
|
|
@@ -762,6 +785,8 @@ export async function superblocksCdnPlugin(
|
|
|
762
785
|
* These modules will be loaded from CDN at runtime, so we return empty content
|
|
763
786
|
*/
|
|
764
787
|
async load(id: string) {
|
|
788
|
+
debug("loading module", id);
|
|
789
|
+
|
|
765
790
|
if (id.startsWith("cdn:")) {
|
|
766
791
|
debug(`Providing empty module for CDN import: ${id}`);
|
|
767
792
|
return "";
|
|
@@ -792,9 +817,13 @@ export async function superblocksCdnPlugin(
|
|
|
792
817
|
}
|
|
793
818
|
}
|
|
794
819
|
}
|
|
820
|
+
|
|
821
|
+
debug({ moduleToChunkMap, importToChunkMap });
|
|
795
822
|
},
|
|
796
823
|
|
|
797
824
|
async transformIndexHtml(html, { server }) {
|
|
825
|
+
debug("transforming index.html");
|
|
826
|
+
|
|
798
827
|
const isDevMode = !!server;
|
|
799
828
|
|
|
800
829
|
// Create the base import map with explicit ordering for proper resolution
|
|
@@ -802,10 +831,12 @@ export async function superblocksCdnPlugin(
|
|
|
802
831
|
const importMap = {
|
|
803
832
|
imports: {
|
|
804
833
|
...Object.fromEntries(
|
|
805
|
-
Object.entries(initialImportMap).map(([module, url]) =>
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
834
|
+
Object.entries(initialImportMap).map(([module, url]) => {
|
|
835
|
+
if (wellKnownPackages.has(module)) {
|
|
836
|
+
return [module, wellKnownPackages.get(module)!];
|
|
837
|
+
}
|
|
838
|
+
return [`${isDevMode ? "/@id/" : ""}cdn:${module}`, url];
|
|
839
|
+
}),
|
|
809
840
|
),
|
|
810
841
|
},
|
|
811
842
|
// Scopes apply to specific URL prefixes for more granular control
|
|
@@ -851,7 +882,6 @@ export async function superblocksCdnPlugin(
|
|
|
851
882
|
|
|
852
883
|
// Get the asset URL as it would be served to the browser
|
|
853
884
|
// For Vite to correctly resolve this module in the browser
|
|
854
|
-
|
|
855
885
|
if (resolvedChunkUrl.startsWith("/")) {
|
|
856
886
|
// For paths starting with /, they're already root-relative
|
|
857
887
|
// Make sure we don't duplicate the base path
|
|
@@ -871,6 +901,8 @@ export async function superblocksCdnPlugin(
|
|
|
871
901
|
const chunkPath = importToChunkMap.get(moduleName);
|
|
872
902
|
if (chunkPath) {
|
|
873
903
|
dependencyChunkUrl = `${base}${chunkPath}`;
|
|
904
|
+
} else if (wellKnownPackages.has(moduleName)) {
|
|
905
|
+
dependencyChunkUrl = wellKnownPackages.get(moduleName)!;
|
|
874
906
|
}
|
|
875
907
|
}
|
|
876
908
|
|
|
@@ -884,6 +916,8 @@ export async function superblocksCdnPlugin(
|
|
|
884
916
|
debug(`Resolved %s to %s`, moduleName, dependencyChunkUrl);
|
|
885
917
|
// Store in the import map scope
|
|
886
918
|
importMap.scopes[baseUrl][moduleName] = dependencyChunkUrl;
|
|
919
|
+
// Also add to main imports for external dependencies
|
|
920
|
+
importMap.imports[moduleName] = dependencyChunkUrl;
|
|
887
921
|
}
|
|
888
922
|
}
|
|
889
923
|
}
|
package/src/index.ts
CHANGED
package/src/socket/handlers.ts
CHANGED
|
@@ -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<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
});
|
|
119
|
+
return { ok: true };
|
|
120
|
+
} catch {
|
|
121
|
+
return { ok: false };
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
],
|
|
121
125
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
}
|
package/src/socket/index.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
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
|
-
|
|
6
|
-
ISocketClient,
|
|
7
|
-
MethodHandlers,
|
|
10
|
+
ClientMethods,
|
|
8
11
|
RequestContextBase,
|
|
9
|
-
|
|
10
|
-
} from "
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
+
}
|