jitsu-cli 2.14.0-beta.85 → 2.14.0-beta.96

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jitsu-cli",
3
- "version": "2.14.0-beta.85",
3
+ "version": "2.14.0-beta.96",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/jitsucom/jitsu",
@@ -17,37 +17,21 @@
17
17
  },
18
18
  "license": "MIT",
19
19
  "private": false,
20
- "scripts": {
21
- "clean": "rm -rf ./dist ./compiled",
22
- "typecheck": "tsc --noEmit",
23
- "build": "tsc && tsx build.mts",
24
- "cli": "tsx src/index.ts",
25
- "run": "pnpm build && node dist/main.js",
26
- "login": "pnpm build && node dist/main.js login",
27
- "init child": "pnpm build && node dist/main.js init",
28
- "build child": "pnpm build && node dist/main.js build",
29
- "run child": "pnpm build && node dist/main.js run -e ./data/page.json",
30
- "test child": "pnpm build && node dist/main.js test",
31
- "deploy child": "pnpm build && node dist/main.js deploy"
32
- },
33
20
  "dependencies": {
34
- "esbuild": "catalog:",
21
+ "esbuild": "^0.27.0",
35
22
  "figlet": "^1.6.0",
36
23
  "jest-cli": "^29.7.0",
37
- "tslib": "catalog:",
38
- "typescript": "catalog:"
24
+ "tslib": "^2.6.3",
25
+ "typescript": "^5.6.3"
39
26
  },
40
27
  "devDependencies": {
41
- "@jitsu/common-config": "workspace:*",
42
- "@jitsu/functions-lib": "workspace:*",
43
- "@jitsu/protocols": "workspace:*",
44
28
  "@types/chalk": "^2.2.0",
45
29
  "@types/commander": "^2.12.2",
46
30
  "@types/express": "^4.17.21",
47
31
  "@types/inquirer": "^9.0.3",
48
- "@types/lodash": "catalog:",
49
- "@types/node": "catalog:",
50
- "@vitest/ui": "catalog:",
32
+ "@types/lodash": "^4.17.24",
33
+ "@types/node": "^18.15.3",
34
+ "@vitest/ui": "^4.1.4",
51
35
  "chalk": "^5.3.0",
52
36
  "commander": "^11.0.0",
53
37
  "cross-fetch": "^4.0.0",
@@ -58,11 +42,27 @@
58
42
  "js-yaml": "^4.1.0",
59
43
  "@types/js-yaml": "^4.0.9",
60
44
  "json5": "^2.2.3",
61
- "juava": "workspace:*",
62
- "lodash": "catalog:",
45
+ "lodash": "^4.18.1",
63
46
  "prismjs": "^1.30.0",
64
47
  "semver": "^7.5.4",
65
- "tsx": "catalog:",
66
- "vitest": "catalog:"
48
+ "tsx": "^4.21.0",
49
+ "vitest": "^4.1.4",
50
+ "@jitsu/common-config": "0.0.0",
51
+ "@jitsu/functions-lib": "2.14.0-beta.96",
52
+ "@jitsu/protocols": "2.14.0-beta.96",
53
+ "juava": "0.0.0"
54
+ },
55
+ "scripts": {
56
+ "clean": "rm -rf ./dist ./compiled",
57
+ "typecheck": "tsc --noEmit",
58
+ "build": "tsc && tsx build.mts",
59
+ "cli": "tsx src/index.ts",
60
+ "run": "pnpm build && node dist/main.js",
61
+ "login": "pnpm build && node dist/main.js login",
62
+ "init child": "pnpm build && node dist/main.js init",
63
+ "build child": "pnpm build && node dist/main.js build",
64
+ "run child": "pnpm build && node dist/main.js run -e ./data/page.json",
65
+ "test child": "pnpm build && node dist/main.js test",
66
+ "deploy child": "pnpm build && node dist/main.js deploy"
67
67
  }
68
- }
68
+ }
@@ -143,6 +143,11 @@ async function deployFunctions(
143
143
  profileBuilders = ((await res.json()) as any).profileBuilders as any[];
144
144
  }
145
145
 
146
+ // Fetch the existing function list once for slug/id resolution. Previously
147
+ // every deployFunction() call refetched the whole list (with code blobs) —
148
+ // O(N) requests per deploy, each pulling all N rows from the console DB.
149
+ const existingFunctions = await fetchExistingFunctions({ host, apikey, workspaceId: workspace.id! });
150
+
146
151
  for (const file of selectedFiles) {
147
152
  console.log(
148
153
  `${b(`𝑓`)} Deploying function ${b(path.basename(file))} to workspace ${workspace.name} (${host}/${
@@ -156,11 +161,76 @@ async function deployFunctions(
156
161
  workspace,
157
162
  kind,
158
163
  path.resolve(functionsDir, file),
159
- profileBuilders
164
+ profileBuilders,
165
+ existingFunctions
160
166
  );
161
167
  }
162
168
  }
163
169
 
170
+ // Cache of functions already present in the workspace. byId and bySlug share
171
+ // object identity so a single mutation visible from both. `slug` is tracked
172
+ // per entry so we can detect (and reflect) renames on PUT.
173
+ type ExistingFunction = { id: string; slug?: string };
174
+ type ExistingFunctionsCache = {
175
+ bySlug: Map<string, ExistingFunction>;
176
+ byId: Map<string, ExistingFunction>;
177
+ };
178
+
179
+ async function fetchExistingFunctions({
180
+ host,
181
+ apikey,
182
+ workspaceId,
183
+ }: {
184
+ host?: string;
185
+ apikey?: string;
186
+ workspaceId?: string;
187
+ }): Promise<ExistingFunctionsCache> {
188
+ const res = await fetch(`${host}/api/${workspaceId}/config/function`, {
189
+ headers: { Authorization: `Bearer ${apikey}` },
190
+ });
191
+ if (!res.ok) {
192
+ console.error(red(`Cannot list existing functions:\n${b(await res.text())}`));
193
+ process.exit(1);
194
+ }
195
+ const { objects } = (await res.json()) as { objects: { id: string; slug?: string }[] };
196
+ const bySlug = new Map<string, ExistingFunction>();
197
+ const byId = new Map<string, ExistingFunction>();
198
+ for (const f of objects) {
199
+ const entry: ExistingFunction = { id: f.id, slug: f.slug };
200
+ byId.set(f.id, entry);
201
+ if (f.slug) bySlug.set(f.slug, entry);
202
+ }
203
+ return { bySlug, byId };
204
+ }
205
+
206
+ // Update the cache after a successful POST. Both maps must reflect the new
207
+ // function so a later file with the same slug/id in this same deploy run
208
+ // switches to PUT instead of trying a second POST.
209
+ function cacheAfterCreate(cache: ExistingFunctionsCache, id: string, slug: string | undefined) {
210
+ const entry: ExistingFunction = { id, slug };
211
+ cache.byId.set(id, entry);
212
+ if (slug) cache.bySlug.set(slug, entry);
213
+ }
214
+
215
+ // Update the cache after a successful PUT. Preserves the previous re-fetch
216
+ // semantics for slug renames: the old slug is no longer pointing at this id
217
+ // on the server, so drop it from the slug index and install the new one.
218
+ function cacheAfterUpdate(cache: ExistingFunctionsCache, id: string, newSlug: string | undefined) {
219
+ const entry = cache.byId.get(id);
220
+ if (!entry) {
221
+ // Function existed only on the server, not in our hoisted cache (shouldn't
222
+ // normally happen since the PUT branch only runs when we resolved an id).
223
+ // Insert defensively so later files in this run see it.
224
+ cacheAfterCreate(cache, id, newSlug);
225
+ return;
226
+ }
227
+ if (entry.slug && entry.slug !== newSlug) {
228
+ cache.bySlug.delete(entry.slug);
229
+ }
230
+ entry.slug = newSlug;
231
+ if (newSlug) cache.bySlug.set(newSlug, entry);
232
+ }
233
+
164
234
  async function deployFunction(
165
235
  projectDir: string,
166
236
  { host, apikey }: Args,
@@ -168,7 +238,11 @@ async function deployFunction(
168
238
  workspace: Workspace,
169
239
  kind: "function" | "profile",
170
240
  file: string,
171
- profileBuilders: any[] = []
241
+ profileBuilders: any[] = [],
242
+ existingFunctions: ExistingFunctionsCache = {
243
+ bySlug: new Map(),
244
+ byId: new Map(),
245
+ }
172
246
  ) {
173
247
  const code = readFileSync(file, "utf-8");
174
248
 
@@ -182,18 +256,8 @@ async function deployFunction(
182
256
  }
183
257
  let existingFunctionId: string | undefined;
184
258
  if (meta.slug) {
185
- const res = await fetch(`${host}/api/${workspace.id}/config/function`, {
186
- headers: {
187
- Authorization: `Bearer ${apikey}`,
188
- },
189
- });
190
- if (!res.ok) {
191
- console.error(red(`Cannot add function to workspace:\n${b(await res.text())}`));
192
- process.exit(1);
193
- } else {
194
- const existing = (await res.json()) as any;
195
- existingFunctionId = existing.objects.find(f => f.slug === meta.slug || f.id === meta.id)?.id;
196
- }
259
+ existingFunctionId =
260
+ existingFunctions.bySlug.get(meta.slug)?.id ?? (meta.id ? existingFunctions.byId.get(meta.id)?.id : undefined);
197
261
  }
198
262
  let functionPayload = {};
199
263
  if (kind === "profile") {
@@ -231,6 +295,11 @@ async function deployFunction(
231
295
  console.error(red(`Cannot add function to workspace:\n${b(await res.text())}`));
232
296
  process.exit(1);
233
297
  } else {
298
+ // Reflect the new function in the hoisted cache so a later file in
299
+ // this same deploy that targets the same slug switches to PUT instead
300
+ // of POSTing a duplicate. Matches the pre-hoist behavior where each
301
+ // file re-fetched the list.
302
+ cacheAfterCreate(existingFunctions, id, meta.slug);
234
303
  console.log(`Function ${b(meta.name)} was successfully added to workspace ${workspace.name} with id: ${b(id)}`);
235
304
  }
236
305
  } else {
@@ -256,6 +325,10 @@ async function deployFunction(
256
325
  console.error(red(`⚠ Cannot deploy function ${b(meta.slug)}(${id}):\n${b(await res.text())}`));
257
326
  process.exit(1);
258
327
  } else {
328
+ // Slug may have been renamed by this PUT — update the slug index so a
329
+ // later file deploying under the old slug (if any) creates a new
330
+ // function instead of clobbering this one.
331
+ cacheAfterUpdate(existingFunctions, id, meta.slug);
259
332
  console.log(`${green(`✓`)} ${b(meta.name)} deployed successfully!`);
260
333
  }
261
334
  }