@superblocksteam/sdk 2.0.99 → 2.0.100-next.0
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/.turbo/turbo-build.log +1 -1
- package/dist/cli-replacement/dev.d.mts.map +1 -1
- package/dist/cli-replacement/dev.mjs +64 -20
- package/dist/cli-replacement/dev.mjs.map +1 -1
- package/dist/cli-replacement/init.d.ts.map +1 -1
- package/dist/cli-replacement/init.js +1 -0
- package/dist/cli-replacement/init.js.map +1 -1
- package/dist/client.d.ts +8 -21
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +36 -5
- package/dist/client.js.map +1 -1
- package/dist/collect-sdk-apis.d.mts +10 -6
- package/dist/collect-sdk-apis.d.mts.map +1 -1
- package/dist/collect-sdk-apis.mjs +20 -5
- package/dist/collect-sdk-apis.mjs.map +1 -1
- package/dist/collect-sdk-apis.test.mjs +53 -4
- package/dist/collect-sdk-apis.test.mjs.map +1 -1
- package/dist/dbfs/client.d.ts +2 -0
- package/dist/dbfs/client.d.ts.map +1 -1
- package/dist/dbfs/client.js +43 -17
- package/dist/dbfs/client.js.map +1 -1
- package/dist/dbfs/client.test.d.ts +2 -0
- package/dist/dbfs/client.test.d.ts.map +1 -0
- package/dist/dbfs/client.test.js +81 -0
- package/dist/dbfs/client.test.js.map +1 -0
- package/dist/extract-api-integrations.d.mts +17 -0
- package/dist/extract-api-integrations.d.mts.map +1 -0
- package/dist/extract-api-integrations.mjs +233 -0
- package/dist/extract-api-integrations.mjs.map +1 -0
- package/dist/extract-api-integrations.test.d.mts +2 -0
- package/dist/extract-api-integrations.test.d.mts.map +1 -0
- package/dist/extract-api-integrations.test.mjs +97 -0
- package/dist/extract-api-integrations.test.mjs.map +1 -0
- package/dist/sdk.d.ts +13 -6
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +13 -6
- package/dist/sdk.js.map +1 -1
- package/dist/sdk.test.d.ts +2 -0
- package/dist/sdk.test.d.ts.map +1 -0
- package/dist/sdk.test.js +71 -0
- package/dist/sdk.test.js.map +1 -0
- package/dist/telemetry/index.d.ts.map +1 -1
- package/dist/telemetry/index.js +9 -2
- package/dist/telemetry/index.js.map +1 -1
- package/dist/telemetry/logging.d.ts.map +1 -1
- package/dist/telemetry/logging.js +1 -0
- package/dist/telemetry/logging.js.map +1 -1
- package/dist/version-control.d.mts +5 -3
- package/dist/version-control.d.mts.map +1 -1
- package/dist/version-control.mjs +18 -10
- package/dist/version-control.mjs.map +1 -1
- package/dist/vite-plugin-generate-api-build-manifest.d.mts.map +1 -1
- package/dist/vite-plugin-generate-api-build-manifest.mjs.map +1 -1
- package/package.json +6 -6
- package/src/cli-replacement/dev.mts +73 -24
- package/src/cli-replacement/init.ts +1 -0
- package/src/client.ts +53 -22
- package/src/collect-sdk-apis.mts +30 -6
- package/src/collect-sdk-apis.test.mts +58 -4
- package/src/dbfs/client.test.ts +116 -0
- package/src/dbfs/client.ts +60 -21
- package/src/extract-api-integrations.mts +345 -0
- package/src/extract-api-integrations.test.mts +114 -0
- package/src/sdk.test.ts +106 -0
- package/src/sdk.ts +40 -3
- package/src/telemetry/index.ts +13 -2
- package/src/telemetry/logging.ts +1 -0
- package/src/version-control.mts +23 -8
- package/src/vite-plugin-generate-api-build-manifest.mts +7 -1
- package/test/version-control.test.mts +81 -1
- package/tsconfig.tsbuildinfo +1 -1
package/src/client.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { Bucketeer, FileDescriptor } from "@superblocksteam/bucketeer-sdk";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
CommitType,
|
|
6
|
+
ExportViewMode,
|
|
7
|
+
type GetApplicationCommitsResponseBody,
|
|
8
|
+
type GetPublicOrganizationSummaryResponseBody,
|
|
9
|
+
} from "@superblocksteam/shared";
|
|
5
10
|
import {
|
|
6
11
|
COMPONENT_EVENT_HEADER,
|
|
7
12
|
ComponentEvent,
|
|
@@ -72,6 +77,7 @@ export interface ApplicationWrapper {
|
|
|
72
77
|
|
|
73
78
|
export interface MultiPageApplicationWrapper {
|
|
74
79
|
application: Record<string, any>;
|
|
80
|
+
deployedCommitId?: string | null;
|
|
75
81
|
pages: Page[];
|
|
76
82
|
apis: Record<string, any>[];
|
|
77
83
|
}
|
|
@@ -116,25 +122,7 @@ type Branch = {
|
|
|
116
122
|
|
|
117
123
|
type ResponseWithMeta<T> = { responseMeta: unknown; data: T };
|
|
118
124
|
|
|
119
|
-
|
|
120
|
-
commitMessage: string;
|
|
121
|
-
committer: {
|
|
122
|
-
name?: string;
|
|
123
|
-
email: string;
|
|
124
|
-
};
|
|
125
|
-
commitId: string;
|
|
126
|
-
commitDate: number;
|
|
127
|
-
branch?: string;
|
|
128
|
-
autosave?: boolean;
|
|
129
|
-
tag: string;
|
|
130
|
-
externalCommitId?: string | null;
|
|
131
|
-
externalCommitDate?: number | null;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export interface GetCommitsResponseBody {
|
|
135
|
-
autosaves: CommitDto[];
|
|
136
|
-
commits: CommitDto[];
|
|
137
|
-
}
|
|
125
|
+
export type GetCommitsResponseBody = GetApplicationCommitsResponseBody;
|
|
138
126
|
|
|
139
127
|
enum ResourceType {
|
|
140
128
|
APPLICATION = "APPLICATION",
|
|
@@ -959,6 +947,45 @@ export async function fetchCurrentUser(
|
|
|
959
947
|
}
|
|
960
948
|
}
|
|
961
949
|
|
|
950
|
+
export async function fetchOrganizationSummary(
|
|
951
|
+
cliVersion: string,
|
|
952
|
+
token: string,
|
|
953
|
+
superblocksBaseUrl: string,
|
|
954
|
+
organizationId: string,
|
|
955
|
+
): Promise<GetPublicOrganizationSummaryResponseBody> {
|
|
956
|
+
try {
|
|
957
|
+
const config: AxiosRequestConfig = {
|
|
958
|
+
method: "get",
|
|
959
|
+
url: new URL(
|
|
960
|
+
`${BASE_SERVER_PUBLIC_API_URL_v2}/organizations/${organizationId}/summary`,
|
|
961
|
+
superblocksBaseUrl,
|
|
962
|
+
).toString(),
|
|
963
|
+
headers: {
|
|
964
|
+
Authorization: "Bearer " + token,
|
|
965
|
+
[CLI_VERSION_HEADER]: cliVersion,
|
|
966
|
+
},
|
|
967
|
+
};
|
|
968
|
+
const response = await axios(config);
|
|
969
|
+
return response.data.data as GetPublicOrganizationSummaryResponseBody;
|
|
970
|
+
} catch (e: any) {
|
|
971
|
+
if (axios.isAxiosError(e) && e.response?.status === 404) {
|
|
972
|
+
throw new NotFoundError(`Organization ${organizationId} was not found`);
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
let message: string;
|
|
976
|
+
if (e instanceof AxiosError) {
|
|
977
|
+
message =
|
|
978
|
+
(e.response?.data?.responseMeta?.message as string) ??
|
|
979
|
+
JSON.stringify(e.response?.data) ??
|
|
980
|
+
e.response?.statusText ??
|
|
981
|
+
e?.message;
|
|
982
|
+
} else {
|
|
983
|
+
message = `${e?.message ? e?.message : e}`;
|
|
984
|
+
}
|
|
985
|
+
throw new Error(`Could not fetch organization summary: ${message}`);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
|
|
962
989
|
const createSocketConnectionIfNeeded = async (
|
|
963
990
|
cliVersion: string,
|
|
964
991
|
token: string,
|
|
@@ -1381,6 +1408,7 @@ export async function fetchApplicationCommits({
|
|
|
1381
1408
|
cliVersion,
|
|
1382
1409
|
applicationId,
|
|
1383
1410
|
branch,
|
|
1411
|
+
commitType = CommitType.COMMIT,
|
|
1384
1412
|
token,
|
|
1385
1413
|
superblocksBaseUrl,
|
|
1386
1414
|
injectedHeaders = {},
|
|
@@ -1390,6 +1418,7 @@ export async function fetchApplicationCommits({
|
|
|
1390
1418
|
cliVersion: string;
|
|
1391
1419
|
applicationId: string;
|
|
1392
1420
|
branch?: string;
|
|
1421
|
+
commitType?: CommitType;
|
|
1393
1422
|
token: string;
|
|
1394
1423
|
superblocksBaseUrl: string;
|
|
1395
1424
|
injectedHeaders: Record<string, string>;
|
|
@@ -1409,7 +1438,7 @@ export async function fetchApplicationCommits({
|
|
|
1409
1438
|
superblocksBaseUrl,
|
|
1410
1439
|
);
|
|
1411
1440
|
serverURL.search = new URLSearchParams({
|
|
1412
|
-
commitType
|
|
1441
|
+
commitType,
|
|
1413
1442
|
...(limit ? { limit: limit.toString() } : {}),
|
|
1414
1443
|
...(offset ? { offset: offset.toString() } : {}),
|
|
1415
1444
|
}).toString();
|
|
@@ -1437,6 +1466,7 @@ export async function fetchApiCommits({
|
|
|
1437
1466
|
cliVersion,
|
|
1438
1467
|
applicationId,
|
|
1439
1468
|
branch,
|
|
1469
|
+
commitType = CommitType.COMMIT,
|
|
1440
1470
|
token,
|
|
1441
1471
|
superblocksBaseUrl,
|
|
1442
1472
|
injectedHeaders = {},
|
|
@@ -1446,6 +1476,7 @@ export async function fetchApiCommits({
|
|
|
1446
1476
|
cliVersion: string;
|
|
1447
1477
|
applicationId: string;
|
|
1448
1478
|
branch?: string;
|
|
1479
|
+
commitType?: CommitType;
|
|
1449
1480
|
token: string;
|
|
1450
1481
|
superblocksBaseUrl: string;
|
|
1451
1482
|
injectedHeaders: Record<string, string>;
|
|
@@ -1465,7 +1496,7 @@ export async function fetchApiCommits({
|
|
|
1465
1496
|
superblocksBaseUrl,
|
|
1466
1497
|
);
|
|
1467
1498
|
serverURL.search = new URLSearchParams({
|
|
1468
|
-
commitType
|
|
1499
|
+
commitType,
|
|
1469
1500
|
...(limit ? { limit: limit.toString() } : {}),
|
|
1470
1501
|
...(offset ? { offset: offset.toString() } : {}),
|
|
1471
1502
|
}).toString();
|
package/src/collect-sdk-apis.mts
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import {
|
|
3
|
+
extractIntegrationsFromSource,
|
|
4
|
+
type IntegrationInfo,
|
|
5
|
+
} from "./extract-api-integrations.mjs";
|
|
2
6
|
import { parseSdkRegistry } from "./parse-sdk-registry.mjs";
|
|
3
7
|
|
|
4
|
-
export type
|
|
8
|
+
export type SdkApiEntry = {
|
|
9
|
+
entryPoint: string;
|
|
10
|
+
integrations?: IntegrationInfo[];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type SdkApisResult = Record<string, SdkApiEntry>;
|
|
5
14
|
|
|
6
15
|
export type CollectSdkApisFs = {
|
|
7
16
|
pathExists: (p: string) => Promise<boolean>;
|
|
@@ -9,13 +18,14 @@ export type CollectSdkApisFs = {
|
|
|
9
18
|
};
|
|
10
19
|
|
|
11
20
|
/**
|
|
12
|
-
* Collect SDK API entry points from the app's registry
|
|
13
|
-
* Keys match Object.keys(registry.default) so
|
|
14
|
-
* and deployed modes.
|
|
21
|
+
* Collect SDK API entry points and declared integrations from the app's registry
|
|
22
|
+
* at server/apis/index.ts. Keys match Object.keys(registry.default) so
|
|
23
|
+
* useApi("Key") works in both edit and deployed modes.
|
|
15
24
|
*
|
|
16
25
|
* @param root - App root directory
|
|
17
26
|
* @param fs - File system operations (pathExists, readFile)
|
|
18
|
-
* @returns Map of API name → { entryPoint } or empty object
|
|
27
|
+
* @returns Map of API name → { entryPoint, integrations? } or empty object
|
|
28
|
+
* if no registry exists
|
|
19
29
|
*/
|
|
20
30
|
export async function collectSdkApisFromRegistry(
|
|
21
31
|
root: string,
|
|
@@ -37,7 +47,21 @@ export async function collectSdkApisFromRegistry(
|
|
|
37
47
|
|
|
38
48
|
const sdkApis: SdkApisResult = {};
|
|
39
49
|
for (const [apiName, entryPoint] of keyToPath) {
|
|
40
|
-
|
|
50
|
+
const entry: SdkApiEntry = { entryPoint };
|
|
51
|
+
const absolutePath = path.join(root, entryPoint);
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const source = await fs.readFile(absolutePath, "utf-8");
|
|
55
|
+
const integrations = extractIntegrationsFromSource(source);
|
|
56
|
+
if (integrations.length > 0) {
|
|
57
|
+
entry.integrations = integrations;
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
// Integration extraction is best-effort. If a source file cannot be read,
|
|
61
|
+
// still emit the entry point so SDK execution continues to work.
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
sdkApis[apiName] = entry;
|
|
41
65
|
}
|
|
42
66
|
return sdkApis;
|
|
43
67
|
}
|
|
@@ -44,13 +44,30 @@ import CreateOrder from './CreateOrder/api.js';
|
|
|
44
44
|
const apis = { GetUsers, CreateOrder } as const;
|
|
45
45
|
export default apis;
|
|
46
46
|
`;
|
|
47
|
+
const readFile = vi.fn(async (filePath: string) => {
|
|
48
|
+
const rel = path.relative(root, filePath).replace(/\\/g, "/");
|
|
49
|
+
if (rel === "server/apis/index.ts") {
|
|
50
|
+
return registryContent;
|
|
51
|
+
}
|
|
52
|
+
if (rel === "server/apis/GetUsers/api.ts") {
|
|
53
|
+
return `export default api({ integrations: { db: postgres("pg-1") } });`;
|
|
54
|
+
}
|
|
55
|
+
if (rel === "server/apis/CreateOrder/api.ts") {
|
|
56
|
+
return `export default api({});`;
|
|
57
|
+
}
|
|
58
|
+
throw new Error(`Unexpected read: ${rel}`);
|
|
59
|
+
});
|
|
60
|
+
|
|
47
61
|
const result = await collectSdkApisFromRegistry(root, {
|
|
48
62
|
pathExists,
|
|
49
|
-
readFile
|
|
63
|
+
readFile,
|
|
50
64
|
});
|
|
51
65
|
|
|
52
66
|
expect(result).toEqual({
|
|
53
|
-
GetUsers: {
|
|
67
|
+
GetUsers: {
|
|
68
|
+
entryPoint: "server/apis/GetUsers/api.ts",
|
|
69
|
+
integrations: [{ key: "db", pluginId: "postgres", id: "pg-1" }],
|
|
70
|
+
},
|
|
54
71
|
CreateOrder: { entryPoint: "server/apis/CreateOrder/api.ts" },
|
|
55
72
|
});
|
|
56
73
|
});
|
|
@@ -61,13 +78,50 @@ import GetUsers from './v2/GetUsers/api.js';
|
|
|
61
78
|
const apis = { GetUsers } as const;
|
|
62
79
|
export default apis;
|
|
63
80
|
`;
|
|
81
|
+
const readFile = vi.fn(async (filePath: string) => {
|
|
82
|
+
const rel = path.relative(root, filePath).replace(/\\/g, "/");
|
|
83
|
+
if (rel === "server/apis/index.ts") {
|
|
84
|
+
return registryContent;
|
|
85
|
+
}
|
|
86
|
+
if (rel === "server/apis/v2/GetUsers/api.ts") {
|
|
87
|
+
return `const DB = postgres("pg-2"); export default api({ integrations: { db: DB } });`;
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`Unexpected read: ${rel}`);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const result = await collectSdkApisFromRegistry(root, {
|
|
93
|
+
pathExists,
|
|
94
|
+
readFile,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
expect(result).toEqual({
|
|
98
|
+
GetUsers: {
|
|
99
|
+
entryPoint: "server/apis/v2/GetUsers/api.ts",
|
|
100
|
+
integrations: [{ key: "db", pluginId: "postgres", id: "pg-2" }],
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("keeps entryPoint when integration extraction fails", async () => {
|
|
106
|
+
const registryContent = `
|
|
107
|
+
import GetUsers from './GetUsers/api.js';
|
|
108
|
+
export default { GetUsers };
|
|
109
|
+
`;
|
|
110
|
+
const readFile = vi.fn(async (filePath: string) => {
|
|
111
|
+
const rel = path.relative(root, filePath).replace(/\\/g, "/");
|
|
112
|
+
if (rel === "server/apis/index.ts") {
|
|
113
|
+
return registryContent;
|
|
114
|
+
}
|
|
115
|
+
throw new Error("source unreadable");
|
|
116
|
+
});
|
|
117
|
+
|
|
64
118
|
const result = await collectSdkApisFromRegistry(root, {
|
|
65
119
|
pathExists,
|
|
66
|
-
readFile
|
|
120
|
+
readFile,
|
|
67
121
|
});
|
|
68
122
|
|
|
69
123
|
expect(result).toEqual({
|
|
70
|
-
GetUsers: { entryPoint: "server/apis/
|
|
124
|
+
GetUsers: { entryPoint: "server/apis/GetUsers/api.ts" },
|
|
71
125
|
});
|
|
72
126
|
});
|
|
73
127
|
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { ExportViewMode, NotFoundError } from "@superblocksteam/shared";
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
const { connectToISocketRPCServer, unwrapResponseDto, warn } = vi.hoisted(
|
|
5
|
+
() => ({
|
|
6
|
+
connectToISocketRPCServer: vi.fn(),
|
|
7
|
+
unwrapResponseDto: vi.fn(),
|
|
8
|
+
warn: vi.fn(),
|
|
9
|
+
}),
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
vi.mock("../socket/index.js", () => ({
|
|
13
|
+
connectToISocketRPCServer,
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
vi.mock("../telemetry/logging.js", () => ({
|
|
17
|
+
getLogger: () => ({
|
|
18
|
+
warn,
|
|
19
|
+
}),
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
vi.mock("@superblocksteam/shared", async () => {
|
|
23
|
+
const actual = await vi.importActual("@superblocksteam/shared");
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
...actual,
|
|
27
|
+
unwrapResponseDto,
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
import { getApplicationDirectoryHash } from "./client.js";
|
|
32
|
+
|
|
33
|
+
describe("getApplicationDirectoryHash", () => {
|
|
34
|
+
const directoryContentsGet = vi.fn();
|
|
35
|
+
const rpcClient = {
|
|
36
|
+
call: {
|
|
37
|
+
v3: {
|
|
38
|
+
application: {
|
|
39
|
+
directoryContents: {
|
|
40
|
+
get: directoryContentsGet,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
close: vi.fn(),
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
beforeEach(() => {
|
|
49
|
+
connectToISocketRPCServer.mockReset();
|
|
50
|
+
directoryContentsGet.mockReset();
|
|
51
|
+
rpcClient.close.mockReset();
|
|
52
|
+
unwrapResponseDto.mockReset();
|
|
53
|
+
warn.mockReset();
|
|
54
|
+
|
|
55
|
+
connectToISocketRPCServer.mockResolvedValue(rpcClient);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("does not fall back to the live hash for commit lookups", async () => {
|
|
59
|
+
directoryContentsGet.mockResolvedValue("commit-request");
|
|
60
|
+
unwrapResponseDto.mockRejectedValueOnce(
|
|
61
|
+
new NotFoundError("commit hash not found"),
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
await expect(
|
|
65
|
+
getApplicationDirectoryHash(
|
|
66
|
+
"token",
|
|
67
|
+
"https://app.superblocks.com",
|
|
68
|
+
"app-123",
|
|
69
|
+
"main",
|
|
70
|
+
{ commitId: "commit-123" },
|
|
71
|
+
),
|
|
72
|
+
).rejects.toBeInstanceOf(NotFoundError);
|
|
73
|
+
|
|
74
|
+
expect(directoryContentsGet).toHaveBeenCalledTimes(1);
|
|
75
|
+
expect(directoryContentsGet).toHaveBeenCalledWith({
|
|
76
|
+
applicationId: "app-123",
|
|
77
|
+
commitId: "commit-123",
|
|
78
|
+
viewMode: ExportViewMode.EXPORT_COMMIT,
|
|
79
|
+
});
|
|
80
|
+
expect(warn).not.toHaveBeenCalled();
|
|
81
|
+
expect(rpcClient.close).toHaveBeenCalledOnce();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("falls back from draft to live for non-commit lookups", async () => {
|
|
85
|
+
directoryContentsGet
|
|
86
|
+
.mockResolvedValueOnce("draft-request")
|
|
87
|
+
.mockResolvedValueOnce("live-request");
|
|
88
|
+
unwrapResponseDto
|
|
89
|
+
.mockRejectedValueOnce(new NotFoundError("draft hash not found"))
|
|
90
|
+
.mockResolvedValueOnce({ hash: "live-hash" });
|
|
91
|
+
|
|
92
|
+
await expect(
|
|
93
|
+
getApplicationDirectoryHash(
|
|
94
|
+
"token",
|
|
95
|
+
"https://app.superblocks.com",
|
|
96
|
+
"app-123",
|
|
97
|
+
"main",
|
|
98
|
+
),
|
|
99
|
+
).resolves.toBe("live-hash");
|
|
100
|
+
|
|
101
|
+
expect(directoryContentsGet).toHaveBeenNthCalledWith(1, {
|
|
102
|
+
applicationId: "app-123",
|
|
103
|
+
branchName: "main",
|
|
104
|
+
viewMode: ExportViewMode.EXPORT_DRAFT,
|
|
105
|
+
});
|
|
106
|
+
expect(directoryContentsGet).toHaveBeenNthCalledWith(2, {
|
|
107
|
+
applicationId: "app-123",
|
|
108
|
+
branchName: "main",
|
|
109
|
+
viewMode: ExportViewMode.EXPORT_LIVE,
|
|
110
|
+
});
|
|
111
|
+
expect(warn).toHaveBeenCalledWith(
|
|
112
|
+
"Draft state not found, using live edit hash: live-hash",
|
|
113
|
+
);
|
|
114
|
+
expect(rpcClient.close).toHaveBeenCalledOnce();
|
|
115
|
+
});
|
|
116
|
+
});
|
package/src/dbfs/client.ts
CHANGED
|
@@ -15,44 +15,62 @@ export async function getApplicationDirectoryHash(
|
|
|
15
15
|
superblocksBaseUrl: string,
|
|
16
16
|
applicationId: string,
|
|
17
17
|
branch: string | undefined,
|
|
18
|
-
options?: { silent?: boolean },
|
|
18
|
+
options?: { commitId?: string; silent?: boolean },
|
|
19
19
|
) {
|
|
20
20
|
const rpcClient = await connectToISocketRPCServer({
|
|
21
21
|
token,
|
|
22
22
|
superblocksBaseUrl,
|
|
23
23
|
});
|
|
24
24
|
try {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const liveEditHash = response.hash;
|
|
33
|
-
if (!liveEditHash) {
|
|
34
|
-
throw new Error(
|
|
35
|
-
`No directory contents hash found for the view mode ${ExportViewMode.EXPORT_DRAFT}`,
|
|
25
|
+
if (options?.commitId) {
|
|
26
|
+
const response = await unwrapResponseDto(
|
|
27
|
+
rpcClient.call.v3.application.directoryContents.get({
|
|
28
|
+
applicationId,
|
|
29
|
+
commitId: options.commitId,
|
|
30
|
+
viewMode: ExportViewMode.EXPORT_COMMIT,
|
|
31
|
+
}),
|
|
36
32
|
);
|
|
33
|
+
const commitHash = response.hash;
|
|
34
|
+
if (!commitHash) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`No directory contents hash found for commit ${options.commitId}`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return commitHash;
|
|
37
40
|
}
|
|
38
|
-
|
|
39
|
-
} catch (e) {
|
|
40
|
-
if (e instanceof NotFoundError) {
|
|
41
|
+
try {
|
|
41
42
|
const response = await unwrapResponseDto(
|
|
42
43
|
rpcClient.call.v3.application.directoryContents.get({
|
|
43
44
|
applicationId,
|
|
44
45
|
branchName: branch,
|
|
45
|
-
viewMode: ExportViewMode.
|
|
46
|
+
viewMode: ExportViewMode.EXPORT_DRAFT,
|
|
46
47
|
}),
|
|
47
48
|
);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
const liveEditHash = response.hash;
|
|
50
|
+
if (!liveEditHash) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`No directory contents hash found for the view mode ${ExportViewMode.EXPORT_DRAFT}`,
|
|
51
53
|
);
|
|
52
54
|
}
|
|
53
|
-
return
|
|
55
|
+
return liveEditHash;
|
|
56
|
+
} catch (e) {
|
|
57
|
+
if (e instanceof NotFoundError) {
|
|
58
|
+
const response = await unwrapResponseDto(
|
|
59
|
+
rpcClient.call.v3.application.directoryContents.get({
|
|
60
|
+
applicationId,
|
|
61
|
+
branchName: branch,
|
|
62
|
+
viewMode: ExportViewMode.EXPORT_LIVE,
|
|
63
|
+
}),
|
|
64
|
+
);
|
|
65
|
+
if (!options?.silent) {
|
|
66
|
+
getLogger().warn(
|
|
67
|
+
`Draft state not found, using live edit hash: ${response.hash}`,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
return response.hash;
|
|
71
|
+
}
|
|
72
|
+
throw e;
|
|
54
73
|
}
|
|
55
|
-
throw e;
|
|
56
74
|
} finally {
|
|
57
75
|
rpcClient.close();
|
|
58
76
|
}
|
|
@@ -86,6 +104,27 @@ export async function downloadApplicationDirectory(
|
|
|
86
104
|
}
|
|
87
105
|
}
|
|
88
106
|
|
|
107
|
+
export async function downloadDirectoryByHash(
|
|
108
|
+
token: string,
|
|
109
|
+
superblocksBaseUrl: string,
|
|
110
|
+
directoryHash: string,
|
|
111
|
+
localDirectoryPath: string,
|
|
112
|
+
): Promise<void> {
|
|
113
|
+
const rpcClient = await connectToISocketRPCServer({
|
|
114
|
+
token,
|
|
115
|
+
superblocksBaseUrl,
|
|
116
|
+
});
|
|
117
|
+
try {
|
|
118
|
+
await doDownloadDirectoryToLocal(
|
|
119
|
+
rpcClient,
|
|
120
|
+
directoryHash,
|
|
121
|
+
localDirectoryPath,
|
|
122
|
+
);
|
|
123
|
+
} finally {
|
|
124
|
+
rpcClient.close();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
89
128
|
export async function uploadLocalApplication(
|
|
90
129
|
token: string,
|
|
91
130
|
superblocksBaseUrl: string,
|