@kylewadegrove/cutline-mcp-cli 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/callback.d.ts +2 -1
- package/dist/auth/callback.js +7 -2
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +1 -1
- package/dist/commands/setup.js +2 -2
- package/dist/commands/upgrade.js +1 -1
- package/dist/servers/{chunk-IVWF7VYZ.js → chunk-M37M2UA4.js} +517 -95
- package/dist/servers/chunk-NUBIEJTU.js +398 -0
- package/dist/servers/chunk-OP4EO6FV.js +454 -0
- package/dist/servers/chunk-PQUAX5YW.js +464 -0
- package/dist/servers/cutline-server.js +157 -633
- package/dist/servers/data-client-2IQIMRIS.js +117 -0
- package/dist/servers/exploration-server.js +65 -142
- package/dist/servers/integrations-server.js +7 -7
- package/dist/servers/output-server.js +7 -7
- package/dist/servers/premortem-server.js +57 -116
- package/dist/servers/tools-server.js +7 -7
- package/package.json +1 -1
- package/dist/servers/chunk-PD2HN2R5.js +0 -908
- package/dist/servers/chunk-PU7TL6S3.js +0 -91
- package/dist/servers/chunk-TGSEURMN.js +0 -46
- package/dist/servers/score-history-HO5KRVGC.js +0 -6
|
@@ -87,8 +87,8 @@ async function identifyTrialUser(attrs) {
|
|
|
87
87
|
created_at: Math.floor(Date.now() / 1e3)
|
|
88
88
|
});
|
|
89
89
|
console.log(`[Customer.io] Identified trial user: ${attrs.email}`);
|
|
90
|
-
} catch (
|
|
91
|
-
console.error("[Customer.io] Error identifying trial user:",
|
|
90
|
+
} catch (error6) {
|
|
91
|
+
console.error("[Customer.io] Error identifying trial user:", error6);
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
async function trackTrialEvent(email, event, data) {
|
|
@@ -101,8 +101,8 @@ async function trackTrialEvent(email, event, data) {
|
|
|
101
101
|
data: { ...data, timestamp: Math.floor(Date.now() / 1e3) }
|
|
102
102
|
});
|
|
103
103
|
console.log(`[Customer.io] Tracked ${event} for ${email}`);
|
|
104
|
-
} catch (
|
|
105
|
-
console.error(`[Customer.io] Error tracking ${event}:`,
|
|
104
|
+
} catch (error6) {
|
|
105
|
+
console.error(`[Customer.io] Error tracking ${event}:`, error6);
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
var rateLimitStore = /* @__PURE__ */ new Map();
|
|
@@ -908,8 +908,8 @@ var stripeWebhooks = onRequest4({ cors: true, timeoutSeconds: 30, memory: "512Mi
|
|
|
908
908
|
await processStripeEvent(event, stripe);
|
|
909
909
|
audit({ eventType: "data.updated", resourceType: "stripe_webhook", resourceId: event.id, data: { type: event.type } });
|
|
910
910
|
res.status(200).json({ success: true });
|
|
911
|
-
} catch (
|
|
912
|
-
console.error(`[Stripe] Webhook handling failed for ${event.type}:`,
|
|
911
|
+
} catch (error6) {
|
|
912
|
+
console.error(`[Stripe] Webhook handling failed for ${event.type}:`, error6);
|
|
913
913
|
audit({ eventType: "pipeline.failed", resourceType: "stripe_webhook", resourceId: event.id, success: false, error: "Webhook handling failed", data: { type: event.type } });
|
|
914
914
|
res.status(500).json({ error: "Webhook handling failed" });
|
|
915
915
|
}
|
|
@@ -5737,9 +5737,9 @@ Respond as ${personaContext.persona.name} would. Be authentic, specific, and tru
|
|
|
5737
5737
|
confidence: parsed.confidence,
|
|
5738
5738
|
reasoning: parsed.reasoning
|
|
5739
5739
|
};
|
|
5740
|
-
} catch (
|
|
5741
|
-
console.error("[persona-agent] Error generating response:",
|
|
5742
|
-
throw new Error(`Failed to generate persona response: ${
|
|
5740
|
+
} catch (error6) {
|
|
5741
|
+
console.error("[persona-agent] Error generating response:", error6);
|
|
5742
|
+
throw new Error(`Failed to generate persona response: ${error6.message}`);
|
|
5743
5743
|
}
|
|
5744
5744
|
}
|
|
5745
5745
|
|
|
@@ -6602,8 +6602,8 @@ async function identifyVibekitUser(attrs) {
|
|
|
6602
6602
|
created_at: Math.floor(Date.now() / 1e3)
|
|
6603
6603
|
});
|
|
6604
6604
|
console.log(`[Customer.io] Identified vibekit user: ${attrs.email}`);
|
|
6605
|
-
} catch (
|
|
6606
|
-
console.error("[Customer.io] Error identifying vibekit user:",
|
|
6605
|
+
} catch (error6) {
|
|
6606
|
+
console.error("[Customer.io] Error identifying vibekit user:", error6);
|
|
6607
6607
|
}
|
|
6608
6608
|
}
|
|
6609
6609
|
async function trackVibekitEvent(email, event, data) {
|
|
@@ -6616,8 +6616,8 @@ async function trackVibekitEvent(email, event, data) {
|
|
|
6616
6616
|
data: { ...data, timestamp: Math.floor(Date.now() / 1e3) }
|
|
6617
6617
|
});
|
|
6618
6618
|
console.log(`[Customer.io] Tracked ${event} for ${email}`);
|
|
6619
|
-
} catch (
|
|
6620
|
-
console.error(`[Customer.io] Error tracking ${event}:`,
|
|
6619
|
+
} catch (error6) {
|
|
6620
|
+
console.error(`[Customer.io] Error tracking ${event}:`, error6);
|
|
6621
6621
|
}
|
|
6622
6622
|
}
|
|
6623
6623
|
var ALLOWED_ORIGINS = [
|
|
@@ -7747,8 +7747,8 @@ Respond conversationally while advancing the discovery. Put structured data in a
|
|
|
7747
7747
|
response.artifacts = artifacts;
|
|
7748
7748
|
}
|
|
7749
7749
|
return response;
|
|
7750
|
-
} catch (
|
|
7751
|
-
console.error("[consulting-discovery-agent] Error:",
|
|
7750
|
+
} catch (error6) {
|
|
7751
|
+
console.error("[consulting-discovery-agent] Error:", error6);
|
|
7752
7752
|
return {
|
|
7753
7753
|
content: getDegenerateFallback2(context.currentAct, context),
|
|
7754
7754
|
wasFallback: true
|
|
@@ -9504,18 +9504,18 @@ var personaAgent = onRequest17({ cors: true, timeoutSeconds: 60, memory: "512MiB
|
|
|
9504
9504
|
confidence: response.confidence,
|
|
9505
9505
|
reasoning: response.reasoning
|
|
9506
9506
|
});
|
|
9507
|
-
} catch (
|
|
9508
|
-
console.error("[persona-agent] Error:",
|
|
9507
|
+
} catch (error6) {
|
|
9508
|
+
console.error("[persona-agent] Error:", error6);
|
|
9509
9509
|
res.status(500).json({
|
|
9510
9510
|
error: "Failed to generate persona response",
|
|
9511
|
-
message:
|
|
9511
|
+
message: error6?.message || "Unknown error"
|
|
9512
9512
|
});
|
|
9513
9513
|
}
|
|
9514
|
-
} catch (
|
|
9515
|
-
console.error("[persona-agent] Request error:",
|
|
9514
|
+
} catch (error6) {
|
|
9515
|
+
console.error("[persona-agent] Request error:", error6);
|
|
9516
9516
|
res.status(500).json({
|
|
9517
9517
|
error: "Internal server error",
|
|
9518
|
-
message:
|
|
9518
|
+
message: error6?.message || "Unknown error"
|
|
9519
9519
|
});
|
|
9520
9520
|
}
|
|
9521
9521
|
});
|
|
@@ -9604,18 +9604,18 @@ var mcpGenerateTokenG2 = onCall({ timeoutSeconds: 60 }, async (request) => {
|
|
|
9604
9604
|
deviceId,
|
|
9605
9605
|
email: auth?.token.email
|
|
9606
9606
|
};
|
|
9607
|
-
} catch (
|
|
9607
|
+
} catch (error6) {
|
|
9608
9608
|
logger.error("MCP token generation failed", {
|
|
9609
9609
|
uid,
|
|
9610
9610
|
deviceId,
|
|
9611
9611
|
error: {
|
|
9612
|
-
message:
|
|
9613
|
-
code:
|
|
9612
|
+
message: error6.message,
|
|
9613
|
+
code: error6.code
|
|
9614
9614
|
}
|
|
9615
9615
|
});
|
|
9616
9616
|
audit({ eventType: "security.anomaly", userId: uid, resourceType: "mcp_token", resourceId: deviceId, success: false, error: "Token generation failed" });
|
|
9617
|
-
if (
|
|
9618
|
-
throw
|
|
9617
|
+
if (error6 instanceof HttpsError2) {
|
|
9618
|
+
throw error6;
|
|
9619
9619
|
}
|
|
9620
9620
|
throw new HttpsError2("internal", "Failed to generate MCP token");
|
|
9621
9621
|
}
|
|
@@ -9670,13 +9670,13 @@ var mcpSubscriptionStatus = onRequest18({
|
|
|
9670
9670
|
};
|
|
9671
9671
|
logger2.info("Subscription status retrieved", { uid, status: response.status });
|
|
9672
9672
|
res.json(response);
|
|
9673
|
-
} catch (
|
|
9674
|
-
logger2.error("Failed to get subscription status", { error:
|
|
9675
|
-
if (
|
|
9673
|
+
} catch (error6) {
|
|
9674
|
+
logger2.error("Failed to get subscription status", { error: error6.message });
|
|
9675
|
+
if (error6.code === "auth/id-token-expired") {
|
|
9676
9676
|
res.status(401).json({ error: "Token expired" });
|
|
9677
9677
|
return;
|
|
9678
9678
|
}
|
|
9679
|
-
if (
|
|
9679
|
+
if (error6.code === "auth/argument-error" || error6.code === "auth/invalid-id-token") {
|
|
9680
9680
|
res.status(401).json({ error: "Invalid token" });
|
|
9681
9681
|
return;
|
|
9682
9682
|
}
|
|
@@ -9716,13 +9716,13 @@ var mcpListProducts = onRequest19({ timeoutSeconds: 30, cors: true }, async (req
|
|
|
9716
9716
|
};
|
|
9717
9717
|
});
|
|
9718
9718
|
res.json({ products });
|
|
9719
|
-
} catch (
|
|
9720
|
-
logger3.error("Failed to list products", { error:
|
|
9721
|
-
if (
|
|
9719
|
+
} catch (error6) {
|
|
9720
|
+
logger3.error("Failed to list products", { error: error6.message });
|
|
9721
|
+
if (error6.code === "auth/id-token-expired") {
|
|
9722
9722
|
res.status(401).json({ error: "Token expired" });
|
|
9723
9723
|
return;
|
|
9724
9724
|
}
|
|
9725
|
-
if (
|
|
9725
|
+
if (error6.code === "auth/argument-error" || error6.code === "auth/invalid-id-token") {
|
|
9726
9726
|
res.status(401).json({ error: "Invalid token" });
|
|
9727
9727
|
return;
|
|
9728
9728
|
}
|
|
@@ -9730,11 +9730,433 @@ var mcpListProducts = onRequest19({ timeoutSeconds: 30, cors: true }, async (req
|
|
|
9730
9730
|
}
|
|
9731
9731
|
});
|
|
9732
9732
|
|
|
9733
|
+
// ../lib/mcp/data-proxy.js
|
|
9734
|
+
import { onRequest as onRequest20 } from "firebase-functions/v2/https";
|
|
9735
|
+
import * as logger4 from "firebase-functions/logger";
|
|
9736
|
+
import admin17 from "firebase-admin";
|
|
9737
|
+
var handlers = {};
|
|
9738
|
+
function register(action, handler) {
|
|
9739
|
+
handlers[action] = handler;
|
|
9740
|
+
}
|
|
9741
|
+
register("premortem.list", async (uid, params) => {
|
|
9742
|
+
const db = admin17.firestore();
|
|
9743
|
+
let query = db.collection("premortem_jobs").where("uid", "==", uid).orderBy("createdAt", "desc");
|
|
9744
|
+
if (params.status) {
|
|
9745
|
+
query = query.where("status", "==", params.status);
|
|
9746
|
+
}
|
|
9747
|
+
if (params.limit) {
|
|
9748
|
+
query = query.limit(Math.min(params.limit, 100));
|
|
9749
|
+
}
|
|
9750
|
+
const snap = await query.get();
|
|
9751
|
+
return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
|
|
9752
|
+
});
|
|
9753
|
+
register("premortem.get", async (uid, params) => {
|
|
9754
|
+
const db = admin17.firestore();
|
|
9755
|
+
const doc = await db.collection("premortem_jobs").doc(params.id).get();
|
|
9756
|
+
if (!doc.exists)
|
|
9757
|
+
return { doc: null };
|
|
9758
|
+
const data = doc.data();
|
|
9759
|
+
if (data?.uid !== uid)
|
|
9760
|
+
return { doc: null };
|
|
9761
|
+
return { doc: { id: doc.id, ...data } };
|
|
9762
|
+
});
|
|
9763
|
+
register("premortem.create", async (uid, params) => {
|
|
9764
|
+
const db = admin17.firestore();
|
|
9765
|
+
const ref = params.id ? db.collection("premortem_jobs").doc(params.id) : db.collection("premortem_jobs").doc();
|
|
9766
|
+
await ref.set({ ...params.data, uid, createdAt: admin17.firestore.FieldValue.serverTimestamp() });
|
|
9767
|
+
return { id: ref.id };
|
|
9768
|
+
});
|
|
9769
|
+
register("premortem.update", async (uid, params) => {
|
|
9770
|
+
const db = admin17.firestore();
|
|
9771
|
+
const ref = db.collection("premortem_jobs").doc(params.id);
|
|
9772
|
+
const doc = await ref.get();
|
|
9773
|
+
if (!doc.exists || doc.data()?.uid !== uid) {
|
|
9774
|
+
throw new Error("Not found or not authorized");
|
|
9775
|
+
}
|
|
9776
|
+
await ref.update(params.data);
|
|
9777
|
+
return { ok: true };
|
|
9778
|
+
});
|
|
9779
|
+
register("premortem.getIdea", async (uid, params) => {
|
|
9780
|
+
const db = admin17.firestore();
|
|
9781
|
+
const doc = await db.collection("idea_reports").doc(params.id).get();
|
|
9782
|
+
if (!doc.exists)
|
|
9783
|
+
return { doc: null };
|
|
9784
|
+
return { doc: { id: doc.id, ...doc.data() } };
|
|
9785
|
+
});
|
|
9786
|
+
register("chat.save", async (uid, params) => {
|
|
9787
|
+
const db = admin17.firestore();
|
|
9788
|
+
const ref = db.collection("premortem_chats").doc(params.id);
|
|
9789
|
+
await ref.set({ ...params.data, uid, updatedAt: admin17.firestore.FieldValue.serverTimestamp() });
|
|
9790
|
+
return { id: ref.id };
|
|
9791
|
+
});
|
|
9792
|
+
register("chat.get", async (uid, params) => {
|
|
9793
|
+
const db = admin17.firestore();
|
|
9794
|
+
const doc = await db.collection("premortem_chats").doc(params.id).get();
|
|
9795
|
+
if (!doc.exists)
|
|
9796
|
+
return { doc: null };
|
|
9797
|
+
const data = doc.data();
|
|
9798
|
+
if (data?.uid !== uid)
|
|
9799
|
+
return { doc: null };
|
|
9800
|
+
return { doc: { id: doc.id, ...data } };
|
|
9801
|
+
});
|
|
9802
|
+
register("chat.update", async (uid, params) => {
|
|
9803
|
+
const db = admin17.firestore();
|
|
9804
|
+
const ref = db.collection("premortem_chats").doc(params.id);
|
|
9805
|
+
const doc = await ref.get();
|
|
9806
|
+
if (!doc.exists || doc.data()?.uid !== uid) {
|
|
9807
|
+
throw new Error("Not found or not authorized");
|
|
9808
|
+
}
|
|
9809
|
+
await ref.update(params.data);
|
|
9810
|
+
return { ok: true };
|
|
9811
|
+
});
|
|
9812
|
+
register("exploration.create", async (uid, params) => {
|
|
9813
|
+
const db = admin17.firestore();
|
|
9814
|
+
const collection = params.collection || "exploration_sessions";
|
|
9815
|
+
const ref = db.collection(collection).doc(params.id);
|
|
9816
|
+
await ref.set({ ...params.data, uid, createdAt: admin17.firestore.FieldValue.serverTimestamp() });
|
|
9817
|
+
return { id: ref.id };
|
|
9818
|
+
});
|
|
9819
|
+
register("exploration.get", async (uid, params) => {
|
|
9820
|
+
const db = admin17.firestore();
|
|
9821
|
+
const collection = params.collection || "exploration_sessions";
|
|
9822
|
+
const doc = await db.collection(collection).doc(params.id).get();
|
|
9823
|
+
if (!doc.exists)
|
|
9824
|
+
return { doc: null };
|
|
9825
|
+
const data = doc.data();
|
|
9826
|
+
if (data?.uid !== uid)
|
|
9827
|
+
return { doc: null };
|
|
9828
|
+
return { doc: { id: doc.id, ...data } };
|
|
9829
|
+
});
|
|
9830
|
+
register("exploration.update", async (uid, params) => {
|
|
9831
|
+
const db = admin17.firestore();
|
|
9832
|
+
const collection = params.collection || "exploration_sessions";
|
|
9833
|
+
const ref = db.collection(collection).doc(params.id);
|
|
9834
|
+
const doc = await ref.get();
|
|
9835
|
+
if (!doc.exists || doc.data()?.uid !== uid) {
|
|
9836
|
+
throw new Error("Not found or not authorized");
|
|
9837
|
+
}
|
|
9838
|
+
await ref.update(params.data);
|
|
9839
|
+
return { ok: true };
|
|
9840
|
+
});
|
|
9841
|
+
register("exploration.list", async (uid, params) => {
|
|
9842
|
+
const db = admin17.firestore();
|
|
9843
|
+
const collection = params.collection || "exploration_sessions";
|
|
9844
|
+
const limit = Math.min(params.limit || 20, 100);
|
|
9845
|
+
const snap = await db.collection(collection).where("uid", "==", uid).orderBy("createdAt", "desc").limit(limit).get();
|
|
9846
|
+
return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
|
|
9847
|
+
});
|
|
9848
|
+
function graphCol(productId, sub) {
|
|
9849
|
+
return admin17.firestore().collection("context_graph").doc(productId).collection(sub);
|
|
9850
|
+
}
|
|
9851
|
+
register("graph.getEntities", async (_uid, params) => {
|
|
9852
|
+
const snap = await graphCol(params.productId, "entities").get();
|
|
9853
|
+
return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
|
|
9854
|
+
});
|
|
9855
|
+
register("graph.upsertEntities", async (_uid, params) => {
|
|
9856
|
+
const col = graphCol(params.productId, "entities");
|
|
9857
|
+
const batch = admin17.firestore().batch();
|
|
9858
|
+
if (params.deleteIds?.length) {
|
|
9859
|
+
for (const id of params.deleteIds) {
|
|
9860
|
+
batch.delete(col.doc(id));
|
|
9861
|
+
}
|
|
9862
|
+
}
|
|
9863
|
+
if (params.entities?.length) {
|
|
9864
|
+
for (const entity of params.entities) {
|
|
9865
|
+
const id = entity.id || col.doc().id;
|
|
9866
|
+
batch.set(col.doc(id), entity);
|
|
9867
|
+
}
|
|
9868
|
+
}
|
|
9869
|
+
await batch.commit();
|
|
9870
|
+
return { ok: true };
|
|
9871
|
+
});
|
|
9872
|
+
register("graph.getEdges", async (_uid, params) => {
|
|
9873
|
+
const snap = await graphCol(params.productId, "edges").get();
|
|
9874
|
+
return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
|
|
9875
|
+
});
|
|
9876
|
+
register("graph.upsertEdges", async (_uid, params) => {
|
|
9877
|
+
const col = graphCol(params.productId, "edges");
|
|
9878
|
+
const batch = admin17.firestore().batch();
|
|
9879
|
+
if (params.deleteIds?.length) {
|
|
9880
|
+
for (const id of params.deleteIds) {
|
|
9881
|
+
batch.delete(col.doc(id));
|
|
9882
|
+
}
|
|
9883
|
+
}
|
|
9884
|
+
if (params.edges?.length) {
|
|
9885
|
+
for (const edge of params.edges) {
|
|
9886
|
+
const id = edge.id || col.doc().id;
|
|
9887
|
+
batch.set(col.doc(id), edge);
|
|
9888
|
+
}
|
|
9889
|
+
}
|
|
9890
|
+
await batch.commit();
|
|
9891
|
+
return { ok: true };
|
|
9892
|
+
});
|
|
9893
|
+
register("graph.getBindings", async (_uid, params) => {
|
|
9894
|
+
const col = graphCol(params.productId, "bindings");
|
|
9895
|
+
let query = col;
|
|
9896
|
+
if (params.entityId) {
|
|
9897
|
+
query = col.where("entityId", "==", params.entityId);
|
|
9898
|
+
}
|
|
9899
|
+
const snap = await query.get();
|
|
9900
|
+
return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
|
|
9901
|
+
});
|
|
9902
|
+
register("graph.upsertBindings", async (_uid, params) => {
|
|
9903
|
+
const col = graphCol(params.productId, "bindings");
|
|
9904
|
+
const batch = admin17.firestore().batch();
|
|
9905
|
+
if (params.deleteIds?.length) {
|
|
9906
|
+
for (const id of params.deleteIds) {
|
|
9907
|
+
batch.delete(col.doc(id));
|
|
9908
|
+
}
|
|
9909
|
+
}
|
|
9910
|
+
if (params.bindings?.length) {
|
|
9911
|
+
for (const binding of params.bindings) {
|
|
9912
|
+
const id = binding.id || col.doc().id;
|
|
9913
|
+
batch.set(col.doc(id), binding, { merge: true });
|
|
9914
|
+
}
|
|
9915
|
+
}
|
|
9916
|
+
await batch.commit();
|
|
9917
|
+
return { ok: true };
|
|
9918
|
+
});
|
|
9919
|
+
register("graph.getNodes", async (_uid, params) => {
|
|
9920
|
+
const col = graphCol(params.productId, "nodes");
|
|
9921
|
+
let query = col;
|
|
9922
|
+
if (params.categories?.length) {
|
|
9923
|
+
query = col.where("category", "in", params.categories);
|
|
9924
|
+
}
|
|
9925
|
+
if (params.sourceType) {
|
|
9926
|
+
query = col.where("source_type", "==", params.sourceType);
|
|
9927
|
+
}
|
|
9928
|
+
if (params.light) {
|
|
9929
|
+
query = query.select("id", "category", "title", "severity", "source_type", "tags");
|
|
9930
|
+
}
|
|
9931
|
+
const snap = await query.get();
|
|
9932
|
+
return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
|
|
9933
|
+
});
|
|
9934
|
+
register("graph.upsertNodes", async (_uid, params) => {
|
|
9935
|
+
const col = graphCol(params.productId, "nodes");
|
|
9936
|
+
const batch = admin17.firestore().batch();
|
|
9937
|
+
if (params.deleteIds?.length) {
|
|
9938
|
+
for (const id of params.deleteIds) {
|
|
9939
|
+
batch.delete(col.doc(id));
|
|
9940
|
+
}
|
|
9941
|
+
}
|
|
9942
|
+
if (params.nodes?.length) {
|
|
9943
|
+
for (const node of params.nodes) {
|
|
9944
|
+
const id = node.id || col.doc().id;
|
|
9945
|
+
batch.set(col.doc(id), node);
|
|
9946
|
+
}
|
|
9947
|
+
}
|
|
9948
|
+
await batch.commit();
|
|
9949
|
+
return { ok: true };
|
|
9950
|
+
});
|
|
9951
|
+
register("graph.getTestCases", async (_uid, params) => {
|
|
9952
|
+
const col = graphCol(params.productId, "test_cases");
|
|
9953
|
+
let query = col;
|
|
9954
|
+
if (params.entityId) {
|
|
9955
|
+
query = col.where("entityId", "==", params.entityId);
|
|
9956
|
+
}
|
|
9957
|
+
const snap = await query.get();
|
|
9958
|
+
return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
|
|
9959
|
+
});
|
|
9960
|
+
register("graph.addTestCases", async (_uid, params) => {
|
|
9961
|
+
const col = graphCol(params.productId, "test_cases");
|
|
9962
|
+
const batch = admin17.firestore().batch();
|
|
9963
|
+
for (const tc of params.testCases || []) {
|
|
9964
|
+
const id = tc.id || col.doc().id;
|
|
9965
|
+
batch.set(col.doc(id), tc, { merge: true });
|
|
9966
|
+
}
|
|
9967
|
+
await batch.commit();
|
|
9968
|
+
return { ok: true };
|
|
9969
|
+
});
|
|
9970
|
+
register("graph.getMeta", async (_uid, params) => {
|
|
9971
|
+
const doc = await admin17.firestore().collection("context_graph").doc(params.productId).collection("_meta").doc("graph").get();
|
|
9972
|
+
return { doc: doc.exists ? { id: doc.id, ...doc.data() } : null };
|
|
9973
|
+
});
|
|
9974
|
+
register("graph.updateMeta", async (_uid, params) => {
|
|
9975
|
+
const ref = admin17.firestore().collection("context_graph").doc(params.productId).collection("_meta").doc("graph");
|
|
9976
|
+
await ref.set(params.data, { merge: true });
|
|
9977
|
+
return { ok: true };
|
|
9978
|
+
});
|
|
9979
|
+
register("graph.recordScore", async (_uid, params) => {
|
|
9980
|
+
const db = admin17.firestore();
|
|
9981
|
+
const histRef = db.collection("context_graph").doc(params.productId).collection("score_history").doc(params.snapshotId);
|
|
9982
|
+
await histRef.set(params.snapshot);
|
|
9983
|
+
if (params.jobUpdate) {
|
|
9984
|
+
const jobRef = db.collection("premortem_jobs").doc(params.productId);
|
|
9985
|
+
const jobDoc = await jobRef.get();
|
|
9986
|
+
if (jobDoc.exists) {
|
|
9987
|
+
await jobRef.update(params.jobUpdate);
|
|
9988
|
+
}
|
|
9989
|
+
}
|
|
9990
|
+
return { ok: true };
|
|
9991
|
+
});
|
|
9992
|
+
register("graph.deleteAll", async (_uid, params) => {
|
|
9993
|
+
const db = admin17.firestore();
|
|
9994
|
+
const subs = ["entities", "edges", "bindings", "test_cases", "nodes"];
|
|
9995
|
+
for (const sub of subs) {
|
|
9996
|
+
const snap = await db.collection("context_graph").doc(params.productId).collection(sub).get();
|
|
9997
|
+
if (!snap.empty) {
|
|
9998
|
+
const batch = db.batch();
|
|
9999
|
+
snap.docs.forEach((d) => batch.delete(d.ref));
|
|
10000
|
+
await batch.commit();
|
|
10001
|
+
}
|
|
10002
|
+
}
|
|
10003
|
+
return { ok: true };
|
|
10004
|
+
});
|
|
10005
|
+
register("graph.hasConstraints", async (_uid, params) => {
|
|
10006
|
+
const snap = await graphCol(params.productId, "nodes").limit(1).get();
|
|
10007
|
+
return { hasConstraints: !snap.empty };
|
|
10008
|
+
});
|
|
10009
|
+
register("graph.updateEmbedding", async (_uid, params) => {
|
|
10010
|
+
const ref = graphCol(params.productId, params.collection || "entities").doc(params.docId);
|
|
10011
|
+
await ref.update({ embedding: params.embedding });
|
|
10012
|
+
return { ok: true };
|
|
10013
|
+
});
|
|
10014
|
+
register("template.list", async (uid, params) => {
|
|
10015
|
+
const db = admin17.firestore();
|
|
10016
|
+
let query = db.collection("templates").where("uid", "==", uid);
|
|
10017
|
+
if (params.type) {
|
|
10018
|
+
query = query.where("type", "==", params.type);
|
|
10019
|
+
}
|
|
10020
|
+
const snap = await query.get();
|
|
10021
|
+
return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
|
|
10022
|
+
});
|
|
10023
|
+
register("template.get", async (uid, params) => {
|
|
10024
|
+
const db = admin17.firestore();
|
|
10025
|
+
const doc = await db.collection("templates").doc(params.id).get();
|
|
10026
|
+
if (!doc.exists)
|
|
10027
|
+
return { doc: null };
|
|
10028
|
+
const data = doc.data();
|
|
10029
|
+
if (data?.uid !== uid)
|
|
10030
|
+
return { doc: null };
|
|
10031
|
+
return { doc: { id: doc.id, ...data } };
|
|
10032
|
+
});
|
|
10033
|
+
register("template.create", async (uid, params) => {
|
|
10034
|
+
const db = admin17.firestore();
|
|
10035
|
+
const id = params.id || db.collection("templates").doc().id;
|
|
10036
|
+
const ref = db.collection("templates").doc(id);
|
|
10037
|
+
await ref.set({ ...params.data, uid, createdAt: admin17.firestore.FieldValue.serverTimestamp() });
|
|
10038
|
+
return { id: ref.id };
|
|
10039
|
+
});
|
|
10040
|
+
register("template.update", async (uid, params) => {
|
|
10041
|
+
const db = admin17.firestore();
|
|
10042
|
+
const ref = db.collection("templates").doc(params.id);
|
|
10043
|
+
const doc = await ref.get();
|
|
10044
|
+
if (!doc.exists || doc.data()?.uid !== uid) {
|
|
10045
|
+
throw new Error("Not found or not authorized");
|
|
10046
|
+
}
|
|
10047
|
+
await ref.update(params.data);
|
|
10048
|
+
return { ok: true };
|
|
10049
|
+
});
|
|
10050
|
+
register("scan.save", async (uid, params) => {
|
|
10051
|
+
const db = admin17.firestore();
|
|
10052
|
+
const collection = params.collection || "scan_reports";
|
|
10053
|
+
const id = params.id || db.collection(collection).doc().id;
|
|
10054
|
+
const ref = db.collection(collection).doc(id);
|
|
10055
|
+
await ref.set({ ...params.data, uid, createdAt: admin17.firestore.FieldValue.serverTimestamp() });
|
|
10056
|
+
return { id: ref.id };
|
|
10057
|
+
});
|
|
10058
|
+
register("scan.rateCheck", async (uid, _params) => {
|
|
10059
|
+
const db = admin17.firestore();
|
|
10060
|
+
const ref = db.collection("users").doc(uid);
|
|
10061
|
+
const doc = await ref.get();
|
|
10062
|
+
if (!doc.exists) {
|
|
10063
|
+
return { scanCount: 0, periodStart: null };
|
|
10064
|
+
}
|
|
10065
|
+
const data = doc.data();
|
|
10066
|
+
return {
|
|
10067
|
+
scanCount: data?.freeScanCount ?? 0,
|
|
10068
|
+
periodStart: data?.freeScanPeriodStart?.toDate?.()?.toISOString() ?? null,
|
|
10069
|
+
subscription: data?.subscription?.status ?? "free"
|
|
10070
|
+
};
|
|
10071
|
+
});
|
|
10072
|
+
register("scan.rateUpdate", async (uid, params) => {
|
|
10073
|
+
const db = admin17.firestore();
|
|
10074
|
+
const ref = db.collection("users").doc(uid);
|
|
10075
|
+
await ref.set(params.data, { merge: true });
|
|
10076
|
+
return { ok: true };
|
|
10077
|
+
});
|
|
10078
|
+
register("readiness.get", async (_uid, params) => {
|
|
10079
|
+
const db = admin17.firestore();
|
|
10080
|
+
const doc = await db.collection("readiness_reports").doc(params.id).get();
|
|
10081
|
+
return { doc: doc.exists ? { id: doc.id, ...doc.data() } : null };
|
|
10082
|
+
});
|
|
10083
|
+
register("readiness.save", async (_uid, params) => {
|
|
10084
|
+
const db = admin17.firestore();
|
|
10085
|
+
const ref = db.collection("readiness_reports").doc(params.id);
|
|
10086
|
+
await ref.set(params.data);
|
|
10087
|
+
return { ok: true };
|
|
10088
|
+
});
|
|
10089
|
+
register("persona.list", async (uid, params) => {
|
|
10090
|
+
const db = admin17.firestore();
|
|
10091
|
+
let query = db.collection("users").doc(uid).collection("personas");
|
|
10092
|
+
if (params.productId) {
|
|
10093
|
+
query = query.where("productId", "==", params.productId);
|
|
10094
|
+
}
|
|
10095
|
+
const snap = await query.orderBy("createdAt", "desc").get();
|
|
10096
|
+
return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
|
|
10097
|
+
});
|
|
10098
|
+
register("persona.get", async (uid, params) => {
|
|
10099
|
+
const db = admin17.firestore();
|
|
10100
|
+
const doc = await db.collection("users").doc(uid).collection("personas").doc(params.id).get();
|
|
10101
|
+
if (!doc.exists)
|
|
10102
|
+
return { doc: null };
|
|
10103
|
+
return { doc: { id: doc.id, ...doc.data() } };
|
|
10104
|
+
});
|
|
10105
|
+
var mcpDataProxy = onRequest20({
|
|
10106
|
+
timeoutSeconds: 60,
|
|
10107
|
+
memory: "256MiB",
|
|
10108
|
+
cors: true
|
|
10109
|
+
}, async (req, res) => {
|
|
10110
|
+
ensureFirebaseAdmin();
|
|
10111
|
+
if (req.method === "OPTIONS") {
|
|
10112
|
+
res.status(204).send("");
|
|
10113
|
+
return;
|
|
10114
|
+
}
|
|
10115
|
+
if (req.method !== "POST") {
|
|
10116
|
+
res.status(405).json({ error: "Method not allowed" });
|
|
10117
|
+
return;
|
|
10118
|
+
}
|
|
10119
|
+
const authHeader = req.headers.authorization;
|
|
10120
|
+
if (!authHeader?.startsWith("Bearer ")) {
|
|
10121
|
+
res.status(401).json({ error: "Missing or invalid Authorization header" });
|
|
10122
|
+
return;
|
|
10123
|
+
}
|
|
10124
|
+
let decoded;
|
|
10125
|
+
try {
|
|
10126
|
+
decoded = await admin17.auth().verifyIdToken(authHeader.slice(7));
|
|
10127
|
+
} catch (error6) {
|
|
10128
|
+
if (error6.code === "auth/id-token-expired") {
|
|
10129
|
+
res.status(401).json({ error: "Token expired" });
|
|
10130
|
+
return;
|
|
10131
|
+
}
|
|
10132
|
+
res.status(401).json({ error: "Invalid token" });
|
|
10133
|
+
return;
|
|
10134
|
+
}
|
|
10135
|
+
const uid = decoded.uid;
|
|
10136
|
+
const { action, params } = req.body || {};
|
|
10137
|
+
if (!action || typeof action !== "string") {
|
|
10138
|
+
res.status(400).json({ error: "Missing action" });
|
|
10139
|
+
return;
|
|
10140
|
+
}
|
|
10141
|
+
const handler = handlers[action];
|
|
10142
|
+
if (!handler) {
|
|
10143
|
+
res.status(400).json({ error: `Unknown action: ${action}` });
|
|
10144
|
+
return;
|
|
10145
|
+
}
|
|
10146
|
+
try {
|
|
10147
|
+
const result = await handler(uid, params || {});
|
|
10148
|
+
res.json(result);
|
|
10149
|
+
} catch (error6) {
|
|
10150
|
+
logger4.error(`mcpDataProxy action=${action} error`, { uid, error: error6.message });
|
|
10151
|
+
res.status(error6.message?.includes("not authorized") ? 403 : 500).json({ error: error6.message || "Internal error" });
|
|
10152
|
+
}
|
|
10153
|
+
});
|
|
10154
|
+
|
|
9733
10155
|
// ../lib/subscription/cancel-scheduled.js
|
|
9734
10156
|
import { onSchedule } from "firebase-functions/v2/scheduler";
|
|
9735
10157
|
import Stripe2 from "stripe";
|
|
9736
|
-
import
|
|
9737
|
-
import { logger as
|
|
10158
|
+
import admin18 from "firebase-admin";
|
|
10159
|
+
import { logger as logger5 } from "firebase-functions";
|
|
9738
10160
|
ensureFirebaseAdmin();
|
|
9739
10161
|
function getStripeInstance() {
|
|
9740
10162
|
const secretKey = process.env.STRIPE_SECRET_KEY;
|
|
@@ -9746,7 +10168,7 @@ function getStripeInstance() {
|
|
|
9746
10168
|
});
|
|
9747
10169
|
}
|
|
9748
10170
|
function getUsersCollection() {
|
|
9749
|
-
return
|
|
10171
|
+
return admin18.firestore().collection("users");
|
|
9750
10172
|
}
|
|
9751
10173
|
var cancelScheduledSubscriptions = onSchedule({
|
|
9752
10174
|
schedule: "every day 00:00",
|
|
@@ -9756,20 +10178,20 @@ var cancelScheduledSubscriptions = onSchedule({
|
|
|
9756
10178
|
timeoutSeconds: 540
|
|
9757
10179
|
}, async (event) => {
|
|
9758
10180
|
try {
|
|
9759
|
-
|
|
10181
|
+
logger5.info("[cancel-scheduled-subscriptions] Starting scheduled cancellation check");
|
|
9760
10182
|
const stripe = getStripeInstance();
|
|
9761
10183
|
const users = getUsersCollection();
|
|
9762
10184
|
const now = /* @__PURE__ */ new Date();
|
|
9763
10185
|
const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
9764
10186
|
const todayISO = today.toISOString();
|
|
9765
|
-
|
|
10187
|
+
logger5.info(`[cancel-scheduled-subscriptions] Checking for cancellations on or before ${todayISO}`);
|
|
9766
10188
|
const allUsersWithCancellation = await users.where("subscriptionCancellationDate", "<=", todayISO).get();
|
|
9767
|
-
|
|
10189
|
+
logger5.info(`[cancel-scheduled-subscriptions] Found ${allUsersWithCancellation.docs.length} users with cancellation dates <= ${todayISO}`);
|
|
9768
10190
|
const usersToCancel = allUsersWithCancellation.docs.filter((doc) => {
|
|
9769
10191
|
const data = doc.data();
|
|
9770
10192
|
return data?.subscription?.id;
|
|
9771
10193
|
});
|
|
9772
|
-
|
|
10194
|
+
logger5.info(`[cancel-scheduled-subscriptions] Found ${usersToCancel.length} subscriptions to cancel`);
|
|
9773
10195
|
let successCount = 0;
|
|
9774
10196
|
let errorCount = 0;
|
|
9775
10197
|
for (const userDoc of usersToCancel) {
|
|
@@ -9778,45 +10200,45 @@ var cancelScheduledSubscriptions = onSchedule({
|
|
|
9778
10200
|
const subscriptionId = subscription?.id;
|
|
9779
10201
|
const cancellationDate = userData?.subscriptionCancellationDate;
|
|
9780
10202
|
if (!subscriptionId) {
|
|
9781
|
-
|
|
10203
|
+
logger5.warn(`[cancel-scheduled-subscriptions] User ${userDoc.id} has cancellation date but no subscription ID`);
|
|
9782
10204
|
continue;
|
|
9783
10205
|
}
|
|
9784
10206
|
try {
|
|
9785
10207
|
await stripe.subscriptions.cancel(subscriptionId);
|
|
9786
|
-
|
|
10208
|
+
logger5.info(`[cancel-scheduled-subscriptions] Cancelled Stripe subscription ${subscriptionId} for user ${userDoc.id}`);
|
|
9787
10209
|
await users.doc(userDoc.id).set({
|
|
9788
|
-
subscription:
|
|
9789
|
-
subscriptionCancellationDate:
|
|
9790
|
-
subscriptionUpdatedAt:
|
|
10210
|
+
subscription: admin18.firestore.FieldValue.delete(),
|
|
10211
|
+
subscriptionCancellationDate: admin18.firestore.FieldValue.delete(),
|
|
10212
|
+
subscriptionUpdatedAt: admin18.firestore.FieldValue.serverTimestamp()
|
|
9791
10213
|
}, { merge: true });
|
|
9792
|
-
|
|
10214
|
+
logger5.info(`[cancel-scheduled-subscriptions] Removed subscription from Firestore for user ${userDoc.id}`);
|
|
9793
10215
|
successCount++;
|
|
9794
|
-
} catch (
|
|
9795
|
-
|
|
10216
|
+
} catch (error6) {
|
|
10217
|
+
logger5.error({
|
|
9796
10218
|
userId: userDoc.id,
|
|
9797
10219
|
subscriptionId,
|
|
9798
10220
|
cancellationDate,
|
|
9799
|
-
error:
|
|
10221
|
+
error: error6?.message
|
|
9800
10222
|
}, `[cancel-scheduled-subscriptions] Failed to cancel subscription for user ${userDoc.id}`);
|
|
9801
10223
|
errorCount++;
|
|
9802
10224
|
}
|
|
9803
10225
|
}
|
|
9804
|
-
|
|
10226
|
+
logger5.info({
|
|
9805
10227
|
total: usersToCancel.length,
|
|
9806
10228
|
success: successCount,
|
|
9807
10229
|
errors: errorCount
|
|
9808
10230
|
}, "[cancel-scheduled-subscriptions] Completed scheduled cancellation check");
|
|
9809
|
-
} catch (
|
|
9810
|
-
|
|
9811
|
-
throw
|
|
10231
|
+
} catch (error6) {
|
|
10232
|
+
logger5.error({ error: error6?.message, stack: error6?.stack }, "[cancel-scheduled-subscriptions] Fatal error in scheduled function");
|
|
10233
|
+
throw error6;
|
|
9812
10234
|
}
|
|
9813
10235
|
});
|
|
9814
10236
|
|
|
9815
10237
|
// ../lib/personas/cancel-scheduled.js
|
|
9816
10238
|
import { onSchedule as onSchedule2 } from "firebase-functions/v2/scheduler";
|
|
9817
10239
|
import Stripe3 from "stripe";
|
|
9818
|
-
import
|
|
9819
|
-
import { logger as
|
|
10240
|
+
import admin19 from "firebase-admin";
|
|
10241
|
+
import { logger as logger6 } from "firebase-functions";
|
|
9820
10242
|
ensureFirebaseAdmin();
|
|
9821
10243
|
function getStripeInstance2() {
|
|
9822
10244
|
const secretKey = process.env.STRIPE_SECRET_KEY;
|
|
@@ -9828,7 +10250,7 @@ function getStripeInstance2() {
|
|
|
9828
10250
|
});
|
|
9829
10251
|
}
|
|
9830
10252
|
function getUsersCollection2() {
|
|
9831
|
-
return
|
|
10253
|
+
return admin19.firestore().collection("users");
|
|
9832
10254
|
}
|
|
9833
10255
|
var cancelScheduledPersonas = onSchedule2({
|
|
9834
10256
|
schedule: "every day 00:00",
|
|
@@ -9838,7 +10260,7 @@ var cancelScheduledPersonas = onSchedule2({
|
|
|
9838
10260
|
timeoutSeconds: 540
|
|
9839
10261
|
}, async (event) => {
|
|
9840
10262
|
try {
|
|
9841
|
-
|
|
10263
|
+
logger6.info("[cancel-scheduled-personas] Starting scheduled persona cancellation check");
|
|
9842
10264
|
const stripe = getStripeInstance2();
|
|
9843
10265
|
const users = getUsersCollection2();
|
|
9844
10266
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -9856,7 +10278,7 @@ var cancelScheduledPersonas = onSchedule2({
|
|
|
9856
10278
|
const cancellationDate = data?.lifecycle?.cancellation_date;
|
|
9857
10279
|
if (!cancellationDate)
|
|
9858
10280
|
return false;
|
|
9859
|
-
const cancelDate = cancellationDate instanceof
|
|
10281
|
+
const cancelDate = cancellationDate instanceof admin19.firestore.Timestamp ? cancellationDate.toDate() : new Date(cancellationDate);
|
|
9860
10282
|
return cancelDate <= today;
|
|
9861
10283
|
});
|
|
9862
10284
|
totalPersonasToCancel += personasWithCancellation.length;
|
|
@@ -9876,43 +10298,43 @@ var cancelScheduledPersonas = onSchedule2({
|
|
|
9876
10298
|
const subscription = subscriptions.data.find((sub) => sub.items.data.some((item) => item.id === subscriptionItemId));
|
|
9877
10299
|
if (subscription && !subscription.cancel_at_period_end) {
|
|
9878
10300
|
await stripe.subscriptions.cancel(subscription.id);
|
|
9879
|
-
|
|
10301
|
+
logger6.info(`[cancel-scheduled-personas] Cancelled Stripe subscription ${subscription.id} for persona ${personaId} (user ${userId})`);
|
|
9880
10302
|
}
|
|
9881
10303
|
}
|
|
9882
10304
|
}
|
|
9883
10305
|
await personasRef.doc(personaId).set({
|
|
9884
10306
|
"lifecycle.status": "archived",
|
|
9885
|
-
"lifecycle.cancellation_date":
|
|
9886
|
-
updatedAt:
|
|
10307
|
+
"lifecycle.cancellation_date": admin19.firestore.FieldValue.delete(),
|
|
10308
|
+
updatedAt: admin19.firestore.FieldValue.serverTimestamp()
|
|
9887
10309
|
}, { merge: true });
|
|
9888
|
-
|
|
10310
|
+
logger6.info(`[cancel-scheduled-personas] Archived persona ${personaId} for user ${userId}`);
|
|
9889
10311
|
successCount++;
|
|
9890
|
-
} catch (
|
|
9891
|
-
|
|
10312
|
+
} catch (error6) {
|
|
10313
|
+
logger6.error({
|
|
9892
10314
|
userId,
|
|
9893
10315
|
personaId,
|
|
9894
10316
|
subscriptionItemId,
|
|
9895
|
-
error:
|
|
10317
|
+
error: error6?.message
|
|
9896
10318
|
}, `[cancel-scheduled-personas] Failed to cancel persona ${personaId} for user ${userId}`);
|
|
9897
10319
|
errorCount++;
|
|
9898
10320
|
}
|
|
9899
10321
|
}
|
|
9900
10322
|
}
|
|
9901
|
-
|
|
10323
|
+
logger6.info({
|
|
9902
10324
|
total: totalPersonasToCancel,
|
|
9903
10325
|
success: successCount,
|
|
9904
10326
|
errors: errorCount
|
|
9905
10327
|
}, "[cancel-scheduled-personas] Completed scheduled persona cancellation check");
|
|
9906
|
-
} catch (
|
|
9907
|
-
|
|
9908
|
-
throw
|
|
10328
|
+
} catch (error6) {
|
|
10329
|
+
logger6.error({ error: error6?.message, stack: error6?.stack }, "[cancel-scheduled-personas] Fatal error in scheduled function");
|
|
10330
|
+
throw error6;
|
|
9909
10331
|
}
|
|
9910
10332
|
});
|
|
9911
10333
|
|
|
9912
10334
|
// ../lib/trial/expire-trials.js
|
|
9913
10335
|
import { onSchedule as onSchedule3 } from "firebase-functions/v2/scheduler";
|
|
9914
|
-
import
|
|
9915
|
-
import { logger as
|
|
10336
|
+
import admin20 from "firebase-admin";
|
|
10337
|
+
import { logger as logger7 } from "firebase-functions";
|
|
9916
10338
|
ensureFirebaseAdmin();
|
|
9917
10339
|
function getTrialConfig() {
|
|
9918
10340
|
const isProduction = process.env.GCLOUD_PROJECT === "cutline-prod" || process.env.K_SERVICE?.includes("prod");
|
|
@@ -9955,18 +10377,18 @@ var expireTrials = onSchedule3({
|
|
|
9955
10377
|
// Reduced since it runs frequently now
|
|
9956
10378
|
}, async (event) => {
|
|
9957
10379
|
const config = getTrialConfig();
|
|
9958
|
-
|
|
10380
|
+
logger7.info({
|
|
9959
10381
|
trialDuration: config.durationLabel,
|
|
9960
10382
|
schedule: scheduleConfig.scheduleLabel,
|
|
9961
10383
|
checkTime: (/* @__PURE__ */ new Date()).toISOString()
|
|
9962
10384
|
}, "[expire-trials] Starting trial expiration check");
|
|
9963
10385
|
try {
|
|
9964
|
-
const db =
|
|
10386
|
+
const db = admin20.firestore();
|
|
9965
10387
|
const users = db.collection("users");
|
|
9966
10388
|
const now = Date.now();
|
|
9967
10389
|
const expirationThreshold = now - config.durationMs;
|
|
9968
10390
|
const expiredTrials = await users.where("trialStatus", "==", "active").where("trialStartedAt", "<=", new Date(expirationThreshold)).get();
|
|
9969
|
-
|
|
10391
|
+
logger7.info({
|
|
9970
10392
|
foundCount: expiredTrials.docs.length,
|
|
9971
10393
|
expirationThreshold: new Date(expirationThreshold).toISOString()
|
|
9972
10394
|
}, "[expire-trials] Found trials to expire");
|
|
@@ -9976,36 +10398,36 @@ var expireTrials = onSchedule3({
|
|
|
9976
10398
|
try {
|
|
9977
10399
|
await users.doc(userDoc.id).update({
|
|
9978
10400
|
trialStatus: "expired",
|
|
9979
|
-
trialExpiredAt:
|
|
10401
|
+
trialExpiredAt: admin20.firestore.FieldValue.serverTimestamp()
|
|
9980
10402
|
});
|
|
9981
|
-
|
|
10403
|
+
logger7.info({ userId: userDoc.id }, "[expire-trials] Expired trial for user");
|
|
9982
10404
|
successCount++;
|
|
9983
|
-
} catch (
|
|
9984
|
-
|
|
10405
|
+
} catch (error6) {
|
|
10406
|
+
logger7.error({
|
|
9985
10407
|
userId: userDoc.id,
|
|
9986
|
-
error:
|
|
10408
|
+
error: error6?.message
|
|
9987
10409
|
}, "[expire-trials] Failed to expire trial");
|
|
9988
10410
|
errorCount++;
|
|
9989
10411
|
}
|
|
9990
10412
|
}
|
|
9991
|
-
|
|
10413
|
+
logger7.info({
|
|
9992
10414
|
total: expiredTrials.docs.length,
|
|
9993
10415
|
success: successCount,
|
|
9994
10416
|
errors: errorCount,
|
|
9995
10417
|
trialDuration: config.durationLabel
|
|
9996
10418
|
}, "[expire-trials] Completed trial expiration check");
|
|
9997
|
-
} catch (
|
|
9998
|
-
|
|
9999
|
-
error:
|
|
10000
|
-
stack:
|
|
10419
|
+
} catch (error6) {
|
|
10420
|
+
logger7.error({
|
|
10421
|
+
error: error6?.message,
|
|
10422
|
+
stack: error6?.stack
|
|
10001
10423
|
}, "[expire-trials] Fatal error in scheduled function");
|
|
10002
|
-
throw
|
|
10424
|
+
throw error6;
|
|
10003
10425
|
}
|
|
10004
10426
|
});
|
|
10005
10427
|
|
|
10006
10428
|
// ../lib/persona-testing/trigger.js
|
|
10007
10429
|
import { onDocumentCreated as onDocumentCreated2 } from "firebase-functions/v2/firestore";
|
|
10008
|
-
import * as
|
|
10430
|
+
import * as logger8 from "firebase-functions/logger";
|
|
10009
10431
|
import { getFirestore as getFirestore2, FieldValue } from "firebase-admin/firestore";
|
|
10010
10432
|
function getPersonaTesterUrl() {
|
|
10011
10433
|
const url = process.env.PERSONA_TESTER_URL;
|
|
@@ -10017,24 +10439,24 @@ function getPersonaTesterUrl() {
|
|
|
10017
10439
|
var onPersonaTestCreated = onDocumentCreated2("users/{userId}/personas/{personaId}/tests/{testId}", async (event) => {
|
|
10018
10440
|
const snap = event.data;
|
|
10019
10441
|
if (!snap) {
|
|
10020
|
-
|
|
10442
|
+
logger8.error("[PersonaTest] No data in event");
|
|
10021
10443
|
return;
|
|
10022
10444
|
}
|
|
10023
10445
|
const { userId, personaId, testId } = event.params;
|
|
10024
10446
|
const testData = snap.data();
|
|
10025
|
-
|
|
10447
|
+
logger8.info(`[PersonaTest] New test created: ${testId}`, {
|
|
10026
10448
|
userId,
|
|
10027
10449
|
personaId,
|
|
10028
10450
|
testId,
|
|
10029
10451
|
status: testData.status
|
|
10030
10452
|
});
|
|
10031
10453
|
if (testData.status !== "queued") {
|
|
10032
|
-
|
|
10454
|
+
logger8.info(`[PersonaTest] Skipping test ${testId} - status is ${testData.status}`);
|
|
10033
10455
|
return;
|
|
10034
10456
|
}
|
|
10035
10457
|
try {
|
|
10036
10458
|
const personaTesterUrl = getPersonaTesterUrl();
|
|
10037
|
-
|
|
10459
|
+
logger8.info(`[PersonaTest] Calling Cloud Run service for test ${testId}`, { url: personaTesterUrl });
|
|
10038
10460
|
const response = await fetch(`${personaTesterUrl}/execute`, {
|
|
10039
10461
|
method: "POST",
|
|
10040
10462
|
headers: {
|
|
@@ -10051,10 +10473,10 @@ var onPersonaTestCreated = onDocumentCreated2("users/{userId}/personas/{personaI
|
|
|
10051
10473
|
throw new Error(`Cloud Run service returned ${response.status}: ${errorText}`);
|
|
10052
10474
|
}
|
|
10053
10475
|
const result = await response.json();
|
|
10054
|
-
|
|
10055
|
-
} catch (
|
|
10056
|
-
const err =
|
|
10057
|
-
|
|
10476
|
+
logger8.info(`[PersonaTest] Test ${testId} execution started`, result);
|
|
10477
|
+
} catch (error6) {
|
|
10478
|
+
const err = error6;
|
|
10479
|
+
logger8.error(`[PersonaTest] Failed to trigger test ${testId}:`, err);
|
|
10058
10480
|
const firestore = getFirestore2();
|
|
10059
10481
|
await firestore.collection("users").doc(userId).collection("personas").doc(personaId).collection("tests").doc(testId).update({
|
|
10060
10482
|
status: "failed",
|