@getjack/jack 0.1.33 → 0.1.35
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/README.md +6 -6
- package/package.json +1 -1
- package/src/commands/down.ts +39 -7
- package/src/commands/link.ts +2 -4
- package/src/commands/logs.ts +2 -4
- package/src/commands/mcp.ts +12 -10
- package/src/commands/secrets.ts +3 -1
- package/src/commands/services.ts +4 -2
- package/src/commands/sync.ts +5 -6
- package/src/lib/auth/client.ts +5 -2
- package/src/lib/binding-validator.ts +39 -3
- package/src/lib/build-helper.ts +18 -19
- package/src/lib/control-plane.ts +1 -0
- package/src/lib/crypto.ts +84 -0
- package/src/lib/deploy-upload.ts +7 -3
- package/src/lib/do-config.ts +110 -0
- package/src/lib/do-export-validator.ts +26 -0
- package/src/lib/hooks.ts +1 -2
- package/src/lib/jsonc-edit.ts +292 -0
- package/src/lib/managed-deploy.ts +36 -1
- package/src/lib/project-link.ts +37 -0
- package/src/lib/project-operations.ts +37 -46
- package/src/lib/prompts.ts +2 -2
- package/src/lib/resources.ts +4 -5
- package/src/lib/schema.ts +8 -12
- package/src/lib/services/db-create.ts +2 -2
- package/src/lib/services/db-execute.ts +9 -6
- package/src/lib/services/db-list.ts +6 -4
- package/src/lib/services/endpoint-test.ts +275 -0
- package/src/lib/services/project-delete.ts +190 -0
- package/src/lib/services/project-environment.ts +457 -0
- package/src/lib/services/storage-config.ts +7 -309
- package/src/lib/services/storage-create.ts +2 -1
- package/src/lib/services/storage-delete.ts +3 -2
- package/src/lib/services/storage-info.ts +2 -1
- package/src/lib/services/storage-list.ts +6 -3
- package/src/lib/services/vectorize-config.ts +7 -264
- package/src/lib/services/vectorize-create.ts +2 -1
- package/src/lib/services/vectorize-delete.ts +6 -4
- package/src/lib/services/vectorize-list.ts +6 -3
- package/src/lib/storage/index.ts +21 -23
- package/src/lib/telemetry.ts +1 -0
- package/src/lib/wrangler-config.ts +43 -312
- package/src/lib/zip-packager.ts +28 -0
- package/src/mcp/test-utils.ts +31 -0
- package/src/mcp/tools/index.ts +271 -0
- package/src/templates/index.ts +5 -0
- package/src/templates/types.ts +4 -0
- package/templates/AI-BINDINGS.md +34 -76
- package/templates/CLAUDE.md +22 -1
- package/templates/ai-chat/src/index.ts +7 -14
- package/templates/ai-chat/src/jack-ai.ts +0 -6
- package/templates/chat/.jack.json +45 -0
- package/templates/chat/bun.lock +1588 -0
- package/templates/chat/components.json +23 -0
- package/templates/chat/index.html +12 -0
- package/templates/chat/package.json +41 -0
- package/templates/chat/src/chat-agent.ts +61 -0
- package/templates/chat/src/client/app.tsx +189 -0
- package/templates/chat/src/client/chat.tsx +222 -0
- package/templates/chat/src/client/components/prompt-kit/chat-container.tsx +47 -0
- package/templates/chat/src/client/components/prompt-kit/loader.tsx +33 -0
- package/templates/chat/src/client/components/prompt-kit/markdown.tsx +84 -0
- package/templates/chat/src/client/components/prompt-kit/message.tsx +54 -0
- package/templates/chat/src/client/components/prompt-kit/prompt-suggestion.tsx +20 -0
- package/templates/chat/src/client/components/prompt-kit/reasoning.tsx +134 -0
- package/templates/chat/src/client/components/prompt-kit/scroll-button.tsx +28 -0
- package/templates/chat/src/client/components/ui/button.tsx +38 -0
- package/templates/chat/src/client/lib/utils.ts +6 -0
- package/templates/chat/src/client/main.tsx +11 -0
- package/templates/chat/src/client/styles.css +125 -0
- package/templates/chat/src/index.ts +25 -0
- package/templates/chat/src/jack-ai.ts +94 -0
- package/templates/chat/tsconfig.json +18 -0
- package/templates/chat/vite.config.ts +14 -0
- package/templates/chat/wrangler.jsonc +18 -0
- package/templates/cron/.jack.json +18 -28
- package/templates/cron/schema.sql +10 -20
- package/templates/cron/src/admin.ts +321 -0
- package/templates/cron/src/index.ts +151 -81
- package/templates/cron/src/monitor.ts +124 -0
- package/templates/nextjs-clerk/app/layout.tsx +2 -0
- package/templates/semantic-search/src/index.ts +5 -43
- package/templates/semantic-search/src/jack-ai.ts +0 -6
- package/templates/telegram-bot/.jack.json +56 -0
- package/templates/telegram-bot/bun.lock +41 -0
- package/templates/telegram-bot/package.json +16 -0
- package/templates/telegram-bot/src/index.ts +236 -0
- package/templates/telegram-bot/src/jack-ai.ts +100 -0
- package/templates/telegram-bot/tsconfig.json +11 -0
- package/templates/telegram-bot/wrangler.jsonc +8 -0
- package/templates/cron/src/jobs.ts +0 -139
- package/templates/cron/src/webhooks.ts +0 -95
- package/templates/semantic-search/src/jack-vectorize.ts +0 -169
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { existsSync } from "node:fs";
|
|
6
|
+
import {
|
|
7
|
+
addSectionBeforeClosingBrace,
|
|
8
|
+
findLastObjectEndInArray,
|
|
9
|
+
findMatchingBracket,
|
|
10
|
+
isOnlyCommentsAndWhitespace,
|
|
11
|
+
} from "../jsonc-edit.ts";
|
|
6
12
|
import { parseJsonc } from "../jsonc.ts";
|
|
7
13
|
|
|
8
14
|
export interface R2BindingConfig {
|
|
@@ -167,315 +173,7 @@ function appendToR2BucketsArray(content: string, bindingJson: string): string {
|
|
|
167
173
|
* Inserts before the final closing brace.
|
|
168
174
|
*/
|
|
169
175
|
function addR2BucketsSection(content: string, bindingJson: string): string {
|
|
170
|
-
|
|
171
|
-
const lastBraceIndex = content.lastIndexOf("}");
|
|
172
|
-
if (lastBraceIndex === -1) {
|
|
173
|
-
throw new Error("Invalid JSON: no closing brace found");
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Check what comes before the last brace to determine if we need a comma
|
|
177
|
-
const beforeBrace = content.slice(0, lastBraceIndex);
|
|
178
|
-
const needsComma = shouldAddCommaBefore(beforeBrace);
|
|
179
|
-
|
|
180
|
-
// Build the r2_buckets section
|
|
181
|
-
const r2Section = `"r2_buckets": [
|
|
182
|
-
${bindingJson}
|
|
183
|
-
]`;
|
|
184
|
-
|
|
185
|
-
// Find proper insertion point - look for last non-whitespace content
|
|
186
|
-
const trimmedBefore = beforeBrace.trimEnd();
|
|
187
|
-
|
|
188
|
-
let insertion: string;
|
|
189
|
-
if (needsComma) {
|
|
190
|
-
insertion = `,\n\t${r2Section}`;
|
|
191
|
-
} else {
|
|
192
|
-
insertion = `\n\t${r2Section}`;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Reconstruct: content before + insertion + newline + closing brace
|
|
196
|
-
return trimmedBefore + insertion + "\n" + content.slice(lastBraceIndex);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Find the matching closing bracket/brace for an opening one
|
|
201
|
-
*/
|
|
202
|
-
function findMatchingBracket(
|
|
203
|
-
content: string,
|
|
204
|
-
startIndex: number,
|
|
205
|
-
openChar: string,
|
|
206
|
-
closeChar: string,
|
|
207
|
-
): number {
|
|
208
|
-
let depth = 0;
|
|
209
|
-
let inString = false;
|
|
210
|
-
let stringChar = "";
|
|
211
|
-
let escaped = false;
|
|
212
|
-
let inLineComment = false;
|
|
213
|
-
let inBlockComment = false;
|
|
214
|
-
|
|
215
|
-
for (let i = startIndex; i < content.length; i++) {
|
|
216
|
-
const char = content[i] ?? "";
|
|
217
|
-
const next = content[i + 1] ?? "";
|
|
218
|
-
|
|
219
|
-
// Handle line comments
|
|
220
|
-
if (inLineComment) {
|
|
221
|
-
if (char === "\n") {
|
|
222
|
-
inLineComment = false;
|
|
223
|
-
}
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Handle block comments
|
|
228
|
-
if (inBlockComment) {
|
|
229
|
-
if (char === "*" && next === "/") {
|
|
230
|
-
inBlockComment = false;
|
|
231
|
-
i++;
|
|
232
|
-
}
|
|
233
|
-
continue;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Handle strings
|
|
237
|
-
if (inString) {
|
|
238
|
-
if (escaped) {
|
|
239
|
-
escaped = false;
|
|
240
|
-
continue;
|
|
241
|
-
}
|
|
242
|
-
if (char === "\\") {
|
|
243
|
-
escaped = true;
|
|
244
|
-
continue;
|
|
245
|
-
}
|
|
246
|
-
if (char === stringChar) {
|
|
247
|
-
inString = false;
|
|
248
|
-
stringChar = "";
|
|
249
|
-
}
|
|
250
|
-
continue;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Check for comment start
|
|
254
|
-
if (char === "/" && next === "/") {
|
|
255
|
-
inLineComment = true;
|
|
256
|
-
i++;
|
|
257
|
-
continue;
|
|
258
|
-
}
|
|
259
|
-
if (char === "/" && next === "*") {
|
|
260
|
-
inBlockComment = true;
|
|
261
|
-
i++;
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Check for string start
|
|
266
|
-
if (char === '"' || char === "'") {
|
|
267
|
-
inString = true;
|
|
268
|
-
stringChar = char;
|
|
269
|
-
continue;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// Track bracket depth
|
|
273
|
-
if (char === openChar) {
|
|
274
|
-
depth++;
|
|
275
|
-
} else if (char === closeChar) {
|
|
276
|
-
depth--;
|
|
277
|
-
if (depth === 0) {
|
|
278
|
-
return i;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
return -1;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Check if content is only whitespace and comments
|
|
288
|
-
*/
|
|
289
|
-
function isOnlyCommentsAndWhitespace(content: string): boolean {
|
|
290
|
-
let inLineComment = false;
|
|
291
|
-
let inBlockComment = false;
|
|
292
|
-
|
|
293
|
-
for (let i = 0; i < content.length; i++) {
|
|
294
|
-
const char = content[i] ?? "";
|
|
295
|
-
const next = content[i + 1] ?? "";
|
|
296
|
-
|
|
297
|
-
if (inLineComment) {
|
|
298
|
-
if (char === "\n") {
|
|
299
|
-
inLineComment = false;
|
|
300
|
-
}
|
|
301
|
-
continue;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
if (inBlockComment) {
|
|
305
|
-
if (char === "*" && next === "/") {
|
|
306
|
-
inBlockComment = false;
|
|
307
|
-
i++;
|
|
308
|
-
}
|
|
309
|
-
continue;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
if (char === "/" && next === "/") {
|
|
313
|
-
inLineComment = true;
|
|
314
|
-
i++;
|
|
315
|
-
continue;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
if (char === "/" && next === "*") {
|
|
319
|
-
inBlockComment = true;
|
|
320
|
-
i++;
|
|
321
|
-
continue;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (!/\s/.test(char)) {
|
|
325
|
-
return false;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return true;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* Find the last closing brace of an object within an array range
|
|
334
|
-
*/
|
|
335
|
-
function findLastObjectEndInArray(content: string, startIndex: number, endIndex: number): number {
|
|
336
|
-
let lastBraceIndex = -1;
|
|
337
|
-
let inString = false;
|
|
338
|
-
let stringChar = "";
|
|
339
|
-
let escaped = false;
|
|
340
|
-
let inLineComment = false;
|
|
341
|
-
let inBlockComment = false;
|
|
342
|
-
|
|
343
|
-
for (let i = startIndex; i < endIndex; i++) {
|
|
344
|
-
const char = content[i] ?? "";
|
|
345
|
-
const next = content[i + 1] ?? "";
|
|
346
|
-
|
|
347
|
-
if (inLineComment) {
|
|
348
|
-
if (char === "\n") {
|
|
349
|
-
inLineComment = false;
|
|
350
|
-
}
|
|
351
|
-
continue;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
if (inBlockComment) {
|
|
355
|
-
if (char === "*" && next === "/") {
|
|
356
|
-
inBlockComment = false;
|
|
357
|
-
i++;
|
|
358
|
-
}
|
|
359
|
-
continue;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
if (inString) {
|
|
363
|
-
if (escaped) {
|
|
364
|
-
escaped = false;
|
|
365
|
-
continue;
|
|
366
|
-
}
|
|
367
|
-
if (char === "\\") {
|
|
368
|
-
escaped = true;
|
|
369
|
-
continue;
|
|
370
|
-
}
|
|
371
|
-
if (char === stringChar) {
|
|
372
|
-
inString = false;
|
|
373
|
-
stringChar = "";
|
|
374
|
-
}
|
|
375
|
-
continue;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
if (char === "/" && next === "/") {
|
|
379
|
-
inLineComment = true;
|
|
380
|
-
i++;
|
|
381
|
-
continue;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
if (char === "/" && next === "*") {
|
|
385
|
-
inBlockComment = true;
|
|
386
|
-
i++;
|
|
387
|
-
continue;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
if (char === '"' || char === "'") {
|
|
391
|
-
inString = true;
|
|
392
|
-
stringChar = char;
|
|
393
|
-
continue;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
if (char === "}") {
|
|
397
|
-
lastBraceIndex = i;
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
return lastBraceIndex;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* Determine if we need to add a comma before new content.
|
|
406
|
-
* Looks at the last non-whitespace, non-comment character.
|
|
407
|
-
*/
|
|
408
|
-
function shouldAddCommaBefore(content: string): boolean {
|
|
409
|
-
// Strip trailing comments and whitespace to find last meaningful char
|
|
410
|
-
let i = content.length - 1;
|
|
411
|
-
|
|
412
|
-
// First pass: find where any trailing line comment starts
|
|
413
|
-
for (let j = content.length - 1; j >= 0; j--) {
|
|
414
|
-
if (content[j] === "\n") {
|
|
415
|
-
// Check if there's a // comment on this line
|
|
416
|
-
const lineStart = content.lastIndexOf("\n", j - 1) + 1;
|
|
417
|
-
const line = content.slice(lineStart, j);
|
|
418
|
-
const commentIndex = findLineCommentStart(line);
|
|
419
|
-
if (commentIndex !== -1) {
|
|
420
|
-
i = lineStart + commentIndex - 1;
|
|
421
|
-
}
|
|
422
|
-
break;
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
// Skip whitespace
|
|
427
|
-
while (i >= 0 && /\s/.test(content[i] ?? "")) {
|
|
428
|
-
i--;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
if (i < 0) return false;
|
|
432
|
-
|
|
433
|
-
const lastChar = content[i];
|
|
434
|
-
// Need comma if last char is }, ], ", number, or identifier char
|
|
435
|
-
// Don't need comma if last char is { or [ or ,
|
|
436
|
-
return lastChar !== "{" && lastChar !== "[" && lastChar !== ",";
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* Find the start of a line comment (//) in a string, respecting strings
|
|
441
|
-
*/
|
|
442
|
-
function findLineCommentStart(line: string): number {
|
|
443
|
-
let inString = false;
|
|
444
|
-
let stringChar = "";
|
|
445
|
-
let escaped = false;
|
|
446
|
-
|
|
447
|
-
for (let i = 0; i < line.length - 1; i++) {
|
|
448
|
-
const char = line[i] ?? "";
|
|
449
|
-
const next = line[i + 1] ?? "";
|
|
450
|
-
|
|
451
|
-
if (inString) {
|
|
452
|
-
if (escaped) {
|
|
453
|
-
escaped = false;
|
|
454
|
-
continue;
|
|
455
|
-
}
|
|
456
|
-
if (char === "\\") {
|
|
457
|
-
escaped = true;
|
|
458
|
-
continue;
|
|
459
|
-
}
|
|
460
|
-
if (char === stringChar) {
|
|
461
|
-
inString = false;
|
|
462
|
-
stringChar = "";
|
|
463
|
-
}
|
|
464
|
-
continue;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
if (char === '"' || char === "'") {
|
|
468
|
-
inString = true;
|
|
469
|
-
stringChar = char;
|
|
470
|
-
continue;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
if (char === "/" && next === "/") {
|
|
474
|
-
return i;
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
return -1;
|
|
176
|
+
return addSectionBeforeClosingBrace(content, `"r2_buckets": [\n\t\t${bindingJson}\n\t]`);
|
|
479
177
|
}
|
|
480
178
|
|
|
481
179
|
/**
|
|
@@ -9,6 +9,7 @@ import { $ } from "bun";
|
|
|
9
9
|
import { createProjectResource } from "../control-plane.ts";
|
|
10
10
|
import { readProjectLink } from "../project-link.ts";
|
|
11
11
|
import { getProjectNameFromDir } from "../storage/index.ts";
|
|
12
|
+
import { findWranglerConfig } from "../wrangler-config.ts";
|
|
12
13
|
import {
|
|
13
14
|
addR2Binding,
|
|
14
15
|
generateBucketName,
|
|
@@ -103,7 +104,7 @@ export async function createStorageBucket(
|
|
|
103
104
|
const projectName = await getProjectNameFromDir(projectDir);
|
|
104
105
|
|
|
105
106
|
// Get existing R2 bindings to determine naming
|
|
106
|
-
const wranglerPath = join(projectDir, "wrangler.jsonc");
|
|
107
|
+
const wranglerPath = findWranglerConfig(projectDir) ?? join(projectDir, "wrangler.jsonc");
|
|
107
108
|
const existingBindings = await getExistingR2Bindings(wranglerPath);
|
|
108
109
|
const existingCount = existingBindings.length;
|
|
109
110
|
|
|
@@ -8,6 +8,7 @@ import { join } from "node:path";
|
|
|
8
8
|
import { $ } from "bun";
|
|
9
9
|
import { deleteProjectResource, fetchProjectResources } from "../control-plane.ts";
|
|
10
10
|
import { readProjectLink } from "../project-link.ts";
|
|
11
|
+
import { findWranglerConfig } from "../wrangler-config.ts";
|
|
11
12
|
import { getExistingR2Bindings, removeR2Binding } from "./storage-config.ts";
|
|
12
13
|
|
|
13
14
|
export interface DeleteStorageBucketResult {
|
|
@@ -49,9 +50,9 @@ export async function deleteStorageBucket(
|
|
|
49
50
|
throw new Error("Not in a jack project. Run 'jack new' to create a project.");
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
const wranglerPath = join(projectDir, "wrangler.jsonc");
|
|
53
|
+
const wranglerPath = findWranglerConfig(projectDir) ?? join(projectDir, "wrangler.jsonc");
|
|
53
54
|
|
|
54
|
-
// Verify bucket exists in wrangler
|
|
55
|
+
// Verify bucket exists in wrangler config
|
|
55
56
|
const bindings = await getExistingR2Bindings(wranglerPath);
|
|
56
57
|
const binding = bindings.find((b) => b.bucket_name === bucketName);
|
|
57
58
|
|
|
@@ -9,6 +9,7 @@ import { join } from "node:path";
|
|
|
9
9
|
import { $ } from "bun";
|
|
10
10
|
import { fetchProjectResources } from "../control-plane.ts";
|
|
11
11
|
import { readProjectLink } from "../project-link.ts";
|
|
12
|
+
import { findWranglerConfig } from "../wrangler-config.ts";
|
|
12
13
|
import { getExistingR2Bindings } from "./storage-config.ts";
|
|
13
14
|
|
|
14
15
|
export interface StorageBucketInfo {
|
|
@@ -46,7 +47,7 @@ export async function getStorageBucketInfo(
|
|
|
46
47
|
projectDir: string,
|
|
47
48
|
bucketName?: string,
|
|
48
49
|
): Promise<StorageBucketInfo | null> {
|
|
49
|
-
const wranglerPath = join(projectDir, "wrangler.jsonc");
|
|
50
|
+
const wranglerPath = findWranglerConfig(projectDir) ?? join(projectDir, "wrangler.jsonc");
|
|
50
51
|
|
|
51
52
|
// Read deploy mode from .jack/project.json
|
|
52
53
|
const link = await readProjectLink(projectDir);
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* For managed projects, fetches metadata via control plane instead of wrangler.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { findWranglerConfig } from "../wrangler-config.ts";
|
|
9
9
|
import { getExistingR2Bindings } from "./storage-config.ts";
|
|
10
10
|
|
|
11
11
|
export interface StorageBucketListEntry {
|
|
@@ -23,9 +23,12 @@ export interface StorageBucketListEntry {
|
|
|
23
23
|
* the configured bindings. For detailed info, use storage info.
|
|
24
24
|
*/
|
|
25
25
|
export async function listStorageBuckets(projectDir: string): Promise<StorageBucketListEntry[]> {
|
|
26
|
-
const wranglerPath =
|
|
26
|
+
const wranglerPath = findWranglerConfig(projectDir);
|
|
27
|
+
if (!wranglerPath) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
27
30
|
|
|
28
|
-
// Get existing R2 bindings from wrangler
|
|
31
|
+
// Get existing R2 bindings from wrangler config
|
|
29
32
|
const bindings = await getExistingR2Bindings(wranglerPath);
|
|
30
33
|
|
|
31
34
|
if (bindings.length === 0) {
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { existsSync } from "node:fs";
|
|
6
|
+
import {
|
|
7
|
+
addSectionBeforeClosingBrace,
|
|
8
|
+
findLastObjectEndInArray,
|
|
9
|
+
findMatchingBracket,
|
|
10
|
+
isOnlyCommentsAndWhitespace,
|
|
11
|
+
} from "../jsonc-edit.ts";
|
|
6
12
|
import { parseJsonc } from "../jsonc.ts";
|
|
7
13
|
|
|
8
14
|
export interface VectorizeBindingConfig {
|
|
@@ -132,28 +138,7 @@ function appendToVectorizeArray(content: string, bindingJson: string): string {
|
|
|
132
138
|
* Add a new vectorize section to the config.
|
|
133
139
|
*/
|
|
134
140
|
function addVectorizeSection(content: string, bindingJson: string): string {
|
|
135
|
-
|
|
136
|
-
if (lastBraceIndex === -1) {
|
|
137
|
-
throw new Error("Invalid JSON: no closing brace found");
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const beforeBrace = content.slice(0, lastBraceIndex);
|
|
141
|
-
const needsComma = shouldAddCommaBefore(beforeBrace);
|
|
142
|
-
|
|
143
|
-
const vecSection = `"vectorize": [
|
|
144
|
-
${bindingJson}
|
|
145
|
-
]`;
|
|
146
|
-
|
|
147
|
-
const trimmedBefore = beforeBrace.trimEnd();
|
|
148
|
-
|
|
149
|
-
let insertion: string;
|
|
150
|
-
if (needsComma) {
|
|
151
|
-
insertion = `,\n\t${vecSection}`;
|
|
152
|
-
} else {
|
|
153
|
-
insertion = `\n\t${vecSection}`;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return trimmedBefore + insertion + "\n" + content.slice(lastBraceIndex);
|
|
141
|
+
return addSectionBeforeClosingBrace(content, `"vectorize": [\n\t\t${bindingJson}\n\t]`);
|
|
157
142
|
}
|
|
158
143
|
|
|
159
144
|
/**
|
|
@@ -276,248 +261,6 @@ function removeVectorizeProperty(content: string, propertyStart: number, arrayEn
|
|
|
276
261
|
return content.slice(0, removeStart) + content.slice(removeEnd);
|
|
277
262
|
}
|
|
278
263
|
|
|
279
|
-
// Helper functions (same as in wrangler-config.ts)
|
|
280
|
-
|
|
281
|
-
function findMatchingBracket(
|
|
282
|
-
content: string,
|
|
283
|
-
startIndex: number,
|
|
284
|
-
openChar: string,
|
|
285
|
-
closeChar: string,
|
|
286
|
-
): number {
|
|
287
|
-
let depth = 0;
|
|
288
|
-
let inString = false;
|
|
289
|
-
let stringChar = "";
|
|
290
|
-
let escaped = false;
|
|
291
|
-
let inLineComment = false;
|
|
292
|
-
let inBlockComment = false;
|
|
293
|
-
|
|
294
|
-
for (let i = startIndex; i < content.length; i++) {
|
|
295
|
-
const char = content[i] ?? "";
|
|
296
|
-
const next = content[i + 1] ?? "";
|
|
297
|
-
|
|
298
|
-
if (inLineComment) {
|
|
299
|
-
if (char === "\n") inLineComment = false;
|
|
300
|
-
continue;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
if (inBlockComment) {
|
|
304
|
-
if (char === "*" && next === "/") {
|
|
305
|
-
inBlockComment = false;
|
|
306
|
-
i++;
|
|
307
|
-
}
|
|
308
|
-
continue;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
if (inString) {
|
|
312
|
-
if (escaped) {
|
|
313
|
-
escaped = false;
|
|
314
|
-
continue;
|
|
315
|
-
}
|
|
316
|
-
if (char === "\\") {
|
|
317
|
-
escaped = true;
|
|
318
|
-
continue;
|
|
319
|
-
}
|
|
320
|
-
if (char === stringChar) {
|
|
321
|
-
inString = false;
|
|
322
|
-
stringChar = "";
|
|
323
|
-
}
|
|
324
|
-
continue;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
if (char === "/" && next === "/") {
|
|
328
|
-
inLineComment = true;
|
|
329
|
-
i++;
|
|
330
|
-
continue;
|
|
331
|
-
}
|
|
332
|
-
if (char === "/" && next === "*") {
|
|
333
|
-
inBlockComment = true;
|
|
334
|
-
i++;
|
|
335
|
-
continue;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
if (char === '"' || char === "'") {
|
|
339
|
-
inString = true;
|
|
340
|
-
stringChar = char;
|
|
341
|
-
continue;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
if (char === openChar) {
|
|
345
|
-
depth++;
|
|
346
|
-
} else if (char === closeChar) {
|
|
347
|
-
depth--;
|
|
348
|
-
if (depth === 0) return i;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
return -1;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
function isOnlyCommentsAndWhitespace(content: string): boolean {
|
|
356
|
-
let inLineComment = false;
|
|
357
|
-
let inBlockComment = false;
|
|
358
|
-
|
|
359
|
-
for (let i = 0; i < content.length; i++) {
|
|
360
|
-
const char = content[i] ?? "";
|
|
361
|
-
const next = content[i + 1] ?? "";
|
|
362
|
-
|
|
363
|
-
if (inLineComment) {
|
|
364
|
-
if (char === "\n") inLineComment = false;
|
|
365
|
-
continue;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
if (inBlockComment) {
|
|
369
|
-
if (char === "*" && next === "/") {
|
|
370
|
-
inBlockComment = false;
|
|
371
|
-
i++;
|
|
372
|
-
}
|
|
373
|
-
continue;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
if (char === "/" && next === "/") {
|
|
377
|
-
inLineComment = true;
|
|
378
|
-
i++;
|
|
379
|
-
continue;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
if (char === "/" && next === "*") {
|
|
383
|
-
inBlockComment = true;
|
|
384
|
-
i++;
|
|
385
|
-
continue;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
if (!/\s/.test(char)) return false;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
return true;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
function findLastObjectEndInArray(content: string, startIndex: number, endIndex: number): number {
|
|
395
|
-
let lastBraceIndex = -1;
|
|
396
|
-
let inString = false;
|
|
397
|
-
let stringChar = "";
|
|
398
|
-
let escaped = false;
|
|
399
|
-
let inLineComment = false;
|
|
400
|
-
let inBlockComment = false;
|
|
401
|
-
|
|
402
|
-
for (let i = startIndex; i < endIndex; i++) {
|
|
403
|
-
const char = content[i] ?? "";
|
|
404
|
-
const next = content[i + 1] ?? "";
|
|
405
|
-
|
|
406
|
-
if (inLineComment) {
|
|
407
|
-
if (char === "\n") inLineComment = false;
|
|
408
|
-
continue;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
if (inBlockComment) {
|
|
412
|
-
if (char === "*" && next === "/") {
|
|
413
|
-
inBlockComment = false;
|
|
414
|
-
i++;
|
|
415
|
-
}
|
|
416
|
-
continue;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
if (inString) {
|
|
420
|
-
if (escaped) {
|
|
421
|
-
escaped = false;
|
|
422
|
-
continue;
|
|
423
|
-
}
|
|
424
|
-
if (char === "\\") {
|
|
425
|
-
escaped = true;
|
|
426
|
-
continue;
|
|
427
|
-
}
|
|
428
|
-
if (char === stringChar) {
|
|
429
|
-
inString = false;
|
|
430
|
-
stringChar = "";
|
|
431
|
-
}
|
|
432
|
-
continue;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
if (char === "/" && next === "/") {
|
|
436
|
-
inLineComment = true;
|
|
437
|
-
i++;
|
|
438
|
-
continue;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
if (char === "/" && next === "*") {
|
|
442
|
-
inBlockComment = true;
|
|
443
|
-
i++;
|
|
444
|
-
continue;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
if (char === '"' || char === "'") {
|
|
448
|
-
inString = true;
|
|
449
|
-
stringChar = char;
|
|
450
|
-
continue;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
if (char === "}") lastBraceIndex = i;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
return lastBraceIndex;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
function shouldAddCommaBefore(content: string): boolean {
|
|
460
|
-
let i = content.length - 1;
|
|
461
|
-
|
|
462
|
-
for (let j = content.length - 1; j >= 0; j--) {
|
|
463
|
-
if (content[j] === "\n") {
|
|
464
|
-
const lineStart = content.lastIndexOf("\n", j - 1) + 1;
|
|
465
|
-
const line = content.slice(lineStart, j);
|
|
466
|
-
const commentIndex = findLineCommentStart(line);
|
|
467
|
-
if (commentIndex !== -1) {
|
|
468
|
-
i = lineStart + commentIndex - 1;
|
|
469
|
-
}
|
|
470
|
-
break;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
while (i >= 0 && /\s/.test(content[i] ?? "")) {
|
|
475
|
-
i--;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
if (i < 0) return false;
|
|
479
|
-
|
|
480
|
-
const lastChar = content[i];
|
|
481
|
-
return lastChar !== "{" && lastChar !== "[" && lastChar !== ",";
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
function findLineCommentStart(line: string): number {
|
|
485
|
-
let inString = false;
|
|
486
|
-
let stringChar = "";
|
|
487
|
-
let escaped = false;
|
|
488
|
-
|
|
489
|
-
for (let i = 0; i < line.length - 1; i++) {
|
|
490
|
-
const char = line[i] ?? "";
|
|
491
|
-
const next = line[i + 1] ?? "";
|
|
492
|
-
|
|
493
|
-
if (inString) {
|
|
494
|
-
if (escaped) {
|
|
495
|
-
escaped = false;
|
|
496
|
-
continue;
|
|
497
|
-
}
|
|
498
|
-
if (char === "\\") {
|
|
499
|
-
escaped = true;
|
|
500
|
-
continue;
|
|
501
|
-
}
|
|
502
|
-
if (char === stringChar) {
|
|
503
|
-
inString = false;
|
|
504
|
-
stringChar = "";
|
|
505
|
-
}
|
|
506
|
-
continue;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
if (char === '"' || char === "'") {
|
|
510
|
-
inString = true;
|
|
511
|
-
stringChar = char;
|
|
512
|
-
continue;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
if (char === "/" && next === "/") return i;
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
return -1;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
264
|
function findObjectStartBefore(content: string, fromPos: number): number {
|
|
522
265
|
let depth = 0;
|
|
523
266
|
for (let i = fromPos; i >= 0; i--) {
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
import { $ } from "bun";
|
|
9
9
|
import { getProjectNameFromDir } from "../storage/index.ts";
|
|
10
|
+
import { findWranglerConfig } from "../wrangler-config.ts";
|
|
10
11
|
import { addVectorizeBinding, getExistingVectorizeBindings } from "./vectorize-config.ts";
|
|
11
12
|
|
|
12
13
|
export type VectorizeMetric = "cosine" | "euclidean" | "dot-product";
|
|
@@ -128,7 +129,7 @@ export async function createVectorizeIndex(
|
|
|
128
129
|
const projectName = await getProjectNameFromDir(projectDir);
|
|
129
130
|
|
|
130
131
|
// Get existing Vectorize bindings to determine naming
|
|
131
|
-
const wranglerPath = join(projectDir, "wrangler.jsonc");
|
|
132
|
+
const wranglerPath = findWranglerConfig(projectDir) ?? join(projectDir, "wrangler.jsonc");
|
|
132
133
|
const existingBindings = await getExistingVectorizeBindings(wranglerPath);
|
|
133
134
|
const existingCount = existingBindings.length;
|
|
134
135
|
|