@superblocksteam/sdk 2.0.99 → 2.0.100-next.1

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 (71) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/cli-replacement/dev.d.mts.map +1 -1
  3. package/dist/cli-replacement/dev.mjs +64 -20
  4. package/dist/cli-replacement/dev.mjs.map +1 -1
  5. package/dist/cli-replacement/init.d.ts.map +1 -1
  6. package/dist/cli-replacement/init.js +1 -0
  7. package/dist/cli-replacement/init.js.map +1 -1
  8. package/dist/client.d.ts +8 -21
  9. package/dist/client.d.ts.map +1 -1
  10. package/dist/client.js +36 -5
  11. package/dist/client.js.map +1 -1
  12. package/dist/collect-sdk-apis.d.mts +10 -6
  13. package/dist/collect-sdk-apis.d.mts.map +1 -1
  14. package/dist/collect-sdk-apis.mjs +20 -5
  15. package/dist/collect-sdk-apis.mjs.map +1 -1
  16. package/dist/collect-sdk-apis.test.mjs +53 -4
  17. package/dist/collect-sdk-apis.test.mjs.map +1 -1
  18. package/dist/dbfs/client.d.ts +2 -0
  19. package/dist/dbfs/client.d.ts.map +1 -1
  20. package/dist/dbfs/client.js +43 -17
  21. package/dist/dbfs/client.js.map +1 -1
  22. package/dist/dbfs/client.test.d.ts +2 -0
  23. package/dist/dbfs/client.test.d.ts.map +1 -0
  24. package/dist/dbfs/client.test.js +81 -0
  25. package/dist/dbfs/client.test.js.map +1 -0
  26. package/dist/extract-api-integrations.d.mts +17 -0
  27. package/dist/extract-api-integrations.d.mts.map +1 -0
  28. package/dist/extract-api-integrations.mjs +233 -0
  29. package/dist/extract-api-integrations.mjs.map +1 -0
  30. package/dist/extract-api-integrations.test.d.mts +2 -0
  31. package/dist/extract-api-integrations.test.d.mts.map +1 -0
  32. package/dist/extract-api-integrations.test.mjs +97 -0
  33. package/dist/extract-api-integrations.test.mjs.map +1 -0
  34. package/dist/sdk.d.ts +13 -6
  35. package/dist/sdk.d.ts.map +1 -1
  36. package/dist/sdk.js +13 -6
  37. package/dist/sdk.js.map +1 -1
  38. package/dist/sdk.test.d.ts +2 -0
  39. package/dist/sdk.test.d.ts.map +1 -0
  40. package/dist/sdk.test.js +71 -0
  41. package/dist/sdk.test.js.map +1 -0
  42. package/dist/telemetry/index.d.ts.map +1 -1
  43. package/dist/telemetry/index.js +9 -2
  44. package/dist/telemetry/index.js.map +1 -1
  45. package/dist/telemetry/logging.d.ts.map +1 -1
  46. package/dist/telemetry/logging.js +1 -0
  47. package/dist/telemetry/logging.js.map +1 -1
  48. package/dist/version-control.d.mts +5 -3
  49. package/dist/version-control.d.mts.map +1 -1
  50. package/dist/version-control.mjs +18 -10
  51. package/dist/version-control.mjs.map +1 -1
  52. package/dist/vite-plugin-generate-api-build-manifest.d.mts.map +1 -1
  53. package/dist/vite-plugin-generate-api-build-manifest.mjs.map +1 -1
  54. package/package.json +6 -6
  55. package/src/cli-replacement/dev.mts +73 -24
  56. package/src/cli-replacement/init.ts +1 -0
  57. package/src/client.ts +53 -22
  58. package/src/collect-sdk-apis.mts +30 -6
  59. package/src/collect-sdk-apis.test.mts +58 -4
  60. package/src/dbfs/client.test.ts +116 -0
  61. package/src/dbfs/client.ts +60 -21
  62. package/src/extract-api-integrations.mts +345 -0
  63. package/src/extract-api-integrations.test.mts +114 -0
  64. package/src/sdk.test.ts +106 -0
  65. package/src/sdk.ts +40 -3
  66. package/src/telemetry/index.ts +13 -2
  67. package/src/telemetry/logging.ts +1 -0
  68. package/src/version-control.mts +23 -8
  69. package/src/vite-plugin-generate-api-build-manifest.mts +7 -1
  70. package/test/version-control.test.mts +81 -1
  71. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,345 @@
1
+ import { parse } from "@babel/parser";
2
+
3
+ export type IntegrationInfo = {
4
+ key: string;
5
+ pluginId: string;
6
+ id: string;
7
+ };
8
+
9
+ type AstNode = {
10
+ type?: string;
11
+ [key: string]: unknown;
12
+ };
13
+
14
+ function isNode(value: unknown): value is AstNode {
15
+ return !!value && typeof value === "object";
16
+ }
17
+
18
+ function getPropertyName(node: unknown): string | undefined {
19
+ if (!isNode(node)) {
20
+ return undefined;
21
+ }
22
+
23
+ if (node.type === "Identifier" && typeof node.name === "string") {
24
+ return node.name;
25
+ }
26
+
27
+ if (node.type === "StringLiteral" && typeof node.value === "string") {
28
+ return node.value;
29
+ }
30
+
31
+ return undefined;
32
+ }
33
+
34
+ function getLiteralString(node: unknown): string | undefined {
35
+ if (!isNode(node)) {
36
+ return undefined;
37
+ }
38
+
39
+ if (node.type === "StringLiteral" && typeof node.value === "string") {
40
+ return node.value;
41
+ }
42
+
43
+ if (
44
+ node.type === "TemplateLiteral" &&
45
+ Array.isArray(node.expressions) &&
46
+ node.expressions.length === 0 &&
47
+ Array.isArray(node.quasis) &&
48
+ node.quasis.length === 1
49
+ ) {
50
+ const quasi = node.quasis[0];
51
+ if (
52
+ isNode(quasi) &&
53
+ isNode(quasi.value) &&
54
+ typeof quasi.value.cooked === "string"
55
+ ) {
56
+ return quasi.value.cooked;
57
+ }
58
+ }
59
+
60
+ return undefined;
61
+ }
62
+
63
+ function getCalleeName(node: unknown): string | undefined {
64
+ if (!isNode(node)) {
65
+ return undefined;
66
+ }
67
+
68
+ if (node.type === "Identifier" && typeof node.name === "string") {
69
+ return node.name;
70
+ }
71
+
72
+ if (node.type === "MemberExpression") {
73
+ return getPropertyName(node.property);
74
+ }
75
+
76
+ return undefined;
77
+ }
78
+
79
+ function unwrapExpression(node: unknown): AstNode | undefined {
80
+ if (!isNode(node)) {
81
+ return undefined;
82
+ }
83
+
84
+ if (
85
+ node.type === "TSAsExpression" ||
86
+ node.type === "TSTypeAssertion" ||
87
+ node.type === "ParenthesizedExpression"
88
+ ) {
89
+ return unwrapExpression(node.expression);
90
+ }
91
+
92
+ return node;
93
+ }
94
+
95
+ function buildVariableInitializerMap(
96
+ programBody: unknown[],
97
+ ): Map<string, unknown> {
98
+ const initializers = new Map<string, unknown>();
99
+
100
+ for (const statement of programBody) {
101
+ if (
102
+ !isNode(statement) ||
103
+ statement.type !== "VariableDeclaration" ||
104
+ !Array.isArray(statement.declarations)
105
+ ) {
106
+ continue;
107
+ }
108
+
109
+ for (const declaration of statement.declarations) {
110
+ if (!isNode(declaration)) {
111
+ continue;
112
+ }
113
+
114
+ const identifier = declaration.id;
115
+ if (
116
+ !isNode(identifier) ||
117
+ identifier.type !== "Identifier" ||
118
+ typeof identifier.name !== "string"
119
+ ) {
120
+ continue;
121
+ }
122
+
123
+ initializers.set(identifier.name, declaration.init);
124
+ }
125
+ }
126
+
127
+ return initializers;
128
+ }
129
+
130
+ function resolveApiConfigObject(
131
+ expression: unknown,
132
+ variableInitializers: Map<string, unknown>,
133
+ ): AstNode | undefined {
134
+ const resolvedExpression = unwrapExpression(expression);
135
+ if (!resolvedExpression) {
136
+ return undefined;
137
+ }
138
+
139
+ if (
140
+ resolvedExpression.type === "Identifier" &&
141
+ typeof resolvedExpression.name === "string"
142
+ ) {
143
+ return resolveApiConfigObject(
144
+ variableInitializers.get(resolvedExpression.name),
145
+ variableInitializers,
146
+ );
147
+ }
148
+
149
+ if (
150
+ resolvedExpression.type !== "CallExpression" ||
151
+ getCalleeName(resolvedExpression.callee) !== "api" ||
152
+ !Array.isArray(resolvedExpression.arguments)
153
+ ) {
154
+ return undefined;
155
+ }
156
+
157
+ const config = unwrapExpression(resolvedExpression.arguments[0]);
158
+ if (!config || config.type !== "ObjectExpression") {
159
+ return undefined;
160
+ }
161
+
162
+ return config;
163
+ }
164
+
165
+ function findExportedApiConfigObject(
166
+ programBody: unknown[],
167
+ ): AstNode | undefined {
168
+ const variableInitializers = buildVariableInitializerMap(programBody);
169
+
170
+ for (const statement of programBody) {
171
+ if (!isNode(statement)) {
172
+ continue;
173
+ }
174
+
175
+ if (statement.type === "ExportDefaultDeclaration") {
176
+ return resolveApiConfigObject(
177
+ statement.declaration,
178
+ variableInitializers,
179
+ );
180
+ }
181
+
182
+ if (
183
+ statement.type === "ExportNamedDeclaration" &&
184
+ Array.isArray(statement.specifiers)
185
+ ) {
186
+ for (const specifier of statement.specifiers) {
187
+ if (
188
+ !isNode(specifier) ||
189
+ specifier.type !== "ExportSpecifier" ||
190
+ getPropertyName(specifier.exported) !== "default"
191
+ ) {
192
+ continue;
193
+ }
194
+
195
+ return resolveApiConfigObject(specifier.local, variableInitializers);
196
+ }
197
+ }
198
+ }
199
+
200
+ return undefined;
201
+ }
202
+
203
+ function buildVariableReferenceMap(
204
+ programBody: unknown[],
205
+ ): Map<string, Omit<IntegrationInfo, "key">> {
206
+ const refs = new Map<string, Omit<IntegrationInfo, "key">>();
207
+
208
+ for (const statement of programBody) {
209
+ if (
210
+ !isNode(statement) ||
211
+ statement.type !== "VariableDeclaration" ||
212
+ !Array.isArray(statement.declarations)
213
+ ) {
214
+ continue;
215
+ }
216
+
217
+ for (const declaration of statement.declarations) {
218
+ if (!isNode(declaration)) {
219
+ continue;
220
+ }
221
+
222
+ const identifier = declaration.id;
223
+ const init = declaration.init;
224
+ if (
225
+ !isNode(identifier) ||
226
+ identifier.type !== "Identifier" ||
227
+ typeof identifier.name !== "string"
228
+ ) {
229
+ continue;
230
+ }
231
+
232
+ if (
233
+ !isNode(init) ||
234
+ init.type !== "CallExpression" ||
235
+ !Array.isArray(init.arguments)
236
+ ) {
237
+ continue;
238
+ }
239
+
240
+ const pluginId = getCalleeName(init.callee);
241
+ const id = getLiteralString(init.arguments[0]);
242
+ if (!pluginId || !id) {
243
+ continue;
244
+ }
245
+
246
+ refs.set(identifier.name, { pluginId, id });
247
+ }
248
+ }
249
+
250
+ return refs;
251
+ }
252
+
253
+ /**
254
+ * Extract integration declarations from an SDK API source file.
255
+ *
256
+ * Supports both inline declarations:
257
+ * `integrations: { db: postgres("uuid") }`
258
+ *
259
+ * and top-level variable references:
260
+ * `const DB = postgres("uuid"); integrations: { db: DB }`
261
+ */
262
+ export function extractIntegrationsFromSource(
263
+ source: string,
264
+ ): IntegrationInfo[] {
265
+ let ast: ReturnType<typeof parse>;
266
+ try {
267
+ ast = parse(source, {
268
+ sourceType: "module",
269
+ plugins: ["typescript"],
270
+ });
271
+ } catch {
272
+ return [];
273
+ }
274
+
275
+ const variableRefs = buildVariableReferenceMap(ast.program.body);
276
+ const apiConfig = findExportedApiConfigObject(ast.program.body);
277
+ if (!apiConfig) {
278
+ return [];
279
+ }
280
+ const results: IntegrationInfo[] = [];
281
+
282
+ const apiConfigProperties = Array.isArray(apiConfig.properties)
283
+ ? apiConfig.properties
284
+ : [];
285
+ const integrationsProperty = apiConfigProperties.find(
286
+ (property: AstNode) =>
287
+ isNode(property) &&
288
+ property.type === "ObjectProperty" &&
289
+ getPropertyName(property.key) === "integrations",
290
+ );
291
+
292
+ if (
293
+ !isNode(integrationsProperty) ||
294
+ !isNode(integrationsProperty.value) ||
295
+ integrationsProperty.value.type !== "ObjectExpression"
296
+ ) {
297
+ return [];
298
+ }
299
+
300
+ const properties = Array.isArray(integrationsProperty.value.properties)
301
+ ? integrationsProperty.value.properties
302
+ : [];
303
+ for (const property of properties) {
304
+ if (!isNode(property) || property.type !== "ObjectProperty") {
305
+ continue;
306
+ }
307
+
308
+ const key = getPropertyName(property.key);
309
+ if (!key) {
310
+ continue;
311
+ }
312
+
313
+ if (
314
+ isNode(property.value) &&
315
+ property.value.type === "CallExpression" &&
316
+ Array.isArray(property.value.arguments)
317
+ ) {
318
+ const pluginId = getCalleeName(property.value.callee);
319
+ const id = getLiteralString(property.value.arguments[0]);
320
+ if (pluginId && id) {
321
+ results.push({ key, pluginId, id });
322
+ }
323
+ continue;
324
+ }
325
+
326
+ if (
327
+ isNode(property.value) &&
328
+ property.value.type === "Identifier" &&
329
+ typeof property.value.name === "string"
330
+ ) {
331
+ const resolved = variableRefs.get(property.value.name);
332
+ if (resolved) {
333
+ results.push({ key, ...resolved });
334
+ }
335
+ }
336
+ }
337
+
338
+ return results;
339
+ }
340
+
341
+ export function extractIntegrationIdsFromSource(source: string): string[] {
342
+ return extractIntegrationsFromSource(source).map(
343
+ (integration) => integration.id,
344
+ );
345
+ }
@@ -0,0 +1,114 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ extractIntegrationIdsFromSource,
4
+ extractIntegrationsFromSource,
5
+ } from "./extract-api-integrations.mjs";
6
+
7
+ describe("extractIntegrationsFromSource", () => {
8
+ it("extracts integration declarations from API source", () => {
9
+ const source = `
10
+ import { api, postgres, slack } from "@superblocksteam/sdk-api";
11
+ export default api({
12
+ integrations: {
13
+ db: postgres("pg-uuid-prod"),
14
+ notifier: slack("slack-uuid"),
15
+ },
16
+ });
17
+ `;
18
+
19
+ expect(extractIntegrationsFromSource(source)).toEqual([
20
+ { key: "db", pluginId: "postgres", id: "pg-uuid-prod" },
21
+ { key: "notifier", pluginId: "slack", id: "slack-uuid" },
22
+ ]);
23
+ });
24
+
25
+ it("extracts declarations from top-level variable references", () => {
26
+ const source = `
27
+ import { api, postgres } from "@superblocksteam/sdk-api";
28
+ const DB = postgres("db-uuid");
29
+ export default api({
30
+ integrations: { myDb: DB },
31
+ });
32
+ `;
33
+
34
+ expect(extractIntegrationsFromSource(source)).toEqual([
35
+ { key: "myDb", pluginId: "postgres", id: "db-uuid" },
36
+ ]);
37
+ });
38
+
39
+ it("supports template literals without expressions", () => {
40
+ const source = `
41
+ import { api, postgres } from "@superblocksteam/sdk-api";
42
+ export default api({
43
+ integrations: { db: postgres(\`pg-uuid\`) },
44
+ });
45
+ `;
46
+
47
+ expect(extractIntegrationsFromSource(source)).toEqual([
48
+ { key: "db", pluginId: "postgres", id: "pg-uuid" },
49
+ ]);
50
+ });
51
+
52
+ it("ignores unrelated integrations objects outside the exported API config", () => {
53
+ const source = `
54
+ import { api, postgres, slack } from "@superblocksteam/sdk-api";
55
+
56
+ const helper = {
57
+ integrations: {
58
+ fake: postgres("11111111-1111-1111-1111-111111111111"),
59
+ },
60
+ };
61
+
62
+ const REAL = slack("22222222-2222-2222-2222-222222222222");
63
+
64
+ export default api({
65
+ integrations: { notifier: REAL },
66
+ async run() {
67
+ return helper.integrations.fake;
68
+ },
69
+ });
70
+ `;
71
+
72
+ expect(extractIntegrationsFromSource(source)).toEqual([
73
+ {
74
+ key: "notifier",
75
+ pluginId: "slack",
76
+ id: "22222222-2222-2222-2222-222222222222",
77
+ },
78
+ ]);
79
+ });
80
+
81
+ it("returns empty array when no integrations field is present", () => {
82
+ const source = `
83
+ import { api } from "@superblocksteam/sdk-api";
84
+ export default api({});
85
+ `;
86
+
87
+ expect(extractIntegrationsFromSource(source)).toEqual([]);
88
+ });
89
+
90
+ it("handles malformed source gracefully", () => {
91
+ expect(extractIntegrationsFromSource("this is not valid {{{ code")).toEqual(
92
+ [],
93
+ );
94
+ });
95
+ });
96
+
97
+ describe("extractIntegrationIdsFromSource", () => {
98
+ it("returns the extracted IDs in declaration order", () => {
99
+ const source = `
100
+ import { api, postgres, slack } from "@superblocksteam/sdk-api";
101
+ export default api({
102
+ integrations: {
103
+ db: postgres("pg-uuid-prod"),
104
+ notifier: slack("slack-uuid"),
105
+ },
106
+ });
107
+ `;
108
+
109
+ expect(extractIntegrationIdsFromSource(source)).toEqual([
110
+ "pg-uuid-prod",
111
+ "slack-uuid",
112
+ ]);
113
+ });
114
+ });
@@ -0,0 +1,106 @@
1
+ import {
2
+ CommitType,
3
+ BillingPlan,
4
+ type GetApplicationCommitsResponseBody,
5
+ type GetPublicOrganizationSummaryResponseBody,
6
+ } from "@superblocksteam/shared";
7
+ import { beforeEach, describe, expect, it, vi } from "vitest";
8
+
9
+ const { fetchApplicationCommits, fetchOrganizationSummary } = vi.hoisted(
10
+ () => ({
11
+ fetchApplicationCommits: vi.fn(),
12
+ fetchOrganizationSummary: vi.fn(),
13
+ }),
14
+ );
15
+
16
+ vi.mock("./client.js", async () => {
17
+ const actual = await vi.importActual("./client.js");
18
+
19
+ return {
20
+ ...actual,
21
+ fetchApplicationCommits,
22
+ fetchOrganizationSummary,
23
+ };
24
+ });
25
+
26
+ import { SuperblocksSdk } from "./sdk.js";
27
+
28
+ describe("SuperblocksSdk.fetchOrganizationSummary", () => {
29
+ beforeEach(() => {
30
+ fetchApplicationCommits.mockReset();
31
+ fetchOrganizationSummary.mockReset();
32
+ });
33
+
34
+ it("delegates to the client helper with the SDK context", async () => {
35
+ const expectedResponse: GetPublicOrganizationSummaryResponseBody = {
36
+ billing_plan: BillingPlan.ENTERPRISE,
37
+ name: "Customer Org",
38
+ organization_id: "org-123",
39
+ organization_type: "opa",
40
+ registered_opas: [
41
+ {
42
+ url: "https://opa.example.com",
43
+ version: "1.2.3",
44
+ },
45
+ ],
46
+ };
47
+ fetchOrganizationSummary.mockResolvedValue(expectedResponse);
48
+
49
+ const sdk = new SuperblocksSdk(
50
+ "test-token",
51
+ "https://staging.superblocks.com",
52
+ "1.2.3",
53
+ );
54
+
55
+ await expect(sdk.fetchOrganizationSummary("org-123")).resolves.toEqual(
56
+ expectedResponse,
57
+ );
58
+ expect(fetchOrganizationSummary).toHaveBeenCalledWith(
59
+ "1.2.3",
60
+ "test-token",
61
+ "https://staging.superblocks.com",
62
+ "org-123",
63
+ );
64
+ });
65
+ });
66
+
67
+ describe("SuperblocksSdk.fetchApplicationCommits", () => {
68
+ beforeEach(() => {
69
+ fetchApplicationCommits.mockReset();
70
+ });
71
+
72
+ it("delegates commit history requests with commit type filters", async () => {
73
+ const expectedResponse: GetApplicationCommitsResponseBody = {
74
+ autosaves: [],
75
+ commits: [],
76
+ };
77
+ fetchApplicationCommits.mockResolvedValue(expectedResponse);
78
+
79
+ const sdk = new SuperblocksSdk(
80
+ "test-token",
81
+ "https://staging.superblocks.com",
82
+ "1.2.3",
83
+ );
84
+
85
+ await expect(
86
+ sdk.fetchApplicationCommits({
87
+ applicationId: "app-123",
88
+ branch: "feature/test",
89
+ commitType: CommitType.ALL,
90
+ limit: 25,
91
+ offset: 50,
92
+ }),
93
+ ).resolves.toEqual(expectedResponse);
94
+ expect(fetchApplicationCommits).toHaveBeenCalledWith({
95
+ cliVersion: "1.2.3",
96
+ applicationId: "app-123",
97
+ branch: "feature/test",
98
+ commitType: CommitType.ALL,
99
+ token: "test-token",
100
+ superblocksBaseUrl: "https://staging.superblocks.com",
101
+ injectedHeaders: {},
102
+ limit: 25,
103
+ offset: 50,
104
+ });
105
+ });
106
+ });
package/src/sdk.ts CHANGED
@@ -1,4 +1,8 @@
1
- import { ExportViewMode } from "@superblocksteam/shared";
1
+ import {
2
+ CommitType,
3
+ ExportViewMode,
4
+ type GetPublicOrganizationSummaryResponseBody,
5
+ } from "@superblocksteam/shared";
2
6
  import {
3
7
  fetchApi,
4
8
  fetchApiCommits,
@@ -9,6 +13,7 @@ import {
9
13
  fetchApplications,
10
14
  fetchApplicationWithComponents,
11
15
  fetchCurrentUser,
16
+ fetchOrganizationSummary,
12
17
  getApplicationGitConfig,
13
18
  getGitFreshToken,
14
19
  sync,
@@ -23,6 +28,7 @@ import {
23
28
  } from "./client.js";
24
29
  import {
25
30
  downloadApplicationDirectory,
31
+ downloadDirectoryByHash,
26
32
  uploadLocalApplication,
27
33
  uploadLocalDirectory,
28
34
  printDirectoryEntries,
@@ -164,12 +170,14 @@ export class SuperblocksSdk {
164
170
  async fetchApplicationCommits({
165
171
  applicationId,
166
172
  branch,
173
+ commitType = CommitType.COMMIT,
167
174
  headers = {},
168
175
  limit,
169
176
  offset,
170
177
  }: {
171
178
  applicationId: string;
172
179
  branch: string;
180
+ commitType?: CommitType;
173
181
  headers?: Record<string, string>;
174
182
  limit?: number;
175
183
  offset?: number;
@@ -178,6 +186,7 @@ export class SuperblocksSdk {
178
186
  cliVersion: this.cliVersion,
179
187
  applicationId,
180
188
  branch,
189
+ commitType,
181
190
  token: this.token,
182
191
  superblocksBaseUrl: this.superblocksBaseUrl,
183
192
  injectedHeaders: headers,
@@ -310,6 +319,17 @@ export class SuperblocksSdk {
310
319
  );
311
320
  }
312
321
 
322
+ async fetchOrganizationSummary(
323
+ organizationId: string,
324
+ ): Promise<GetPublicOrganizationSummaryResponseBody> {
325
+ return fetchOrganizationSummary(
326
+ this.cliVersion,
327
+ this.token,
328
+ this.superblocksBaseUrl,
329
+ organizationId,
330
+ );
331
+ }
332
+
313
333
  async pushApplication({
314
334
  applicationId,
315
335
  applicationConfig,
@@ -405,6 +425,21 @@ export class SuperblocksSdk {
405
425
  );
406
426
  }
407
427
 
428
+ async dbfsGetDirectoryByHash({
429
+ hash,
430
+ localDirectoryPath,
431
+ }: {
432
+ hash: string;
433
+ localDirectoryPath: string;
434
+ }) {
435
+ await downloadDirectoryByHash(
436
+ this.token,
437
+ this.superblocksBaseUrl,
438
+ hash,
439
+ localDirectoryPath,
440
+ );
441
+ }
442
+
408
443
  async dbfsPutApplication({
409
444
  applicationId,
410
445
  branch,
@@ -438,10 +473,12 @@ export class SuperblocksSdk {
438
473
  async dbfsGetApplicationDirectoryHash({
439
474
  applicationId,
440
475
  branch,
476
+ commitId,
441
477
  silent,
442
478
  }: {
443
479
  applicationId: string;
444
- branch: string | undefined;
480
+ branch?: string;
481
+ commitId?: string;
445
482
  silent?: boolean;
446
483
  }) {
447
484
  return getApplicationDirectoryHash(
@@ -449,7 +486,7 @@ export class SuperblocksSdk {
449
486
  this.superblocksBaseUrl,
450
487
  applicationId,
451
488
  branch,
452
- { silent },
489
+ { commitId, silent },
453
490
  );
454
491
  }
455
492
 
@@ -18,8 +18,6 @@ import {
18
18
  resetTelemetry,
19
19
  getDefaultPolicy,
20
20
  } from "@superblocksteam/telemetry";
21
- // Note: dd-trace kept for LLMObs until Epic 07 completes
22
- import ddTrace from "dd-trace";
23
21
  import packageJson from "../../package.json" with { type: "json" };
24
22
  import {
25
23
  ATTR_SUPERBLOCKS_BASE_URL,
@@ -33,6 +31,7 @@ import { applyLocalObsEnvVars, isLocalObsEnabled } from "./local-obs.js";
33
31
  import { getLogger as getStandardLogger } from "./logging.js";
34
32
  import { getConfiguration, SERVICE_NAME } from "./util.js";
35
33
  import type { ApplicationConfigWithTokenConfigAndUserInfo } from "../types/index.js";
34
+ import type ddTraceDefault from "dd-trace";
36
35
 
37
36
  // Apply local observability env vars early, before dd-trace auto-init
38
37
  applyLocalObsEnvVars();
@@ -41,6 +40,17 @@ applyLocalObsEnvVars();
41
40
  let config: Awaited<ReturnType<typeof getConfiguration>> | undefined =
42
41
  undefined;
43
42
  let configured = false;
43
+ type DdTrace = typeof ddTraceDefault;
44
+
45
+ // Load dd-trace only when telemetry is explicitly configured. This keeps
46
+ // lightweight SDK consumers from pulling in dd-trace as a module-load side
47
+ // effect when they only need logger/tracer helpers.
48
+ let ddTracePromise: Promise<DdTrace> | undefined = undefined;
49
+
50
+ async function getDdTrace() {
51
+ ddTracePromise ??= import("dd-trace").then((module) => module.default);
52
+ return await ddTracePromise;
53
+ }
44
54
 
45
55
  /**
46
56
  * Current deployment type based on SUPERBLOCKS_DEPLOYMENT_TYPE env var.
@@ -122,6 +132,7 @@ export async function configureTelemetry(
122
132
  // NOTE: @joeyagreco - we do this because (per DataDog support):
123
133
  // NOTE: @joeyagreco - "There is currently no way to define a retention filter directly for "LLM apps" unless those apps are associated with a specific service tag."
124
134
  const SERVICE_NAME_LLM = "superblocks-ai-code-gen";
135
+ const ddTrace = await getDdTrace();
125
136
  ddTrace.init({
126
137
  env: getEnvironmentFromHostname(config.superblocksHostname),
127
138
  service: SERVICE_NAME_LLM,