@insforge/mcp 1.2.8 → 1.2.10-dev.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.
@@ -41,17 +41,40 @@ ${JSON.stringify(data, null, 2)}`;
41
41
 
42
42
  // src/shared/usage-tracker.ts
43
43
  import fetch from "node-fetch";
44
+ var PLATFORM_API_BASE = "https://api.insforge.dev";
45
+ function parseAppKey(apiBaseUrl) {
46
+ try {
47
+ const url = new URL(apiBaseUrl);
48
+ const match = url.hostname.match(/^([^.]+)\.[^.]+\.insforge\.app$/);
49
+ return match ? match[1] : null;
50
+ } catch {
51
+ return null;
52
+ }
53
+ }
44
54
  var UsageTracker = class {
45
55
  apiBaseUrl;
46
56
  apiKey;
47
- constructor(apiBaseUrl, apiKey) {
57
+ agentConnectedReported = false;
58
+ projectId;
59
+ accessToken;
60
+ isRemote;
61
+ constructor(apiBaseUrl, apiKey, options) {
48
62
  this.apiBaseUrl = apiBaseUrl;
49
63
  this.apiKey = apiKey;
64
+ this.projectId = options?.projectId;
65
+ this.accessToken = options?.accessToken;
66
+ this.isRemote = options?.isRemote ?? false;
50
67
  }
51
68
  async trackUsage(toolName, success = true) {
52
69
  if (!this.apiKey) {
53
70
  return;
54
71
  }
72
+ if (!this.agentConnectedReported) {
73
+ this.agentConnectedReported = true;
74
+ this.reportAgentConnected().catch((error) => {
75
+ console.error("Failed to report agent-connected:", error);
76
+ });
77
+ }
55
78
  try {
56
79
  const payload = {
57
80
  tool_name: toolName,
@@ -70,6 +93,27 @@ var UsageTracker = class {
70
93
  console.error("Failed to track usage:", error);
71
94
  }
72
95
  }
96
+ async reportAgentConnected() {
97
+ const body = {};
98
+ const headers = { "Content-Type": "application/json" };
99
+ if (this.isRemote && this.projectId && this.projectId !== "legacy") {
100
+ body.project_id = this.projectId;
101
+ if (this.accessToken) {
102
+ headers["Authorization"] = `Bearer ${this.accessToken}`;
103
+ }
104
+ } else {
105
+ const appKey = parseAppKey(this.apiBaseUrl);
106
+ if (!appKey) {
107
+ return;
108
+ }
109
+ body.app_key = appKey;
110
+ }
111
+ await fetch(`${PLATFORM_API_BASE}/tracking/v1/agent-connected`, {
112
+ method: "POST",
113
+ headers,
114
+ body: JSON.stringify(body)
115
+ });
116
+ }
73
117
  };
74
118
 
75
119
  // src/shared/tools/docs.ts
@@ -394,6 +438,12 @@ var storageBucketSchema = z5.object({
394
438
  public: z5.boolean(),
395
439
  createdAt: z5.string()
396
440
  });
441
+ var storageConfigSchema = z5.object({
442
+ id: z5.string().uuid(),
443
+ maxFileSizeMb: z5.number().int().positive(),
444
+ createdAt: z5.string(),
445
+ updatedAt: z5.string()
446
+ });
397
447
 
398
448
  // node_modules/@insforge/shared-schemas/dist/storage-api.schema.js
399
449
  import { z as z6 } from "zod";
@@ -440,6 +490,9 @@ var confirmUploadRequestSchema = z6.object({
440
490
  contentType: z6.string().optional(),
441
491
  etag: z6.string().optional()
442
492
  });
493
+ var updateStorageConfigRequestSchema = z6.object({
494
+ maxFileSizeMb: z6.number().int().min(1, "Must be at least 1 MB").max(200, "Must be at most 200 MB")
495
+ });
443
496
 
444
497
  // node_modules/@insforge/shared-schemas/dist/auth.schema.js
445
498
  import { z as z7 } from "zod";
@@ -497,6 +550,7 @@ var oAuthConfigSchema = z7.object({
497
550
  updatedAt: z7.string()
498
551
  // PostgreSQL timestamp
499
552
  });
553
+ var allowedRedirectUrlsRegex = /^(?:(?:https?:\/\/)(?:(?:\*\.)?[^\s/:?#]+|\[[0-9A-Fa-f:.]+\])(?::\d+)?(?:\/[^\s]*)?|(?!(?:https?|javascript|data|file|vbscript):)[a-zA-Z][a-zA-Z0-9+.-]*:(?:\/\/[^\s/]+(?:\/[^\s]*)?|\/[^\s]*))$/i;
500
554
  var authConfigSchema = z7.object({
501
555
  id: z7.string().uuid(),
502
556
  requireEmailVerification: z7.boolean(),
@@ -507,12 +561,34 @@ var authConfigSchema = z7.object({
507
561
  requireSpecialChar: z7.boolean(),
508
562
  verifyEmailMethod: verificationMethodSchema,
509
563
  resetPasswordMethod: verificationMethodSchema,
510
- signInRedirectTo: z7.union([z7.string().url(), z7.literal(""), z7.null()]).optional().transform((val) => val === "" ? null : val),
564
+ allowedRedirectUrls: z7.array(z7.string().regex(allowedRedirectUrlsRegex, { message: "Invalid URL or wildcard URL" })).optional().nullable(),
511
565
  createdAt: z7.string(),
512
566
  // PostgreSQL timestamp
513
567
  updatedAt: z7.string()
514
568
  // PostgreSQL timestamp
515
569
  });
570
+ var smtpConfigSchema = z7.object({
571
+ id: z7.string().uuid(),
572
+ enabled: z7.boolean(),
573
+ host: z7.string(),
574
+ port: z7.number().int(),
575
+ username: z7.string(),
576
+ hasPassword: z7.boolean(),
577
+ // Never expose actual password
578
+ senderEmail: z7.string(),
579
+ senderName: z7.string(),
580
+ minIntervalSeconds: z7.number().int().min(0),
581
+ createdAt: z7.string(),
582
+ updatedAt: z7.string()
583
+ });
584
+ var emailTemplateSchema = z7.object({
585
+ id: z7.string().uuid(),
586
+ templateType: z7.string(),
587
+ subject: z7.string(),
588
+ bodyHtml: z7.string(),
589
+ createdAt: z7.string(),
590
+ updatedAt: z7.string()
591
+ });
516
592
  var tokenPayloadSchema = z7.object({
517
593
  sub: userIdSchema,
518
594
  // Subject (user ID)
@@ -523,6 +599,16 @@ var tokenPayloadSchema = z7.object({
523
599
  exp: z7.number().optional()
524
600
  // Expiration
525
601
  });
602
+ var customOAuthKeySchema = z7.string().min(1).max(64).regex(/^[a-z0-9_-]+$/, "Key must contain only lowercase letters, numbers, hyphens, and underscores");
603
+ var customOAuthConfigSchema = z7.object({
604
+ id: z7.string().uuid(),
605
+ key: customOAuthKeySchema,
606
+ name: z7.string().min(1),
607
+ discoveryEndpoint: z7.string().url(),
608
+ clientId: z7.string().min(1),
609
+ createdAt: z7.string(),
610
+ updatedAt: z7.string()
611
+ });
526
612
 
527
613
  // node_modules/@insforge/shared-schemas/dist/auth-api.schema.js
528
614
  import { z as z8 } from "zod";
@@ -530,19 +616,20 @@ var paginationSchema = z8.object({
530
616
  limit: z8.string().optional(),
531
617
  offset: z8.string().optional()
532
618
  });
533
- var authOptionsSchema = z8.object({
534
- emailRedirectTo: z8.string().url().optional()
535
- }).optional();
536
619
  var createUserRequestSchema = z8.object({
537
620
  email: emailSchema,
538
621
  password: passwordSchema,
539
622
  name: nameSchema.optional(),
540
- options: authOptionsSchema
623
+ redirectTo: z8.string().url().optional(),
624
+ autoConfirm: z8.boolean().optional()
541
625
  });
542
626
  var createSessionRequestSchema = z8.object({
543
627
  email: emailSchema,
544
628
  password: passwordSchema
545
629
  });
630
+ var refreshSessionRequestSchema = z8.object({
631
+ refreshToken: z8.string().min(1, "refreshToken is required")
632
+ });
546
633
  var exchangeAdminSessionRequestSchema = z8.object({
547
634
  code: z8.string()
548
635
  });
@@ -557,20 +644,19 @@ var updateProfileRequestSchema = z8.object({
557
644
  });
558
645
  var sendVerificationEmailRequestSchema = z8.object({
559
646
  email: emailSchema,
560
- options: authOptionsSchema
647
+ redirectTo: z8.string().url().optional()
561
648
  });
562
649
  var verifyEmailRequestSchema = z8.object({
563
- email: emailSchema.optional(),
564
- otp: z8.string().min(1)
565
- }).refine((data) => data.email || data.otp, {
566
- message: "Either email or otp must be provided"
650
+ email: emailSchema,
651
+ otp: z8.string().regex(/^\d{6}$/, "OTP code must be a 6-digit numeric code")
567
652
  });
568
653
  var sendResetPasswordEmailRequestSchema = z8.object({
569
- email: emailSchema
654
+ email: emailSchema,
655
+ redirectTo: z8.string().url().optional()
570
656
  });
571
657
  var exchangeResetPasswordTokenRequestSchema = z8.object({
572
658
  email: emailSchema,
573
- code: z8.string().min(1)
659
+ code: z8.string().regex(/^\d{6}$/, "Reset password code must be a 6-digit numeric code")
574
660
  });
575
661
  var resetPasswordRequestSchema = z8.object({
576
662
  newPassword: passwordSchema,
@@ -580,7 +666,6 @@ var createUserResponseSchema = z8.object({
580
666
  user: userSchema.optional(),
581
667
  accessToken: z8.string().nullable(),
582
668
  requireEmailVerification: z8.boolean().optional(),
583
- redirectTo: z8.string().url().optional(),
584
669
  csrfToken: z8.string().nullable().optional(),
585
670
  refreshToken: z8.string().optional()
586
671
  // For mobile/desktop clients (no cookies)
@@ -588,7 +673,6 @@ var createUserResponseSchema = z8.object({
588
673
  var createSessionResponseSchema = z8.object({
589
674
  user: userSchema,
590
675
  accessToken: z8.string(),
591
- redirectTo: z8.string().url().optional(),
592
676
  csrfToken: z8.string().nullable().optional(),
593
677
  refreshToken: z8.string().optional()
594
678
  // For mobile/desktop clients (no cookies)
@@ -596,7 +680,6 @@ var createSessionResponseSchema = z8.object({
596
680
  var verifyEmailResponseSchema = z8.object({
597
681
  user: userSchema,
598
682
  accessToken: z8.string(),
599
- redirectTo: z8.string().url().optional(),
600
683
  csrfToken: z8.string().nullable().optional(),
601
684
  refreshToken: z8.string().optional()
602
685
  // For mobile/desktop clients (no cookies)
@@ -676,19 +759,49 @@ var updateAuthConfigRequestSchema = authConfigSchema.omit({
676
759
  }).partial();
677
760
  var getPublicAuthConfigResponseSchema = z8.object({
678
761
  oAuthProviders: z8.array(oAuthProvidersSchema),
762
+ customOAuthProviders: z8.array(customOAuthKeySchema),
679
763
  ...authConfigSchema.omit({
680
764
  id: true,
681
765
  updatedAt: true,
682
766
  createdAt: true,
683
- signInRedirectTo: true
767
+ allowedRedirectUrls: true
684
768
  }).shape
685
769
  });
770
+ var upsertSmtpConfigRequestSchema = z8.object({
771
+ enabled: z8.boolean(),
772
+ host: z8.string().min(1, "SMTP host is required"),
773
+ port: z8.union([z8.literal(25), z8.literal(465), z8.literal(587), z8.literal(2525)], {
774
+ errorMap: () => ({ message: "Port must be one of: 25, 465, 587, 2525" })
775
+ }),
776
+ username: z8.string().min(1, "SMTP username is required"),
777
+ password: z8.string().min(1, "SMTP password is required").optional(),
778
+ senderEmail: z8.string().email("Invalid sender email"),
779
+ senderName: z8.string().min(1, "Sender name is required"),
780
+ minIntervalSeconds: z8.number().int().min(0).default(60)
781
+ });
782
+ var updateEmailTemplateRequestSchema = z8.object({
783
+ subject: z8.string().min(1, "Subject is required"),
784
+ bodyHtml: z8.string().min(1, "Template body is required")
785
+ });
786
+ var listEmailTemplatesResponseSchema = z8.object({
787
+ data: z8.array(emailTemplateSchema)
788
+ });
686
789
  var authErrorResponseSchema = z8.object({
687
790
  error: z8.string(),
688
791
  message: z8.string(),
689
792
  statusCode: z8.number().int(),
690
793
  nextActions: z8.string().optional()
691
794
  });
795
+ var createCustomOAuthConfigRequestSchema = customOAuthConfigSchema.omit({ id: true, createdAt: true, updatedAt: true }).extend({
796
+ clientSecret: z8.string().min(1, "Client secret is required")
797
+ });
798
+ var updateCustomOAuthConfigRequestSchema = customOAuthConfigSchema.omit({ id: true, key: true, createdAt: true, updatedAt: true }).extend({
799
+ clientSecret: z8.string().min(1).optional()
800
+ }).partial();
801
+ var listCustomOAuthConfigsResponseSchema = z8.object({
802
+ data: z8.array(customOAuthConfigSchema),
803
+ count: z8.number()
804
+ });
692
805
 
693
806
  // node_modules/@insforge/shared-schemas/dist/metadata.schema.js
694
807
  import { z as z11 } from "zod";
@@ -718,6 +831,9 @@ var realtimeMessageSchema = z9.object({
718
831
  whDeliveredCount: z9.number().int().min(0),
719
832
  createdAt: z9.string().datetime()
720
833
  });
834
+ var realtimeConfigSchema = z9.object({
835
+ retentionDays: z9.number().int().positive().nullable()
836
+ });
721
837
  var subscribeChannelPayloadSchema = z9.object({
722
838
  channel: z9.string().min(1)
723
839
  // The resolved channel instance, e.g., "order:123"
@@ -803,7 +919,8 @@ var messageStatsResponseSchema = z10.object({
803
919
  topEvents: z10.array(z10.object({
804
920
  eventName: z10.string(),
805
921
  count: z10.number().int().min(0)
806
- }))
922
+ })),
923
+ retentionDays: realtimeConfigSchema.shape.retentionDays
807
924
  });
808
925
  var rlsPolicySchema = z10.object({
809
926
  policyName: z10.string(),
@@ -883,6 +1000,9 @@ var databasePasswordInfoSchema = z11.object({
883
1000
  var apiKeyResponseSchema = z11.object({
884
1001
  apiKey: z11.string()
885
1002
  });
1003
+ var projectIdResponseSchema = z11.object({
1004
+ projectId: z11.string().nullable()
1005
+ });
886
1006
 
887
1007
  // node_modules/@insforge/shared-schemas/dist/ai.schema.js
888
1008
  import { z as z12 } from "zod";
@@ -975,12 +1095,42 @@ var contentSchema = z13.union([
975
1095
  audioContentSchema,
976
1096
  fileContentSchema
977
1097
  ]);
1098
+ var toolFunctionSchema = z13.object({
1099
+ name: z13.string(),
1100
+ description: z13.string().optional(),
1101
+ parameters: z13.record(z13.unknown()).optional()
1102
+ });
1103
+ var toolSchema = z13.object({
1104
+ type: z13.literal("function"),
1105
+ function: toolFunctionSchema
1106
+ });
1107
+ var toolChoiceSchema = z13.union([
1108
+ z13.enum(["auto", "none", "required"]),
1109
+ z13.object({
1110
+ type: z13.literal("function"),
1111
+ function: z13.object({ name: z13.string() })
1112
+ })
1113
+ ]);
1114
+ var toolCallSchema = z13.object({
1115
+ id: z13.string(),
1116
+ type: z13.literal("function"),
1117
+ function: z13.object({
1118
+ name: z13.string(),
1119
+ arguments: z13.string()
1120
+ })
1121
+ });
978
1122
  var chatMessageSchema = z13.object({
979
- role: z13.enum(["user", "assistant", "system"]),
1123
+ role: z13.enum(["user", "assistant", "system", "tool"]),
980
1124
  // New format: content can be string or array of content parts (OpenAI-compatible)
981
- content: z13.union([z13.string(), z13.array(contentSchema)]),
1125
+ content: z13.union([z13.string(), z13.array(contentSchema)]).nullable(),
982
1126
  // Legacy format: separate images field (deprecated but supported for backward compatibility)
983
- images: z13.array(z13.object({ url: z13.string() })).optional()
1127
+ images: z13.array(z13.object({ url: z13.string() })).optional(),
1128
+ // Tool calls made by the assistant
1129
+ // eslint-disable-next-line @typescript-eslint/naming-convention
1130
+ tool_calls: z13.array(toolCallSchema).optional(),
1131
+ // Tool call ID for tool response messages
1132
+ // eslint-disable-next-line @typescript-eslint/naming-convention
1133
+ tool_call_id: z13.string().optional()
984
1134
  });
985
1135
  var webSearchPluginSchema = z13.object({
986
1136
  enabled: z13.boolean(),
@@ -1020,7 +1170,13 @@ var chatCompletionRequestSchema = z13.object({
1020
1170
  fileParser: fileParserPluginSchema.optional(),
1021
1171
  // Thinking/Reasoning mode: Enable extended reasoning capabilities
1022
1172
  // Appends ":thinking" to the model ID for chain-of-thought reasoning
1023
- thinking: z13.boolean().optional()
1173
+ thinking: z13.boolean().optional(),
1174
+ // Tool calling: Define functions the AI can call
1175
+ tools: z13.array(toolSchema).optional(),
1176
+ // Tool choice: Control whether/which tool is called ('auto', 'none', 'required', or specific function)
1177
+ toolChoice: toolChoiceSchema.optional(),
1178
+ // Parallel tool calls: Allow the model to call multiple tools in parallel
1179
+ parallelToolCalls: z13.boolean().optional()
1024
1180
  });
1025
1181
  var urlCitationAnnotationSchema = z13.object({
1026
1182
  type: z13.literal("url_citation"),
@@ -1046,6 +1202,9 @@ var fileAnnotationSchema = z13.object({
1046
1202
  var annotationSchema = z13.union([urlCitationAnnotationSchema, fileAnnotationSchema]);
1047
1203
  var chatCompletionResponseSchema = z13.object({
1048
1204
  text: z13.string(),
1205
+ // Tool calls from the assistant (present when the model invokes tools)
1206
+ // eslint-disable-next-line @typescript-eslint/naming-convention
1207
+ tool_calls: z13.array(toolCallSchema).optional(),
1049
1208
  // Annotations from web search or file parsing (can be URL citations or file annotations)
1050
1209
  annotations: z13.array(annotationSchema).optional(),
1051
1210
  metadata: z13.object({
@@ -1135,6 +1294,15 @@ var getAIUsageSummaryRequestSchema = z13.object({
1135
1294
  startDate: z13.string().datetime().optional(),
1136
1295
  endDate: z13.string().datetime().optional()
1137
1296
  });
1297
+ var keySourceSchema = z13.enum(["byok", "cloud", "env", "unconfigured"]);
1298
+ var gatewayConfigResponseSchema = z13.object({
1299
+ keySource: keySourceSchema,
1300
+ hasByokKey: z13.boolean(),
1301
+ maskedKey: z13.string().optional()
1302
+ });
1303
+ var setGatewayBYOKKeyRequestSchema = z13.object({
1304
+ apiKey: z13.string().min(1, "API key is required")
1305
+ });
1138
1306
 
1139
1307
  // node_modules/@insforge/shared-schemas/dist/logs.schema.js
1140
1308
  import { z as z14 } from "zod";
@@ -1165,6 +1333,16 @@ var logStatsSchema = z14.object({
1165
1333
  count: z14.number(),
1166
1334
  lastActivity: z14.string()
1167
1335
  });
1336
+ var buildLogEntrySchema = z14.object({
1337
+ level: z14.string(),
1338
+ message: z14.string()
1339
+ });
1340
+ var getBuildLogsResponseSchema = z14.object({
1341
+ deploymentId: z14.string(),
1342
+ status: z14.enum(["pending", "success", "failed"]),
1343
+ logs: z14.array(buildLogEntrySchema),
1344
+ createdAt: z14.string()
1345
+ });
1168
1346
 
1169
1347
  // node_modules/@insforge/shared-schemas/dist/logs-api.schema.js
1170
1348
  import { z as z15 } from "zod";
@@ -1240,7 +1418,19 @@ var listFunctionsResponseSchema = z17.object({
1240
1418
  functions: z17.array(functionSchema),
1241
1419
  runtime: z17.object({
1242
1420
  status: z17.enum(["running", "unavailable"])
1243
- })
1421
+ }),
1422
+ deploymentUrl: z17.string().nullable().optional()
1423
+ });
1424
+ var deploymentResultSchema = z17.object({
1425
+ id: z17.string(),
1426
+ status: z17.enum(["success", "failed"]),
1427
+ url: z17.string().nullable(),
1428
+ buildLogs: z17.array(z17.string()).optional()
1429
+ });
1430
+ var functionResponseSchema = z17.object({
1431
+ success: z17.boolean(),
1432
+ function: functionSchema,
1433
+ deployment: deploymentResultSchema.nullable().optional()
1244
1434
  });
1245
1435
 
1246
1436
  // node_modules/@insforge/shared-schemas/dist/cloud-events.schema.js
@@ -1280,6 +1470,9 @@ var showContactModalEventSchema = z18.object({
1280
1470
  var showConnectOverlayEventSchema = z18.object({
1281
1471
  type: z18.literal("SHOW_CONNECT_OVERLAY")
1282
1472
  });
1473
+ var showPlanModalEventSchema = z18.object({
1474
+ type: z18.literal("SHOW_PLAN_MODAL")
1475
+ });
1283
1476
  var authorizationCodeEventSchema = z18.object({
1284
1477
  type: z18.literal("AUTHORIZATION_CODE"),
1285
1478
  code: z18.string()
@@ -1288,6 +1481,51 @@ var routeChangeEventSchema = z18.object({
1288
1481
  type: z18.literal("ROUTE_CHANGE"),
1289
1482
  path: z18.string()
1290
1483
  });
1484
+ var requestProjectInfoEventSchema = z18.object({
1485
+ type: z18.literal("REQUEST_PROJECT_INFO")
1486
+ });
1487
+ var projectInfoEventSchema = z18.object({
1488
+ type: z18.literal("PROJECT_INFO"),
1489
+ name: z18.string(),
1490
+ instanceType: z18.string(),
1491
+ region: z18.string(),
1492
+ latestVersion: z18.string().optional()
1493
+ });
1494
+ var requestInstanceInfoEventSchema = z18.object({
1495
+ type: z18.literal("REQUEST_INSTANCE_INFO")
1496
+ });
1497
+ var instanceInfoEventSchema = z18.object({
1498
+ type: z18.literal("INSTANCE_INFO"),
1499
+ currentInstanceType: z18.string(),
1500
+ planName: z18.string(),
1501
+ computeCredits: z18.number(),
1502
+ currentOrgComputeCost: z18.number(),
1503
+ instanceTypes: z18.array(z18.object({
1504
+ id: z18.string(),
1505
+ name: z18.string(),
1506
+ cpu: z18.string(),
1507
+ ram: z18.string(),
1508
+ pricePerHour: z18.number(),
1509
+ pricePerMonth: z18.number()
1510
+ })),
1511
+ projects: z18.array(z18.object({
1512
+ name: z18.string(),
1513
+ instanceType: z18.string(),
1514
+ monthlyCost: z18.number(),
1515
+ isCurrent: z18.boolean(),
1516
+ status: z18.string()
1517
+ }))
1518
+ });
1519
+ var requestInstanceTypeChangeEventSchema = z18.object({
1520
+ type: z18.literal("REQUEST_INSTANCE_TYPE_CHANGE"),
1521
+ instanceType: z18.string()
1522
+ });
1523
+ var instanceTypeChangeResultEventSchema = z18.object({
1524
+ type: z18.literal("INSTANCE_TYPE_CHANGE_RESULT"),
1525
+ success: z18.boolean(),
1526
+ instanceType: z18.string().optional(),
1527
+ error: z18.string().optional()
1528
+ });
1291
1529
  var cloudEventSchema = z18.discriminatedUnion("type", [
1292
1530
  appRouteChangeEventSchema,
1293
1531
  authSuccessEventSchema,
@@ -1299,8 +1537,15 @@ var cloudEventSchema = z18.discriminatedUnion("type", [
1299
1537
  navigateToUsageSchema,
1300
1538
  showContactModalEventSchema,
1301
1539
  showConnectOverlayEventSchema,
1540
+ showPlanModalEventSchema,
1302
1541
  authorizationCodeEventSchema,
1303
- routeChangeEventSchema
1542
+ routeChangeEventSchema,
1543
+ requestProjectInfoEventSchema,
1544
+ projectInfoEventSchema,
1545
+ requestInstanceInfoEventSchema,
1546
+ instanceInfoEventSchema,
1547
+ requestInstanceTypeChangeEventSchema,
1548
+ instanceTypeChangeResultEventSchema
1304
1549
  ]);
1305
1550
 
1306
1551
  // node_modules/@insforge/shared-schemas/dist/docs.schema.js
@@ -1336,8 +1581,6 @@ var docTypeSchema = z19.enum([
1336
1581
  "storage-sdk",
1337
1582
  "functions-sdk",
1338
1583
  "ai-integration-sdk",
1339
- "auth-components-react",
1340
- "auth-components-nextjs",
1341
1584
  "real-time",
1342
1585
  "deployment"
1343
1586
  ]).describe(`
@@ -1347,8 +1590,6 @@ var docTypeSchema = z19.enum([
1347
1590
  "storage-sdk" (file storage),
1348
1591
  "functions-sdk" (edge functions),
1349
1592
  "auth-sdk" (direct SDK methods for custom auth flows),
1350
- "auth-components-react" (authentication components for React+Vite applications),
1351
- "auth-components-nextjs" (authentication components for Next.js applications),
1352
1593
  "ai-integration-sdk" (AI features),
1353
1594
  "real-time" (real-time pub/sub through WebSockets),
1354
1595
  "deployment" (deploy frontend applications via MCP tool)
@@ -1375,9 +1616,9 @@ var sendEmailResponseSchema = z20.object({});
1375
1616
  import { z as z21 } from "zod";
1376
1617
  var deploymentStatusSchema = z21.enum([
1377
1618
  "WAITING",
1378
- // Record created, waiting for client to upload zip to S3
1619
+ // Record created, waiting for source zip upload or direct file registration/content
1379
1620
  "UPLOADING",
1380
- // Server is downloading from S3 and uploading to Vercel
1621
+ // File uploads or Vercel deployment creation are in progress
1381
1622
  "QUEUED",
1382
1623
  // Vercel: deployment queued
1383
1624
  "BUILDING",
@@ -1414,11 +1655,47 @@ var envVarSchema = z22.object({
1414
1655
  key: z22.string(),
1415
1656
  value: z22.string()
1416
1657
  });
1658
+ var deploymentFilePathSchema = z22.string().min(1, "path is required").max(2048, "path is too long").refine((value) => !value.includes("\0"), "path cannot contain null bytes").refine((value) => !value.includes("\\"), "path must use forward slashes").refine((value) => !value.startsWith("/"), "path must be relative").refine((value) => value.split("/").every((part) => part !== "" && part !== "." && part !== ".."), "path cannot contain empty, current, or parent directory segments");
1659
+ var deploymentManifestFileEntrySchema = z22.object({
1660
+ path: deploymentFilePathSchema,
1661
+ sha: z22.string().regex(/^[a-f0-9]{40}$/i, "sha must be a SHA-1 hex digest"),
1662
+ size: z22.number().int().nonnegative()
1663
+ });
1664
+ var deploymentManifestFileSchema = deploymentManifestFileEntrySchema.extend({
1665
+ fileId: z22.string().uuid(),
1666
+ uploadedAt: z22.string().datetime().nullable()
1667
+ });
1417
1668
  var createDeploymentResponseSchema = z22.object({
1418
1669
  id: z22.string().uuid(),
1419
1670
  uploadUrl: z22.string().url(),
1420
1671
  uploadFields: z22.record(z22.string())
1421
- // Required for S3 presigned POST (policy, signature, key, etc.)
1672
+ });
1673
+ var createDirectDeploymentResponseSchema = z22.object({
1674
+ id: z22.string().uuid(),
1675
+ status: deploymentSchema.shape.status
1676
+ });
1677
+ var createDeploymentManifestRequestSchema = z22.object({
1678
+ files: z22.array(deploymentManifestFileEntrySchema).min(1)
1679
+ }).superRefine(({ files }, ctx) => {
1680
+ const firstSeenByPath = /* @__PURE__ */ new Map();
1681
+ files.forEach((file, index) => {
1682
+ const existingIndex = firstSeenByPath.get(file.path);
1683
+ if (existingIndex !== void 0) {
1684
+ ctx.addIssue({
1685
+ code: z22.ZodIssueCode.custom,
1686
+ message: "duplicate file path",
1687
+ path: ["files", index, "path"]
1688
+ });
1689
+ return;
1690
+ }
1691
+ firstSeenByPath.set(file.path, index);
1692
+ });
1693
+ });
1694
+ var createDeploymentManifestResponseSchema = z22.object({
1695
+ files: z22.array(deploymentManifestFileSchema)
1696
+ });
1697
+ var uploadDeploymentFileResponseSchema = deploymentManifestFileSchema.extend({
1698
+ uploadedAt: z22.string().datetime()
1422
1699
  });
1423
1700
  var startDeploymentRequestSchema = z22.object({
1424
1701
  projectSettings: projectSettingsSchema.optional(),
@@ -1433,6 +1710,96 @@ var listDeploymentsResponseSchema = z22.object({
1433
1710
  total: z22.number()
1434
1711
  })
1435
1712
  });
1713
+ var deploymentEnvVarSchema = z22.object({
1714
+ id: z22.string(),
1715
+ // Vercel env var ID (needed for delete/get)
1716
+ key: z22.string(),
1717
+ type: z22.enum(["plain", "encrypted", "secret", "sensitive", "system"]),
1718
+ updatedAt: z22.number().optional()
1719
+ // Unix timestamp (milliseconds)
1720
+ });
1721
+ var deploymentEnvVarWithValueSchema = z22.object({
1722
+ id: z22.string(),
1723
+ key: z22.string(),
1724
+ value: z22.string(),
1725
+ type: z22.enum(["plain", "encrypted", "secret", "sensitive", "system"]),
1726
+ updatedAt: z22.number().optional()
1727
+ });
1728
+ var listEnvVarsResponseSchema = z22.object({
1729
+ envVars: z22.array(deploymentEnvVarSchema)
1730
+ });
1731
+ var getEnvVarResponseSchema = z22.object({
1732
+ envVar: deploymentEnvVarWithValueSchema
1733
+ });
1734
+ var upsertEnvVarRequestSchema = z22.object({
1735
+ key: z22.string().trim().min(1, "key is required"),
1736
+ value: z22.string()
1737
+ });
1738
+ var upsertEnvVarsRequestSchema = z22.object({
1739
+ envVars: z22.array(upsertEnvVarRequestSchema).min(1)
1740
+ }).superRefine(({ envVars }, ctx) => {
1741
+ const firstSeenByKey = /* @__PURE__ */ new Map();
1742
+ envVars.forEach((envVar, index) => {
1743
+ const existingIndex = firstSeenByKey.get(envVar.key);
1744
+ if (existingIndex !== void 0) {
1745
+ ctx.addIssue({
1746
+ code: z22.ZodIssueCode.custom,
1747
+ message: "duplicate environment variable key",
1748
+ path: ["envVars", index, "key"]
1749
+ });
1750
+ return;
1751
+ }
1752
+ firstSeenByKey.set(envVar.key, index);
1753
+ });
1754
+ });
1755
+ var upsertEnvVarResponseSchema = z22.object({
1756
+ success: z22.literal(true),
1757
+ message: z22.string()
1758
+ });
1759
+ var upsertEnvVarsResponseSchema = z22.object({
1760
+ success: z22.literal(true),
1761
+ message: z22.string(),
1762
+ count: z22.number().int().positive()
1763
+ });
1764
+ var deleteEnvVarResponseSchema = z22.object({
1765
+ success: z22.literal(true),
1766
+ message: z22.string()
1767
+ });
1768
+ var updateSlugRequestSchema = z22.object({
1769
+ slug: z22.string().trim().min(3, "slug must be at least 3 characters").max(63, "slug must be at most 63 characters").regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/, "slug must be lowercase alphanumeric with hyphens, not starting or ending with hyphen").nullable()
1770
+ });
1771
+ var updateSlugResponseSchema = z22.object({
1772
+ success: z22.boolean(),
1773
+ slug: z22.string().nullable(),
1774
+ domain: z22.string().nullable()
1775
+ });
1776
+ var deploymentMetadataResponseSchema = z22.object({
1777
+ currentDeploymentId: z22.string().uuid().nullable(),
1778
+ defaultDomainUrl: z22.string().nullable(),
1779
+ customDomainUrl: z22.string().nullable()
1780
+ });
1781
+ var domainVerificationRecordSchema = z22.object({
1782
+ type: z22.string(),
1783
+ domain: z22.string(),
1784
+ value: z22.string()
1785
+ });
1786
+ var customDomainSchema = z22.object({
1787
+ domain: z22.string(),
1788
+ apexDomain: z22.string(),
1789
+ verified: z22.boolean(),
1790
+ misconfigured: z22.boolean(),
1791
+ verification: z22.array(domainVerificationRecordSchema),
1792
+ cnameTarget: z22.string().nullable(),
1793
+ aRecordValue: z22.string().nullable()
1794
+ });
1795
+ var addCustomDomainRequestSchema = z22.object({
1796
+ domain: z22.string().trim().min(1, "Domain is required").regex(/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$/i, "Invalid domain format (e.g. myapp.com or www.myapp.com)").refine((domain) => !domain.toLowerCase().endsWith(".insforge.site"), {
1797
+ message: "Domains ending with .insforge.site are reserved by InsForge"
1798
+ })
1799
+ });
1800
+ var listCustomDomainsResponseSchema = z22.object({
1801
+ domains: z22.array(customDomainSchema)
1802
+ });
1436
1803
 
1437
1804
  // node_modules/@insforge/shared-schemas/dist/schedules.schema.js
1438
1805
  import { z as z23 } from "zod";
@@ -2273,23 +2640,320 @@ function registerFunctionTools(ctx) {
2273
2640
  // src/shared/tools/deployment.ts
2274
2641
  import { z as z29 } from "zod";
2275
2642
  import fetch6 from "node-fetch";
2643
+ import { createHash } from "crypto";
2276
2644
  import { promises as fs3, createWriteStream, createReadStream } from "fs";
2277
2645
  import { tmpdir as tmpdir2 } from "os";
2278
- import { join as join2 } from "path";
2646
+ import { join as join2, relative, sep } from "path";
2279
2647
  import archiver from "archiver";
2280
2648
  import FormData2 from "form-data";
2281
- function isCreateDeploymentResponse(obj) {
2282
- if (typeof obj !== "object" || obj === null) {
2283
- return false;
2649
+ var DIRECT_DEPLOYMENT_MIN_VERSION = "2.0.5";
2650
+ var EXCLUDED_DEPLOYMENT_SEGMENTS = /* @__PURE__ */ new Set(["node_modules", ".git", ".next", "dist", "build", ".insforge"]);
2651
+ var DirectDeploymentUnsupportedError = class extends Error {
2652
+ constructor() {
2653
+ super("Direct deployment endpoints are not available on this backend");
2654
+ this.name = "DirectDeploymentUnsupportedError";
2284
2655
  }
2285
- const value = obj;
2286
- const idOk = "id" in value && (typeof value.id === "string" || typeof value.id === "number");
2287
- const urlOk = "uploadUrl" in value && typeof value.uploadUrl === "string" && value.uploadUrl.length > 0;
2288
- const fieldsOk = "uploadFields" in value && typeof value.uploadFields === "object" && value.uploadFields !== null;
2289
- return idOk && urlOk && fieldsOk;
2656
+ };
2657
+ function isAbsoluteSourcePath(sourceDirectory) {
2658
+ return sourceDirectory.startsWith("/") || /^[a-zA-Z]:[/\\]/.test(sourceDirectory);
2659
+ }
2660
+ function supportsDirectDeploymentVersion(backendVersion) {
2661
+ const cleanVersion = backendVersion.replace(/^v/, "").split("-")[0];
2662
+ const [major = 0, minor = 0, patch = 0] = cleanVersion.split(".").map(Number);
2663
+ const [minMajor, minMinor, minPatch] = DIRECT_DEPLOYMENT_MIN_VERSION.split(".").map(Number);
2664
+ if (major !== minMajor) return major > minMajor;
2665
+ if (minor !== minMinor) return minor > minMinor;
2666
+ return patch >= minPatch;
2667
+ }
2668
+ function shouldExcludeDeploymentPath(normalizedName) {
2669
+ const segments = normalizedName.split("/");
2670
+ if (segments.some((segment) => segment === ".env" || segment.startsWith(".env."))) {
2671
+ return true;
2672
+ }
2673
+ if (segments.some((segment) => EXCLUDED_DEPLOYMENT_SEGMENTS.has(segment))) {
2674
+ return true;
2675
+ }
2676
+ return normalizedName === ".DS_Store" || normalizedName.endsWith("/.DS_Store") || normalizedName.endsWith(".log");
2677
+ }
2678
+ function normalizeRelativePath(rootDirectory, absolutePath) {
2679
+ return relative(rootDirectory, absolutePath).split(sep).join("/").replace(/\\/g, "/");
2680
+ }
2681
+ async function hashFile(filePath) {
2682
+ const hash = createHash("sha1");
2683
+ let size = 0;
2684
+ for await (const chunk of createReadStream(filePath)) {
2685
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
2686
+ size += buffer.length;
2687
+ hash.update(buffer);
2688
+ }
2689
+ return { sha: hash.digest("hex"), size };
2690
+ }
2691
+ function parseCreateDeploymentResponse(obj) {
2692
+ const result = createDeploymentResponseSchema.safeParse(obj);
2693
+ if (!result.success) {
2694
+ throw new Error("Unexpected response format from deployments endpoint");
2695
+ }
2696
+ return result.data;
2697
+ }
2698
+ function parseCreateDirectDeploymentResponse(obj) {
2699
+ const result = createDirectDeploymentResponseSchema.safeParse(obj);
2700
+ if (!result.success) {
2701
+ throw new Error("Unexpected response format from direct deployments endpoint");
2702
+ }
2703
+ return result.data;
2704
+ }
2705
+ function parseCreateDeploymentManifestResponse(obj) {
2706
+ const result = createDeploymentManifestResponseSchema.safeParse(obj);
2707
+ if (!result.success) {
2708
+ throw new Error("Unexpected response format from deployment manifest endpoint");
2709
+ }
2710
+ return result.data;
2711
+ }
2712
+ async function collectDeploymentFiles(sourceDirectory) {
2713
+ const files = [];
2714
+ async function walk(currentDirectory) {
2715
+ const entries = await fs3.readdir(currentDirectory, { withFileTypes: true });
2716
+ entries.sort((a, b) => a.name.localeCompare(b.name));
2717
+ for (const entry of entries) {
2718
+ const absolutePath = join2(currentDirectory, entry.name);
2719
+ const normalizedPath = normalizeRelativePath(sourceDirectory, absolutePath);
2720
+ if (!normalizedPath || shouldExcludeDeploymentPath(normalizedPath)) {
2721
+ continue;
2722
+ }
2723
+ if (entry.isDirectory()) {
2724
+ await walk(absolutePath);
2725
+ continue;
2726
+ }
2727
+ if (!entry.isFile()) {
2728
+ continue;
2729
+ }
2730
+ const { sha, size } = await hashFile(absolutePath);
2731
+ files.push({
2732
+ absolutePath,
2733
+ path: normalizedPath,
2734
+ sha,
2735
+ size
2736
+ });
2737
+ }
2738
+ }
2739
+ await walk(sourceDirectory);
2740
+ return files;
2741
+ }
2742
+ function buildStartBody(input) {
2743
+ const startBody = {};
2744
+ if (input.projectSettings) startBody.projectSettings = input.projectSettings;
2745
+ if (input.envVars) startBody.envVars = input.envVars;
2746
+ if (input.meta) startBody.meta = input.meta;
2747
+ return startBody;
2748
+ }
2749
+ async function createDirectDeploymentSession(API_BASE_URL, apiKey) {
2750
+ const response = await fetch6(`${API_BASE_URL}/api/deployments/direct`, {
2751
+ method: "POST",
2752
+ headers: {
2753
+ "x-api-key": apiKey,
2754
+ "Content-Type": "application/json"
2755
+ }
2756
+ });
2757
+ if (response.status === 404) {
2758
+ throw new DirectDeploymentUnsupportedError();
2759
+ }
2760
+ const result = await handleApiResponse(response);
2761
+ return parseCreateDirectDeploymentResponse(result);
2762
+ }
2763
+ async function createDeploymentManifest(API_BASE_URL, apiKey, deploymentId, files) {
2764
+ const response = await fetch6(`${API_BASE_URL}/api/deployments/${encodeURIComponent(deploymentId)}/manifest`, {
2765
+ method: "POST",
2766
+ headers: {
2767
+ "x-api-key": apiKey,
2768
+ "Content-Type": "application/json"
2769
+ },
2770
+ body: JSON.stringify({ files })
2771
+ });
2772
+ if (response.status === 404) {
2773
+ throw new DirectDeploymentUnsupportedError();
2774
+ }
2775
+ const result = await handleApiResponse(response);
2776
+ return parseCreateDeploymentManifestResponse(result);
2777
+ }
2778
+ async function uploadDeploymentFileContent(API_BASE_URL, apiKey, deploymentId, file, localFile) {
2779
+ const response = await fetch6(
2780
+ `${API_BASE_URL}/api/deployments/${encodeURIComponent(deploymentId)}/files/${encodeURIComponent(file.fileId)}/content`,
2781
+ {
2782
+ method: "PUT",
2783
+ headers: {
2784
+ "x-api-key": apiKey,
2785
+ "Content-Type": "application/octet-stream",
2786
+ "Content-Length": String(localFile.size)
2787
+ },
2788
+ body: createReadStream(localFile.absolutePath)
2789
+ }
2790
+ );
2791
+ if (response.status === 404) {
2792
+ throw new DirectDeploymentUnsupportedError();
2793
+ }
2794
+ await handleApiResponse(response);
2795
+ }
2796
+ async function startDeployment(API_BASE_URL, apiKey, deploymentId, startBody) {
2797
+ const response = await fetch6(`${API_BASE_URL}/api/deployments/${encodeURIComponent(deploymentId)}/start`, {
2798
+ method: "POST",
2799
+ headers: {
2800
+ "x-api-key": apiKey,
2801
+ "Content-Type": "application/json"
2802
+ },
2803
+ body: JSON.stringify(startBody)
2804
+ });
2805
+ return handleApiResponse(response);
2806
+ }
2807
+ async function deployDirect(API_BASE_URL, apiKey, sourceDirectory, startBody) {
2808
+ const files = await collectDeploymentFiles(sourceDirectory);
2809
+ if (files.length === 0) {
2810
+ throw new Error("No deployable files found in source directory after applying exclusions.");
2811
+ }
2812
+ const createResult = await createDirectDeploymentSession(API_BASE_URL, apiKey);
2813
+ const deploymentId = String(createResult.id);
2814
+ const manifest = await createDeploymentManifest(
2815
+ API_BASE_URL,
2816
+ apiKey,
2817
+ deploymentId,
2818
+ files.map(({ path, sha, size }) => ({ path, sha, size }))
2819
+ );
2820
+ const localFilesByPath = new Map(files.map((file) => [file.path, file]));
2821
+ for (const manifestFile of manifest.files) {
2822
+ const localFile = localFilesByPath.get(manifestFile.path);
2823
+ if (!localFile) {
2824
+ throw new Error(`Manifest response included unknown file path: ${manifestFile.path}`);
2825
+ }
2826
+ await uploadDeploymentFileContent(API_BASE_URL, apiKey, deploymentId, manifestFile, localFile);
2827
+ }
2828
+ const startResult = await startDeployment(API_BASE_URL, apiKey, deploymentId, startBody);
2829
+ return { deploymentId, fileCount: files.length, startResult };
2830
+ }
2831
+ function buildRemoteDirectUploadInstructions(API_BASE_URL, sourceDirectory, deploymentId) {
2832
+ const escapedDir = shellEsc(sourceDirectory);
2833
+ const apiBaseUrlJson = JSON.stringify(API_BASE_URL);
2834
+ const deploymentIdJson = JSON.stringify(deploymentId);
2835
+ return `Deployment prepared successfully using direct upload. Deployment ID: ${deploymentId}
2836
+
2837
+ Please execute the following command locally from a shell that has INSFORGE_API_KEY set, then call the \`start-deployment\` tool with the deployment ID printed by the script.
2838
+
2839
+ \`\`\`bash
2840
+ cd ${escapedDir}
2841
+ INSFORGE_API_KEY="\${INSFORGE_API_KEY:?Set INSFORGE_API_KEY to your InsForge API key}" node --input-type=module <<'NODE'
2842
+ const { createHash } = await import('node:crypto');
2843
+ const { createReadStream } = await import('node:fs');
2844
+ const fs = await import('node:fs/promises');
2845
+ const path = await import('node:path');
2846
+
2847
+ const API_BASE_URL = ${apiBaseUrlJson};
2848
+ const API_KEY = process.env.INSFORGE_API_KEY;
2849
+ const deploymentId = ${deploymentIdJson};
2850
+ const EXCLUDED_SEGMENTS = new Set(['node_modules', '.git', '.next', 'dist', 'build', '.insforge']);
2851
+
2852
+ function shouldExcludeDeploymentPath(normalizedName) {
2853
+ const segments = normalizedName.split('/');
2854
+ if (segments.some((segment) => segment === '.env' || segment.startsWith('.env.'))) return true;
2855
+ if (segments.some((segment) => EXCLUDED_SEGMENTS.has(segment))) return true;
2856
+ return normalizedName === '.DS_Store' || normalizedName.endsWith('/.DS_Store') || normalizedName.endsWith('.log');
2857
+ }
2858
+
2859
+ async function readJsonResponse(response) {
2860
+ const text = await response.text();
2861
+ const data = text ? JSON.parse(text) : null;
2862
+ if (!response.ok) {
2863
+ throw new Error(data?.message || data?.error || \`Request failed with status \${response.status}\`);
2864
+ }
2865
+ return data;
2866
+ }
2867
+
2868
+ async function api(pathname, init = {}) {
2869
+ const headers = {
2870
+ 'x-api-key': API_KEY,
2871
+ ...(init.headers || {}),
2872
+ };
2873
+ const response = await fetch(\`\${API_BASE_URL}\${pathname}\`, { ...init, headers });
2874
+ return readJsonResponse(response);
2875
+ }
2876
+
2877
+ async function hashFile(filePath) {
2878
+ const hash = createHash('sha1');
2879
+ let size = 0;
2880
+ for await (const chunk of createReadStream(filePath)) {
2881
+ size += chunk.length;
2882
+ hash.update(chunk);
2883
+ }
2884
+ return { sha: hash.digest('hex'), size };
2885
+ }
2886
+
2887
+ async function collectFiles(rootDirectory) {
2888
+ const files = [];
2889
+
2890
+ async function walk(currentDirectory) {
2891
+ const entries = await fs.readdir(currentDirectory, { withFileTypes: true });
2892
+ entries.sort((a, b) => a.name.localeCompare(b.name));
2893
+
2894
+ for (const entry of entries) {
2895
+ const absolutePath = path.join(currentDirectory, entry.name);
2896
+ const normalizedPath = path.relative(rootDirectory, absolutePath).split(path.sep).join('/').replace(/\\\\/g, '/');
2897
+
2898
+ if (!normalizedPath || shouldExcludeDeploymentPath(normalizedPath)) continue;
2899
+ if (entry.isDirectory()) {
2900
+ await walk(absolutePath);
2901
+ continue;
2902
+ }
2903
+ if (!entry.isFile()) continue;
2904
+
2905
+ const { sha, size } = await hashFile(absolutePath);
2906
+ files.push({ absolutePath, path: normalizedPath, sha, size });
2907
+ }
2908
+ }
2909
+
2910
+ await walk(rootDirectory);
2911
+ return files;
2912
+ }
2913
+
2914
+ const rootDirectory = process.cwd();
2915
+ const localFiles = await collectFiles(rootDirectory);
2916
+ if (localFiles.length === 0) throw new Error('No deployable files found after applying exclusions.');
2917
+
2918
+ const manifest = await api(\`/api/deployments/\${encodeURIComponent(deploymentId)}/manifest\`, {
2919
+ method: 'POST',
2920
+ headers: { 'Content-Type': 'application/json' },
2921
+ body: JSON.stringify({
2922
+ files: localFiles.map(({ path, sha, size }) => ({ path, sha, size })),
2923
+ }),
2924
+ });
2925
+
2926
+ const localFilesByPath = new Map(localFiles.map((file) => [file.path, file]));
2927
+ for (const remoteFile of manifest.files) {
2928
+ const localFile = localFilesByPath.get(remoteFile.path);
2929
+ if (!localFile) throw new Error(\`Manifest response included unknown path: \${remoteFile.path}\`);
2930
+
2931
+ const uploadResponse = await fetch(
2932
+ \`\${API_BASE_URL}/api/deployments/\${encodeURIComponent(deploymentId)}/files/\${encodeURIComponent(remoteFile.fileId)}/content\`,
2933
+ {
2934
+ method: 'PUT',
2935
+ headers: {
2936
+ 'x-api-key': API_KEY,
2937
+ 'Content-Type': 'application/octet-stream',
2938
+ 'Content-Length': String(localFile.size),
2939
+ },
2940
+ body: createReadStream(localFile.absolutePath),
2941
+ duplex: 'half',
2942
+ }
2943
+ );
2944
+ await readJsonResponse(uploadResponse);
2945
+ }
2946
+
2947
+ console.log(\`Deployment files uploaded. Deployment ID: \${deploymentId}\`);
2948
+ console.log(\`Uploaded \${localFiles.length} files through the direct deployment proxy.\`);
2949
+ NODE
2950
+ \`\`\`
2951
+
2952
+ After the script succeeds, call the \`start-deployment\` tool with the printed deployment ID.`;
2290
2953
  }
2291
2954
  function registerDeploymentTools(ctx) {
2292
- const { API_BASE_URL, isRemote, registerTool, withUsageTracking, getApiKey, addBackgroundContext } = ctx;
2955
+ const { API_BASE_URL, backendVersion, isRemote, registerTool, withUsageTracking, getApiKey, addBackgroundContext } = ctx;
2956
+ const supportsDirectDeployment = supportsDirectDeploymentVersion(backendVersion);
2293
2957
  registerTool(
2294
2958
  "get-container-logs",
2295
2959
  "Get latest logs from a specific container/service. Use this to help debug problems with your app.",
@@ -2329,14 +2993,13 @@ function registerDeploymentTools(ctx) {
2329
2993
  if (isRemote) {
2330
2994
  registerTool(
2331
2995
  "create-deployment",
2332
- "Prepare a deployment by creating a presigned upload URL. Returns shell commands for the agent to execute locally: zip the source directory and upload to cloud storage. After uploading, call the start-deployment tool to trigger the build.",
2996
+ "Prepare a deployment upload. For backends v2.0.5 and newer, returns direct file upload commands. Older backends use the legacy zip upload flow. After uploading, call the start-deployment tool to trigger the build.",
2333
2997
  {
2334
2998
  sourceDirectory: z29.string().describe('Absolute path to the source directory containing files to deploy (e.g., /Users/name/project). Do not use relative paths like "."')
2335
2999
  },
2336
3000
  withUsageTracking("create-deployment", async ({ sourceDirectory }) => {
2337
3001
  try {
2338
- const isAbsolutePath = sourceDirectory.startsWith("/") || /^[a-zA-Z]:[/\\]/.test(sourceDirectory);
2339
- if (!isAbsolutePath) {
3002
+ if (!isAbsoluteSourcePath(sourceDirectory)) {
2340
3003
  return {
2341
3004
  content: [{
2342
3005
  type: "text",
@@ -2345,6 +3008,21 @@ function registerDeploymentTools(ctx) {
2345
3008
  isError: true
2346
3009
  };
2347
3010
  }
3011
+ if (supportsDirectDeployment) {
3012
+ try {
3013
+ const createResult2 = await createDirectDeploymentSession(API_BASE_URL, getApiKey());
3014
+ return {
3015
+ content: [{
3016
+ type: "text",
3017
+ text: buildRemoteDirectUploadInstructions(API_BASE_URL, sourceDirectory, String(createResult2.id))
3018
+ }]
3019
+ };
3020
+ } catch (error) {
3021
+ if (!(error instanceof DirectDeploymentUnsupportedError)) {
3022
+ throw error;
3023
+ }
3024
+ }
3025
+ }
2348
3026
  const createResponse = await fetch6(`${API_BASE_URL}/api/deployments`, {
2349
3027
  method: "POST",
2350
3028
  headers: {
@@ -2352,10 +3030,7 @@ function registerDeploymentTools(ctx) {
2352
3030
  "Content-Type": "application/json"
2353
3031
  }
2354
3032
  });
2355
- const createResult = await handleApiResponse(createResponse);
2356
- if (!isCreateDeploymentResponse(createResult)) {
2357
- throw new Error("Unexpected response format from deployments endpoint");
2358
- }
3033
+ const createResult = parseCreateDeploymentResponse(await handleApiResponse(createResponse));
2359
3034
  const { id: deploymentId, uploadUrl, uploadFields } = createResult;
2360
3035
  const esc = shellEsc;
2361
3036
  const curlFields = Object.entries(uploadFields).map(([key, value]) => `-F ${esc(`${key}=${value}`)}`).join(" \\\n ");
@@ -2367,7 +3042,7 @@ Please execute the following commands locally, then call the \`start-deployment\
2367
3042
 
2368
3043
  ## Step 1: Zip the source directory
2369
3044
  \`\`\`bash
2370
- cd ${escapedDir} && zip -r ${tmpZip} . -x "node_modules/*" ".git/*" ".next/*" ".env" ".env.local" "dist/*" "build/*" ".DS_Store" "*.log"
3045
+ cd ${escapedDir} && zip -r ${tmpZip} . -x "node_modules/*" ".git/*" ".next/*" ".env*" "dist/*" "build/*" ".insforge/*" ".DS_Store" "*.log"
2371
3046
  \`\`\`
2372
3047
 
2373
3048
  ## Step 2: Upload the zip file
@@ -2436,15 +3111,14 @@ Run each step in order. If any step fails, do not proceed to the next step.`;
2436
3111
  } else {
2437
3112
  registerTool(
2438
3113
  "create-deployment",
2439
- "Deploy source code from a directory. This tool zips files, uploads to cloud storage, and triggers deployment with optional environment variables and project settings.",
3114
+ "Deploy source code from a directory. Uses direct file upload for backends v2.0.5 and newer, with legacy zip upload fallback for older projects.",
2440
3115
  {
2441
3116
  sourceDirectory: z29.string().describe('Absolute path to the source directory containing files to deploy (e.g., /Users/name/project or C:\\Users\\name\\project). Do not use relative paths like "."'),
2442
3117
  ...startDeploymentRequestSchema.shape
2443
3118
  },
2444
3119
  withUsageTracking("create-deployment", async ({ sourceDirectory, projectSettings, envVars, meta }) => {
2445
3120
  try {
2446
- const isAbsolutePath = sourceDirectory.startsWith("/") || /^[a-zA-Z]:[/\\]/.test(sourceDirectory);
2447
- if (!isAbsolutePath) {
3121
+ if (!isAbsoluteSourcePath(sourceDirectory)) {
2448
3122
  return {
2449
3123
  content: [{
2450
3124
  type: "text",
@@ -2474,6 +3148,26 @@ Run each step in order. If any step fails, do not proceed to the next step.`;
2474
3148
  };
2475
3149
  }
2476
3150
  const resolvedSourceDir = sourceDirectory;
3151
+ const startBody = buildStartBody({ projectSettings, envVars, meta });
3152
+ if (supportsDirectDeployment) {
3153
+ try {
3154
+ const { fileCount, startResult: startResult2 } = await deployDirect(API_BASE_URL, getApiKey(), resolvedSourceDir, startBody);
3155
+ return await addBackgroundContext({
3156
+ content: [{
3157
+ type: "text",
3158
+ text: formatSuccessMessage("Deployment started", startResult2) + `
3159
+
3160
+ Uploaded ${fileCount} files through the direct deployment proxy.
3161
+
3162
+ Note: You can check deployment status by querying the system.deployments table.`
3163
+ }]
3164
+ });
3165
+ } catch (error) {
3166
+ if (!(error instanceof DirectDeploymentUnsupportedError)) {
3167
+ throw error;
3168
+ }
3169
+ }
3170
+ }
2477
3171
  const createResponse = await fetch6(`${API_BASE_URL}/api/deployments`, {
2478
3172
  method: "POST",
2479
3173
  headers: {
@@ -2481,10 +3175,7 @@ Run each step in order. If any step fails, do not proceed to the next step.`;
2481
3175
  "Content-Type": "application/json"
2482
3176
  }
2483
3177
  });
2484
- const createResult = await handleApiResponse(createResponse);
2485
- if (!isCreateDeploymentResponse(createResult)) {
2486
- throw new Error("Unexpected response format from deployments endpoint");
2487
- }
3178
+ const createResult = parseCreateDeploymentResponse(await handleApiResponse(createResponse));
2488
3179
  const { id: deploymentId, uploadUrl, uploadFields } = createResult;
2489
3180
  const tmpZipPath = join2(tmpdir2(), `insforge-deploy-${deploymentId}.zip`);
2490
3181
  try {
@@ -2494,15 +3185,9 @@ Run each step in order. If any step fails, do not proceed to the next step.`;
2494
3185
  output.on("close", resolve);
2495
3186
  output.on("error", reject);
2496
3187
  archive.on("error", reject);
2497
- const excludePatterns = ["node_modules", ".git", ".next", ".env", ".env.local", "dist", "build", ".DS_Store"];
2498
3188
  archive.directory(resolvedSourceDir, false, (entry) => {
2499
3189
  const normalizedName = entry.name.replace(/\\/g, "/");
2500
- for (const pattern of excludePatterns) {
2501
- if (normalizedName.startsWith(pattern + "/") || normalizedName === pattern || normalizedName.endsWith("/" + pattern) || normalizedName.includes("/" + pattern + "/")) {
2502
- return false;
2503
- }
2504
- }
2505
- if (normalizedName.endsWith(".log")) return false;
3190
+ if (shouldExcludeDeploymentPath(normalizedName)) return false;
2506
3191
  return entry;
2507
3192
  });
2508
3193
  archive.pipe(output);
@@ -2530,19 +3215,7 @@ Run each step in order. If any step fails, do not proceed to the next step.`;
2530
3215
  } finally {
2531
3216
  await fs3.rm(tmpZipPath, { force: true }).catch(() => void 0);
2532
3217
  }
2533
- const startBody = {};
2534
- if (projectSettings) startBody.projectSettings = projectSettings;
2535
- if (envVars) startBody.envVars = envVars;
2536
- if (meta) startBody.meta = meta;
2537
- const startResponse = await fetch6(`${API_BASE_URL}/api/deployments/${encodeURIComponent(deploymentId)}/start`, {
2538
- method: "POST",
2539
- headers: {
2540
- "x-api-key": getApiKey(),
2541
- "Content-Type": "application/json"
2542
- },
2543
- body: JSON.stringify(startBody)
2544
- });
2545
- const startResult = await handleApiResponse(startResponse);
3218
+ const startResult = await startDeployment(API_BASE_URL, getApiKey(), deploymentId, startBody);
2546
3219
  return await addBackgroundContext({
2547
3220
  content: [{
2548
3221
  type: "text",
@@ -2628,7 +3301,11 @@ async function registerInsforgeTools(server, config = {}) {
2628
3301
  const GLOBAL_API_KEY = config.apiKey || process.env.API_KEY || "";
2629
3302
  const API_BASE_URL = config.apiBaseUrl || process.env.API_BASE_URL || "http://localhost:7130";
2630
3303
  const isRemote = config.mode === "remote";
2631
- const usageTracker = new UsageTracker(API_BASE_URL, GLOBAL_API_KEY);
3304
+ const usageTracker = new UsageTracker(API_BASE_URL, GLOBAL_API_KEY, {
3305
+ projectId: config.projectId,
3306
+ accessToken: config.accessToken,
3307
+ isRemote
3308
+ });
2632
3309
  let backendVersion;
2633
3310
  try {
2634
3311
  backendVersion = await fetchBackendVersion(API_BASE_URL);
@@ -2711,6 +3388,7 @@ ${result.content}`
2711
3388
  };
2712
3389
  const ctx = {
2713
3390
  API_BASE_URL,
3391
+ backendVersion,
2714
3392
  isRemote,
2715
3393
  registerTool,
2716
3394
  withUsageTracking,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  registerInsforgeTools
4
- } from "./chunk-DZ5W3BSP.js";
4
+ } from "./chunk-3HMBKVW5.js";
5
5
 
6
6
  // src/http/server.ts
7
7
  import "dotenv/config";
@@ -98,7 +98,9 @@ var SessionManager = class {
98
98
  const toolsConfig = await registerInsforgeTools(server, {
99
99
  apiKey: sessionData.apiKey,
100
100
  apiBaseUrl: sessionData.apiBaseUrl,
101
- mode: "remote"
101
+ mode: "remote",
102
+ projectId: sessionData.projectId,
103
+ accessToken: sessionData.oauthTokenHash
102
104
  });
103
105
  await server.connect(transport);
104
106
  const fullSessionData = {
@@ -186,7 +188,9 @@ var SessionManager = class {
186
188
  await registerInsforgeTools(server, {
187
189
  apiKey: sessionData.apiKey,
188
190
  apiBaseUrl: sessionData.apiBaseUrl,
189
- mode: "remote"
191
+ mode: "remote",
192
+ projectId: sessionData.projectId,
193
+ accessToken: sessionData.oauthTokenHash
190
194
  });
191
195
  await server.connect(transport);
192
196
  this.runtimeSessions.set(sessionId, { server, transport, transportType: "streamable" });
@@ -210,7 +214,9 @@ var SessionManager = class {
210
214
  const toolsConfig = await registerInsforgeTools(server, {
211
215
  apiKey: sessionData.apiKey,
212
216
  apiBaseUrl: sessionData.apiBaseUrl,
213
- mode: "remote"
217
+ mode: "remote",
218
+ projectId: sessionData.projectId,
219
+ accessToken: sessionData.oauthTokenHash
214
220
  });
215
221
  await server.connect(transport);
216
222
  const fullSessionData = {
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  registerInsforgeTools
4
- } from "./chunk-DZ5W3BSP.js";
4
+ } from "./chunk-3HMBKVW5.js";
5
5
 
6
6
  // src/stdio/index.ts
7
7
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@insforge/mcp",
3
- "version": "1.2.8",
3
+ "version": "1.2.10-dev.0",
4
4
  "description": "MCP (Model Context Protocol) server for Insforge backend-as-a-service",
5
5
  "mcpName": "io.github.InsForge/insforge-mcp",
6
6
  "type": "module",
@@ -45,7 +45,7 @@
45
45
  "server.json"
46
46
  ],
47
47
  "dependencies": {
48
- "@insforge/shared-schemas": "1.1.46",
48
+ "@insforge/shared-schemas": "1.1.48",
49
49
  "@modelcontextprotocol/sdk": "^1.27.1",
50
50
  "archiver": "^7.0.1",
51
51
  "commander": "^14.0.0",
@@ -61,6 +61,9 @@
61
61
  "brace-expansion": "^5.0.5",
62
62
  "glob": "^10.5.0",
63
63
  "minimatch": "^9.0.7",
64
+ "@hono/node-server": "^1.19.13",
65
+ "hono": "^4.12.12",
66
+ "lodash": "^4.18.0",
64
67
  "rollup": "^4.59.0"
65
68
  },
66
69
  "devDependencies": {
@@ -78,7 +81,7 @@
78
81
  "tsx": "^4.7.0",
79
82
  "typescript": "^5.3.3",
80
83
  "typescript-eslint": "^8.57.1",
81
- "vite": "^8.0.3",
84
+ "vite": "^8.0.5",
82
85
  "vitest": "^4.1.0"
83
86
  }
84
87
  }