yap2app 1.2.3 → 1.2.4

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/bin/cli.bundle.js CHANGED
@@ -7581,8 +7581,34 @@ var fs2 = fsSync2.promises || {
7581
7581
  };
7582
7582
  var PORT = Number(process.env.YAP2APP_PORT) || 10420;
7583
7583
  var PROJECT_ROOT = process.cwd();
7584
- var PAIR_CODE = (process.env.YAP2APP_PAIR_CODE || "Y2A-" + Math.floor(1e3 + Math.random() * 9e3)).toUpperCase();
7585
- var CLI_VERSION = "1.2.3";
7584
+ var CLI_VERSION = "1.2.4";
7585
+ function resolvePairCode() {
7586
+ if (process.env.YAP2APP_PAIR_CODE) {
7587
+ return process.env.YAP2APP_PAIR_CODE.trim().toUpperCase();
7588
+ }
7589
+ const configDir = path2.join(PROJECT_ROOT, ".yap2app");
7590
+ const configFile = path2.join(configDir, "bridge.json");
7591
+ try {
7592
+ if (fsSync2.existsSync(configFile)) {
7593
+ const raw = fsSync2.readFileSync(configFile, "utf8");
7594
+ const data = JSON.parse(raw);
7595
+ if (data.pair_code && typeof data.pair_code === "string") {
7596
+ return data.pair_code.trim().toUpperCase();
7597
+ }
7598
+ }
7599
+ } catch (e) {
7600
+ }
7601
+ const newCode = ("Y2A-" + Math.floor(1e3 + Math.random() * 9e3)).toUpperCase();
7602
+ try {
7603
+ if (!fsSync2.existsSync(configDir)) {
7604
+ fsSync2.mkdirSync(configDir, { recursive: true });
7605
+ }
7606
+ fsSync2.writeFileSync(configFile, JSON.stringify({ pair_code: newCode, created_at: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), "utf8");
7607
+ } catch (e) {
7608
+ }
7609
+ return newCode;
7610
+ }
7611
+ var PAIR_CODE = resolvePairCode();
7586
7612
  function getGitUserEmail() {
7587
7613
  try {
7588
7614
  const email2 = execSync("git config user.email", { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"] }).trim();
@@ -7609,18 +7635,23 @@ function safeResolvePath(baseDir, relativePath) {
7609
7635
  return resolved;
7610
7636
  }
7611
7637
  function getCorsHeaders(req) {
7612
- const origin = req?.headers?.origin || "*";
7638
+ const origin = req?.headers?.origin;
7613
7639
  const requestedHeaders = req?.headers?.["access-control-request-headers"] || "*";
7614
- return {
7615
- "Access-Control-Allow-Origin": origin,
7640
+ const headers = {
7616
7641
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS, PUT, DELETE, HEAD, PATCH",
7617
- "Access-Control-Allow-Headers": requestedHeaders === "*" ? "Content-Type, Authorization, Access-Control-Request-Private-Network, X-Requested-With, Accept, Origin, *" : requestedHeaders,
7642
+ "Access-Control-Allow-Headers": requestedHeaders === "*" ? "Content-Type, Authorization, Access-Control-Request-Private-Network, X-Requested-With, Accept, Origin, Cache-Control, Pragma, *" : requestedHeaders,
7618
7643
  "Access-Control-Allow-Private-Network": "true",
7619
- "Access-Control-Allow-Credentials": "true",
7620
7644
  "Access-Control-Max-Age": "86400",
7621
7645
  "Vary": "Origin, Access-Control-Request-Headers, Access-Control-Request-Private-Network",
7622
7646
  "Content-Type": "application/json"
7623
7647
  };
7648
+ if (origin) {
7649
+ headers["Access-Control-Allow-Origin"] = origin;
7650
+ headers["Access-Control-Allow-Credentials"] = "true";
7651
+ } else {
7652
+ headers["Access-Control-Allow-Origin"] = "*";
7653
+ }
7654
+ return headers;
7624
7655
  }
7625
7656
  function computeDiff(originalText, newText) {
7626
7657
  const originalLines = originalText ? originalText.split("\n") : [];
@@ -7774,7 +7805,9 @@ var server = http.createServer(async (req, res) => {
7774
7805
  res.end(JSON.stringify({ error: "Endpoint Not Found", path: pathname }));
7775
7806
  });
7776
7807
  var CLOUD_URL = process.env.YAP2APP_CLOUD_URL || "https://yap2app-dot-cybage-hackathon.uc.r.appspot.com";
7808
+ var isShuttingDown = false;
7777
7809
  async function sendCloudHeartbeat() {
7810
+ if (isShuttingDown) return;
7778
7811
  try {
7779
7812
  const context = await scanCodebase(PROJECT_ROOT);
7780
7813
  const payload = {
@@ -7800,6 +7833,32 @@ async function sendCloudHeartbeat() {
7800
7833
  } catch (err) {
7801
7834
  }
7802
7835
  }
7836
+ async function gracefulShutdown(signal = "SIGINT") {
7837
+ if (isShuttingDown) return;
7838
+ isShuttingDown = true;
7839
+ console.log(`
7840
+ [bridge] Disconnecting bridge (${signal}). Informing cloud relay...`);
7841
+ try {
7842
+ const controller = new AbortController();
7843
+ const timeoutId = setTimeout(() => controller.abort(), 1500);
7844
+ await fetch(`${CLOUD_URL}/api/v1/bridge/disconnect`, {
7845
+ method: "POST",
7846
+ headers: { "Content-Type": "application/json" },
7847
+ body: JSON.stringify({ pair_code: PAIR_CODE }),
7848
+ signal: controller.signal
7849
+ }).catch(() => {
7850
+ });
7851
+ clearTimeout(timeoutId);
7852
+ } catch (e) {
7853
+ }
7854
+ try {
7855
+ server.close();
7856
+ } catch (e) {
7857
+ }
7858
+ process.exit(0);
7859
+ }
7860
+ process.once("SIGINT", () => gracefulShutdown("SIGINT"));
7861
+ process.once("SIGTERM", () => gracefulShutdown("SIGTERM"));
7803
7862
  async function pollAndExecuteCloudWrites() {
7804
7863
  try {
7805
7864
  const res = await fetch(`${CLOUD_URL}/api/v1/bridge/poll-writes?pair_code=${encodeURIComponent(PAIR_CODE)}`);
package/bin/cli.js CHANGED
@@ -7581,8 +7581,34 @@ var fs2 = fsSync2.promises || {
7581
7581
  };
7582
7582
  var PORT = Number(process.env.YAP2APP_PORT) || 10420;
7583
7583
  var PROJECT_ROOT = process.cwd();
7584
- var PAIR_CODE = (process.env.YAP2APP_PAIR_CODE || "Y2A-" + Math.floor(1e3 + Math.random() * 9e3)).toUpperCase();
7585
- var CLI_VERSION = "1.2.3";
7584
+ var CLI_VERSION = "1.2.4";
7585
+ function resolvePairCode() {
7586
+ if (process.env.YAP2APP_PAIR_CODE) {
7587
+ return process.env.YAP2APP_PAIR_CODE.trim().toUpperCase();
7588
+ }
7589
+ const configDir = path2.join(PROJECT_ROOT, ".yap2app");
7590
+ const configFile = path2.join(configDir, "bridge.json");
7591
+ try {
7592
+ if (fsSync2.existsSync(configFile)) {
7593
+ const raw = fsSync2.readFileSync(configFile, "utf8");
7594
+ const data = JSON.parse(raw);
7595
+ if (data.pair_code && typeof data.pair_code === "string") {
7596
+ return data.pair_code.trim().toUpperCase();
7597
+ }
7598
+ }
7599
+ } catch (e) {
7600
+ }
7601
+ const newCode = ("Y2A-" + Math.floor(1e3 + Math.random() * 9e3)).toUpperCase();
7602
+ try {
7603
+ if (!fsSync2.existsSync(configDir)) {
7604
+ fsSync2.mkdirSync(configDir, { recursive: true });
7605
+ }
7606
+ fsSync2.writeFileSync(configFile, JSON.stringify({ pair_code: newCode, created_at: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), "utf8");
7607
+ } catch (e) {
7608
+ }
7609
+ return newCode;
7610
+ }
7611
+ var PAIR_CODE = resolvePairCode();
7586
7612
  function getGitUserEmail() {
7587
7613
  try {
7588
7614
  const email2 = execSync("git config user.email", { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"] }).trim();
@@ -7609,18 +7635,23 @@ function safeResolvePath(baseDir, relativePath) {
7609
7635
  return resolved;
7610
7636
  }
7611
7637
  function getCorsHeaders(req) {
7612
- const origin = req?.headers?.origin || "*";
7638
+ const origin = req?.headers?.origin;
7613
7639
  const requestedHeaders = req?.headers?.["access-control-request-headers"] || "*";
7614
- return {
7615
- "Access-Control-Allow-Origin": origin,
7640
+ const headers = {
7616
7641
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS, PUT, DELETE, HEAD, PATCH",
7617
- "Access-Control-Allow-Headers": requestedHeaders === "*" ? "Content-Type, Authorization, Access-Control-Request-Private-Network, X-Requested-With, Accept, Origin, *" : requestedHeaders,
7642
+ "Access-Control-Allow-Headers": requestedHeaders === "*" ? "Content-Type, Authorization, Access-Control-Request-Private-Network, X-Requested-With, Accept, Origin, Cache-Control, Pragma, *" : requestedHeaders,
7618
7643
  "Access-Control-Allow-Private-Network": "true",
7619
- "Access-Control-Allow-Credentials": "true",
7620
7644
  "Access-Control-Max-Age": "86400",
7621
7645
  "Vary": "Origin, Access-Control-Request-Headers, Access-Control-Request-Private-Network",
7622
7646
  "Content-Type": "application/json"
7623
7647
  };
7648
+ if (origin) {
7649
+ headers["Access-Control-Allow-Origin"] = origin;
7650
+ headers["Access-Control-Allow-Credentials"] = "true";
7651
+ } else {
7652
+ headers["Access-Control-Allow-Origin"] = "*";
7653
+ }
7654
+ return headers;
7624
7655
  }
7625
7656
  function computeDiff(originalText, newText) {
7626
7657
  const originalLines = originalText ? originalText.split("\n") : [];
@@ -7774,7 +7805,9 @@ var server = http.createServer(async (req, res) => {
7774
7805
  res.end(JSON.stringify({ error: "Endpoint Not Found", path: pathname }));
7775
7806
  });
7776
7807
  var CLOUD_URL = process.env.YAP2APP_CLOUD_URL || "https://yap2app-dot-cybage-hackathon.uc.r.appspot.com";
7808
+ var isShuttingDown = false;
7777
7809
  async function sendCloudHeartbeat() {
7810
+ if (isShuttingDown) return;
7778
7811
  try {
7779
7812
  const context = await scanCodebase(PROJECT_ROOT);
7780
7813
  const payload = {
@@ -7800,6 +7833,32 @@ async function sendCloudHeartbeat() {
7800
7833
  } catch (err) {
7801
7834
  }
7802
7835
  }
7836
+ async function gracefulShutdown(signal = "SIGINT") {
7837
+ if (isShuttingDown) return;
7838
+ isShuttingDown = true;
7839
+ console.log(`
7840
+ [bridge] Disconnecting bridge (${signal}). Informing cloud relay...`);
7841
+ try {
7842
+ const controller = new AbortController();
7843
+ const timeoutId = setTimeout(() => controller.abort(), 1500);
7844
+ await fetch(`${CLOUD_URL}/api/v1/bridge/disconnect`, {
7845
+ method: "POST",
7846
+ headers: { "Content-Type": "application/json" },
7847
+ body: JSON.stringify({ pair_code: PAIR_CODE }),
7848
+ signal: controller.signal
7849
+ }).catch(() => {
7850
+ });
7851
+ clearTimeout(timeoutId);
7852
+ } catch (e) {
7853
+ }
7854
+ try {
7855
+ server.close();
7856
+ } catch (e) {
7857
+ }
7858
+ process.exit(0);
7859
+ }
7860
+ process.once("SIGINT", () => gracefulShutdown("SIGINT"));
7861
+ process.once("SIGTERM", () => gracefulShutdown("SIGTERM"));
7803
7862
  async function pollAndExecuteCloudWrites() {
7804
7863
  try {
7805
7864
  const res = await fetch(`${CLOUD_URL}/api/v1/bridge/poll-writes?pair_code=${encodeURIComponent(PAIR_CODE)}`);
package/bridge.js CHANGED
@@ -15,8 +15,35 @@ const fs = fsSync.promises || {
15
15
 
16
16
  const PORT = Number(process.env.YAP2APP_PORT) || 10420;
17
17
  const PROJECT_ROOT = process.cwd();
18
- const PAIR_CODE = (process.env.YAP2APP_PAIR_CODE || ('Y2A-' + Math.floor(1000 + Math.random() * 9000))).toUpperCase();
19
- const CLI_VERSION = '1.2.3';
18
+ const CLI_VERSION = '1.2.4';
19
+
20
+ function resolvePairCode() {
21
+ if (process.env.YAP2APP_PAIR_CODE) {
22
+ return process.env.YAP2APP_PAIR_CODE.trim().toUpperCase();
23
+ }
24
+ const configDir = path.join(PROJECT_ROOT, '.yap2app');
25
+ const configFile = path.join(configDir, 'bridge.json');
26
+ try {
27
+ if (fsSync.existsSync(configFile)) {
28
+ const raw = fsSync.readFileSync(configFile, 'utf8');
29
+ const data = JSON.parse(raw);
30
+ if (data.pair_code && typeof data.pair_code === 'string') {
31
+ return data.pair_code.trim().toUpperCase();
32
+ }
33
+ }
34
+ } catch (e) {}
35
+
36
+ const newCode = ('Y2A-' + Math.floor(1000 + Math.random() * 9000)).toUpperCase();
37
+ try {
38
+ if (!fsSync.existsSync(configDir)) {
39
+ fsSync.mkdirSync(configDir, { recursive: true });
40
+ }
41
+ fsSync.writeFileSync(configFile, JSON.stringify({ pair_code: newCode, created_at: new Date().toISOString() }, null, 2), 'utf8');
42
+ } catch (e) {}
43
+ return newCode;
44
+ }
45
+
46
+ const PAIR_CODE = resolvePairCode();
20
47
 
21
48
  function getGitUserEmail() {
22
49
  try {
@@ -53,18 +80,25 @@ function safeResolvePath(baseDir, relativePath) {
53
80
 
54
81
  // Bulletproof W3C Private Network Access (PNA) and Dynamic Origin CORS Headers
55
82
  function getCorsHeaders(req) {
56
- const origin = req?.headers?.origin || '*';
83
+ const origin = req?.headers?.origin;
57
84
  const requestedHeaders = req?.headers?.['access-control-request-headers'] || '*';
58
- return {
59
- 'Access-Control-Allow-Origin': origin,
85
+ const headers = {
60
86
  'Access-Control-Allow-Methods': 'GET, POST, OPTIONS, PUT, DELETE, HEAD, PATCH',
61
- 'Access-Control-Allow-Headers': requestedHeaders === '*' ? 'Content-Type, Authorization, Access-Control-Request-Private-Network, X-Requested-With, Accept, Origin, *' : requestedHeaders,
87
+ 'Access-Control-Allow-Headers': requestedHeaders === '*'
88
+ ? 'Content-Type, Authorization, Access-Control-Request-Private-Network, X-Requested-With, Accept, Origin, Cache-Control, Pragma, *'
89
+ : requestedHeaders,
62
90
  'Access-Control-Allow-Private-Network': 'true',
63
- 'Access-Control-Allow-Credentials': 'true',
64
91
  'Access-Control-Max-Age': '86400',
65
92
  'Vary': 'Origin, Access-Control-Request-Headers, Access-Control-Request-Private-Network',
66
93
  'Content-Type': 'application/json'
67
94
  };
95
+ if (origin) {
96
+ headers['Access-Control-Allow-Origin'] = origin;
97
+ headers['Access-Control-Allow-Credentials'] = 'true';
98
+ } else {
99
+ headers['Access-Control-Allow-Origin'] = '*';
100
+ }
101
+ return headers;
68
102
  }
69
103
 
70
104
  /**
@@ -259,7 +293,10 @@ const server = http.createServer(async (req, res) => {
259
293
 
260
294
  const CLOUD_URL = process.env.YAP2APP_CLOUD_URL || 'https://yap2app-dot-cybage-hackathon.uc.r.appspot.com';
261
295
 
296
+ let isShuttingDown = false;
297
+
262
298
  async function sendCloudHeartbeat() {
299
+ if (isShuttingDown) return;
263
300
  try {
264
301
  const context = await scanCodebase(PROJECT_ROOT);
265
302
  const payload = {
@@ -289,6 +326,30 @@ async function sendCloudHeartbeat() {
289
326
  }
290
327
  }
291
328
 
329
+ export async function gracefulShutdown(signal = 'SIGINT') {
330
+ if (isShuttingDown) return;
331
+ isShuttingDown = true;
332
+ console.log(`\n [bridge] Disconnecting bridge (${signal}). Informing cloud relay...`);
333
+ try {
334
+ const controller = new AbortController();
335
+ const timeoutId = setTimeout(() => controller.abort(), 1500);
336
+ await fetch(`${CLOUD_URL}/api/v1/bridge/disconnect`, {
337
+ method: 'POST',
338
+ headers: { 'Content-Type': 'application/json' },
339
+ body: JSON.stringify({ pair_code: PAIR_CODE }),
340
+ signal: controller.signal
341
+ }).catch(() => {});
342
+ clearTimeout(timeoutId);
343
+ } catch (e) {}
344
+ try {
345
+ server.close();
346
+ } catch (e) {}
347
+ process.exit(0);
348
+ }
349
+
350
+ process.once('SIGINT', () => gracefulShutdown('SIGINT'));
351
+ process.once('SIGTERM', () => gracefulShutdown('SIGTERM'));
352
+
292
353
  async function pollAndExecuteCloudWrites() {
293
354
  try {
294
355
  const res = await fetch(`${CLOUD_URL}/api/v1/bridge/poll-writes?pair_code=${encodeURIComponent(PAIR_CODE)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yap2app",
3
- "version": "1.2.3",
3
+ "version": "1.2.4",
4
4
  "type": "module",
5
5
  "description": "Autonomous Vibe-to-Prod Localhost Bridge & Model Context Protocol (MCP) Server",
6
6
  "main": "bin/cli.bundle.js",