@lightdash/cli 1.54.0 → 1.56.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/dist/.tsbuildinfo +1 -1
- package/dist/handlers/apps/appCodeFiles.d.ts +5 -0
- package/dist/handlers/apps/appCodeFiles.d.ts.map +1 -1
- package/dist/handlers/apps/appCodeFiles.js +41 -1
- package/dist/handlers/apps/appCodeFiles.test.js +60 -0
- package/dist/handlers/apps/appsDownload.d.ts +49 -0
- package/dist/handlers/apps/appsDownload.d.ts.map +1 -1
- package/dist/handlers/apps/appsDownload.js +90 -1
- package/dist/handlers/apps/appsDownload.test.js +231 -0
- package/dist/handlers/apps/uploadRetry.d.ts +32 -0
- package/dist/handlers/apps/uploadRetry.d.ts.map +1 -0
- package/dist/handlers/apps/uploadRetry.js +60 -0
- package/dist/handlers/apps/uploadRetry.test.d.ts +2 -0
- package/dist/handlers/apps/uploadRetry.test.d.ts.map +1 -0
- package/dist/handlers/apps/uploadRetry.test.js +103 -0
- package/dist/handlers/download.d.ts +16 -1
- package/dist/handlers/download.d.ts.map +1 -1
- package/dist/handlers/download.js +353 -202
- package/dist/handlers/download.test.js +92 -1
- package/dist/vendor/authoring/AGENTS.md.tmpl +1 -1
- package/dist/vendor/authoring/README.md.tmpl +1 -1
- package/dist/vendor/authoring/developing-data-apps-locally/SKILL.md +3 -3
- package/dist/vendor/template/package.json +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withBuildLimitRetry = exports.isBuildLimitError = exports.createBuildLimitWaitState = exports.APP_BUILD_WAIT_MAX_DELAY_MS = exports.APP_BUILD_WAIT_INITIAL_DELAY_MS = exports.APP_BUILD_WAIT_BUDGET_MS = void 0;
|
|
4
|
+
const common_1 = require("@lightdash/common");
|
|
5
|
+
exports.APP_BUILD_WAIT_BUDGET_MS = 10 * 60 * 1000;
|
|
6
|
+
exports.APP_BUILD_WAIT_INITIAL_DELAY_MS = 5 * 1000;
|
|
7
|
+
exports.APP_BUILD_WAIT_MAX_DELAY_MS = 30 * 1000;
|
|
8
|
+
const createBuildLimitWaitState = (budgetMs = exports.APP_BUILD_WAIT_BUDGET_MS) => {
|
|
9
|
+
let remainingMs = budgetMs;
|
|
10
|
+
return {
|
|
11
|
+
remainingMs: () => remainingMs,
|
|
12
|
+
spend: (ms) => {
|
|
13
|
+
remainingMs -= ms;
|
|
14
|
+
},
|
|
15
|
+
refill: () => {
|
|
16
|
+
remainingMs = budgetMs;
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
exports.createBuildLimitWaitState = createBuildLimitWaitState;
|
|
21
|
+
const isBuildLimitError = (err) => err instanceof common_1.LightdashError && err.statusCode === 429;
|
|
22
|
+
exports.isBuildLimitError = isBuildLimitError;
|
|
23
|
+
const defaultSleep = (ms) => new Promise((resolve) => {
|
|
24
|
+
setTimeout(resolve, ms);
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* Runs `post` and, when the server rejects it with the per-project build cap
|
|
28
|
+
* (HTTP 429), retries with capped exponential backoff until the shared wait
|
|
29
|
+
* budget runs out. Builds take minutes, so slots free up slowly — the backoff
|
|
30
|
+
* settles on a slow poll rather than hammering the endpoint. Any other error,
|
|
31
|
+
* or a 429 after the budget is spent, is rethrown to the caller's normal
|
|
32
|
+
* failure handling.
|
|
33
|
+
*/
|
|
34
|
+
const withBuildLimitRetry = async (post, waitState, opts) => {
|
|
35
|
+
const maxDelayMs = opts.maxDelayMs ?? exports.APP_BUILD_WAIT_MAX_DELAY_MS;
|
|
36
|
+
const sleep = opts.sleep ?? defaultSleep;
|
|
37
|
+
let delayMs = opts.initialDelayMs ?? exports.APP_BUILD_WAIT_INITIAL_DELAY_MS;
|
|
38
|
+
let attempt = 0;
|
|
39
|
+
for (;;) {
|
|
40
|
+
try {
|
|
41
|
+
// eslint-disable-next-line no-await-in-loop
|
|
42
|
+
const result = await post();
|
|
43
|
+
waitState.refill();
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
if (!(0, exports.isBuildLimitError)(err) || waitState.remainingMs() <= 0) {
|
|
48
|
+
throw err;
|
|
49
|
+
}
|
|
50
|
+
attempt += 1;
|
|
51
|
+
const waitMs = Math.min(delayMs, waitState.remainingMs());
|
|
52
|
+
opts.onWait(attempt, waitMs);
|
|
53
|
+
// eslint-disable-next-line no-await-in-loop
|
|
54
|
+
await sleep(waitMs);
|
|
55
|
+
waitState.spend(waitMs);
|
|
56
|
+
delayMs = Math.min(delayMs * 2, maxDelayMs);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
exports.withBuildLimitRetry = withBuildLimitRetry;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uploadRetry.test.d.ts","sourceRoot":"","sources":["../../../src/handlers/apps/uploadRetry.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const common_1 = require("@lightdash/common");
|
|
4
|
+
const uploadRetry_1 = require("./uploadRetry");
|
|
5
|
+
const buildLimitError = () => new common_1.LightdashError({
|
|
6
|
+
message: 'Too many app builds in progress for this project (5/5). Wait for some to finish and try again.',
|
|
7
|
+
name: 'TooManyRequestsError',
|
|
8
|
+
statusCode: 429,
|
|
9
|
+
data: {},
|
|
10
|
+
});
|
|
11
|
+
describe('withBuildLimitRetry', () => {
|
|
12
|
+
it('retries 429s with backoff until the upload is accepted and refills the budget', async () => {
|
|
13
|
+
const sleeps = [];
|
|
14
|
+
const sleep = vi.fn(async (ms) => {
|
|
15
|
+
sleeps.push(ms);
|
|
16
|
+
});
|
|
17
|
+
const onWait = vi.fn();
|
|
18
|
+
const post = vi
|
|
19
|
+
.fn()
|
|
20
|
+
.mockRejectedValueOnce(buildLimitError())
|
|
21
|
+
.mockRejectedValueOnce(buildLimitError())
|
|
22
|
+
.mockResolvedValue('accepted');
|
|
23
|
+
const waitState = (0, uploadRetry_1.createBuildLimitWaitState)(600_000);
|
|
24
|
+
waitState.spend(500_000); // partially spent by earlier apps
|
|
25
|
+
const result = await (0, uploadRetry_1.withBuildLimitRetry)(post, waitState, {
|
|
26
|
+
onWait,
|
|
27
|
+
initialDelayMs: 5_000,
|
|
28
|
+
maxDelayMs: 30_000,
|
|
29
|
+
sleep,
|
|
30
|
+
});
|
|
31
|
+
expect(result).toBe('accepted');
|
|
32
|
+
expect(post).toHaveBeenCalledTimes(3);
|
|
33
|
+
expect(sleeps).toEqual([5_000, 10_000]);
|
|
34
|
+
expect(onWait).toHaveBeenNthCalledWith(1, 1, 5_000);
|
|
35
|
+
expect(onWait).toHaveBeenNthCalledWith(2, 2, 10_000);
|
|
36
|
+
// Progress refills the shared budget for the remaining apps
|
|
37
|
+
expect(waitState.remainingMs()).toBe(600_000);
|
|
38
|
+
});
|
|
39
|
+
it('caps the backoff delay at maxDelayMs', async () => {
|
|
40
|
+
const sleeps = [];
|
|
41
|
+
const post = vi
|
|
42
|
+
.fn()
|
|
43
|
+
.mockRejectedValueOnce(buildLimitError())
|
|
44
|
+
.mockRejectedValueOnce(buildLimitError())
|
|
45
|
+
.mockRejectedValueOnce(buildLimitError())
|
|
46
|
+
.mockRejectedValueOnce(buildLimitError())
|
|
47
|
+
.mockResolvedValue('accepted');
|
|
48
|
+
await (0, uploadRetry_1.withBuildLimitRetry)(post, (0, uploadRetry_1.createBuildLimitWaitState)(600_000), {
|
|
49
|
+
onWait: vi.fn(),
|
|
50
|
+
initialDelayMs: 5_000,
|
|
51
|
+
maxDelayMs: 15_000,
|
|
52
|
+
sleep: async (ms) => {
|
|
53
|
+
sleeps.push(ms);
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
expect(sleeps).toEqual([5_000, 10_000, 15_000, 15_000]);
|
|
57
|
+
});
|
|
58
|
+
it('rethrows non-429 errors without sleeping', async () => {
|
|
59
|
+
const sleep = vi.fn();
|
|
60
|
+
const notFound = new common_1.LightdashError({
|
|
61
|
+
message: 'not found',
|
|
62
|
+
name: 'NotFoundError',
|
|
63
|
+
statusCode: 404,
|
|
64
|
+
data: {},
|
|
65
|
+
});
|
|
66
|
+
const post = vi.fn().mockRejectedValue(notFound);
|
|
67
|
+
await expect((0, uploadRetry_1.withBuildLimitRetry)(post, (0, uploadRetry_1.createBuildLimitWaitState)(), {
|
|
68
|
+
onWait: vi.fn(),
|
|
69
|
+
sleep,
|
|
70
|
+
})).rejects.toThrow('not found');
|
|
71
|
+
expect(post).toHaveBeenCalledTimes(1);
|
|
72
|
+
expect(sleep).not.toHaveBeenCalled();
|
|
73
|
+
});
|
|
74
|
+
it('rethrows the 429 once the wait budget is exhausted', async () => {
|
|
75
|
+
const sleeps = [];
|
|
76
|
+
const post = vi.fn().mockRejectedValue(buildLimitError());
|
|
77
|
+
const waitState = (0, uploadRetry_1.createBuildLimitWaitState)(12_000);
|
|
78
|
+
await expect((0, uploadRetry_1.withBuildLimitRetry)(post, waitState, {
|
|
79
|
+
onWait: vi.fn(),
|
|
80
|
+
initialDelayMs: 5_000,
|
|
81
|
+
maxDelayMs: 30_000,
|
|
82
|
+
sleep: async (ms) => {
|
|
83
|
+
sleeps.push(ms);
|
|
84
|
+
},
|
|
85
|
+
})).rejects.toThrow('Too many app builds in progress');
|
|
86
|
+
// 5s, then 10s capped to the 7s remaining, then the budget is spent
|
|
87
|
+
expect(sleeps).toEqual([5_000, 7_000]);
|
|
88
|
+
expect(waitState.remainingMs()).toBe(0);
|
|
89
|
+
expect(post).toHaveBeenCalledTimes(3);
|
|
90
|
+
});
|
|
91
|
+
it('fails fast on 429 when a previous app already exhausted the budget', async () => {
|
|
92
|
+
const sleep = vi.fn();
|
|
93
|
+
const post = vi.fn().mockRejectedValue(buildLimitError());
|
|
94
|
+
const waitState = (0, uploadRetry_1.createBuildLimitWaitState)(600_000);
|
|
95
|
+
waitState.spend(600_000);
|
|
96
|
+
await expect((0, uploadRetry_1.withBuildLimitRetry)(post, waitState, {
|
|
97
|
+
onWait: vi.fn(),
|
|
98
|
+
sleep,
|
|
99
|
+
})).rejects.toThrow('Too many app builds in progress');
|
|
100
|
+
expect(post).toHaveBeenCalledTimes(1);
|
|
101
|
+
expect(sleep).not.toHaveBeenCalled();
|
|
102
|
+
});
|
|
103
|
+
});
|
|
@@ -59,7 +59,15 @@ type MetadataEntry = {
|
|
|
59
59
|
};
|
|
60
60
|
declare const sanitizeChartForDownload: (chart: ChartAsCode, stripPivotSeries: boolean) => ChartAsCode;
|
|
61
61
|
type DownloadContentType = 'charts' | 'dashboards' | 'sqlCharts';
|
|
62
|
-
|
|
62
|
+
declare const extractAppSlugsFromDashboards: (dashboards: DashboardAsCode[]) => string[];
|
|
63
|
+
export type DownloadContentResult = {
|
|
64
|
+
total: number;
|
|
65
|
+
chartSlugs: string[];
|
|
66
|
+
appSlugs: string[];
|
|
67
|
+
metadataEntries: MetadataEntry[];
|
|
68
|
+
spaces: SpaceAsCode[];
|
|
69
|
+
};
|
|
70
|
+
export declare const downloadContent: (ids: string[], type: DownloadContentType, projectId: string, projectName: string, customPath?: string, languageMap?: boolean, nested?: boolean, skipSpaces?: boolean, stripPivotSeries?: boolean, rootSpaces?: boolean, onProgress?: (detail: string) => void) => Promise<DownloadContentResult>;
|
|
63
71
|
declare const upsertVirtualViews: (projectId: string, slugs: string[], changes: Record<string, number>, force: boolean, canUpload: boolean, customPath?: string) => Promise<Record<string, number>>;
|
|
64
72
|
export declare const getExternalConnectionSecretEnvVar: (slug: string) => string;
|
|
65
73
|
/**
|
|
@@ -84,16 +92,23 @@ declare const summarizeUploadChanges: (before: Record<string, number>, after: Re
|
|
|
84
92
|
declare const getDashboardChartSlugs: (dashboardSlugs: string[], customPath?: string, looseDashboards?: (DashboardAsCode & {
|
|
85
93
|
needsUpdating: boolean;
|
|
86
94
|
})[]) => Promise<string[]>;
|
|
95
|
+
declare const getDashboardAppSlugs: (dashboardSlugs: string[], customPath?: string, looseDashboards?: (DashboardAsCode & {
|
|
96
|
+
needsUpdating: boolean;
|
|
97
|
+
})[]) => Promise<string[]>;
|
|
98
|
+
declare const isFilteredWithNoDashboards: (hasFilters: boolean, dashboardSlugs: string[]) => boolean;
|
|
87
99
|
export declare const uploadHandler: (options: DownloadHandlerOptions) => Promise<void>;
|
|
88
100
|
export declare const testHelpers: {
|
|
89
101
|
assertUniqueSpacePaths: typeof assertUniqueSpacePaths;
|
|
90
102
|
downloadSpaces: typeof downloadSpaces;
|
|
103
|
+
extractAppSlugsFromDashboards: typeof extractAppSlugsFromDashboards;
|
|
91
104
|
getFlatSpaceFileNames: typeof getFlatSpaceFileNames;
|
|
105
|
+
getDashboardAppSlugs: typeof getDashboardAppSlugs;
|
|
92
106
|
getDashboardChartSlugs: typeof getDashboardChartSlugs;
|
|
93
107
|
hasContentFilters: typeof hasContentFilters;
|
|
94
108
|
isAiAgentsUnavailableError: typeof isAiAgentsUnavailableError;
|
|
95
109
|
isExternalConnectionsUnavailableError: typeof isExternalConnectionsUnavailableError;
|
|
96
110
|
downloadAiAgents: typeof downloadAiAgents;
|
|
111
|
+
isFilteredWithNoDashboards: typeof isFilteredWithNoDashboards;
|
|
97
112
|
readAiAgentFiles: typeof readAiAgentFiles;
|
|
98
113
|
readExternalConnectionFiles: typeof readExternalConnectionFiles;
|
|
99
114
|
readSpaceFiles: typeof readSpaceFiles;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/handlers/download.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,WAAW,EAyBX,WAAW,EAGX,eAAe,
|
|
1
|
+
{"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/handlers/download.ts"],"names":[],"mappings":"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"}
|