@gonzih/meet-the-one-ai 1.0.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.
Files changed (175) hide show
  1. package/.env.example +41 -0
  2. package/.node-version +1 -0
  3. package/basis/BERNAYS.md +233 -0
  4. package/basis/FOUNDING_TRANSCRIPT.md +218 -0
  5. package/basis/TECH_SPEC.md +303 -0
  6. package/basis/VALS.md +255 -0
  7. package/basis/layers/L1_IDENTITY_AUTH.md +78 -0
  8. package/basis/layers/L2_CONVERSATION.md +159 -0
  9. package/basis/layers/L3_RECORDING_STORE.md +104 -0
  10. package/basis/layers/L4_ANALYSIS_PIPELINE.md +257 -0
  11. package/basis/layers/L5_MATCHING_ENGINE.md +164 -0
  12. package/basis/layers/L6_CONSENT_INTRODUCTION.md +143 -0
  13. package/basis/layers/L7_PORTABLE_IDENTITY.md +139 -0
  14. package/basis/layers/STACK.md +64 -0
  15. package/basis/schema.sql +203 -0
  16. package/dist/agent.d.ts +2 -0
  17. package/dist/agent.d.ts.map +1 -0
  18. package/dist/agent.js +114 -0
  19. package/dist/agent.js.map +1 -0
  20. package/dist/api/routes/auth.d.ts +2 -0
  21. package/dist/api/routes/auth.d.ts.map +1 -0
  22. package/dist/api/routes/auth.js +79 -0
  23. package/dist/api/routes/auth.js.map +1 -0
  24. package/dist/api/routes/identity.d.ts +2 -0
  25. package/dist/api/routes/identity.d.ts.map +1 -0
  26. package/dist/api/routes/identity.js +92 -0
  27. package/dist/api/routes/identity.js.map +1 -0
  28. package/dist/api/routes/text-submission.d.ts +2 -0
  29. package/dist/api/routes/text-submission.d.ts.map +1 -0
  30. package/dist/api/routes/text-submission.js +56 -0
  31. package/dist/api/routes/text-submission.js.map +1 -0
  32. package/dist/api/webhooks/twilio.d.ts +2 -0
  33. package/dist/api/webhooks/twilio.d.ts.map +1 -0
  34. package/dist/api/webhooks/twilio.js +144 -0
  35. package/dist/api/webhooks/twilio.js.map +1 -0
  36. package/dist/api/webhooks/vapi.d.ts +2 -0
  37. package/dist/api/webhooks/vapi.d.ts.map +1 -0
  38. package/dist/api/webhooks/vapi.js +177 -0
  39. package/dist/api/webhooks/vapi.js.map +1 -0
  40. package/dist/bot.d.ts +3 -0
  41. package/dist/bot.d.ts.map +1 -0
  42. package/dist/bot.js +39 -0
  43. package/dist/bot.js.map +1 -0
  44. package/dist/index.d.ts +2 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +9 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/jobs/compact-identity.d.ts +2 -0
  49. package/dist/jobs/compact-identity.d.ts.map +1 -0
  50. package/dist/jobs/compact-identity.js +159 -0
  51. package/dist/jobs/compact-identity.js.map +1 -0
  52. package/dist/jobs/consent-call.d.ts +2 -0
  53. package/dist/jobs/consent-call.d.ts.map +1 -0
  54. package/dist/jobs/consent-call.js +70 -0
  55. package/dist/jobs/consent-call.js.map +1 -0
  56. package/dist/jobs/export-identity.d.ts +2 -0
  57. package/dist/jobs/export-identity.d.ts.map +1 -0
  58. package/dist/jobs/export-identity.js +129 -0
  59. package/dist/jobs/export-identity.js.map +1 -0
  60. package/dist/jobs/introduction-call.d.ts +2 -0
  61. package/dist/jobs/introduction-call.d.ts.map +1 -0
  62. package/dist/jobs/introduction-call.js +86 -0
  63. package/dist/jobs/introduction-call.js.map +1 -0
  64. package/dist/jobs/reanalyze-identity.d.ts +2 -0
  65. package/dist/jobs/reanalyze-identity.d.ts.map +1 -0
  66. package/dist/jobs/reanalyze-identity.js +56 -0
  67. package/dist/jobs/reanalyze-identity.js.map +1 -0
  68. package/dist/jobs/run-matching.d.ts +2 -0
  69. package/dist/jobs/run-matching.d.ts.map +1 -0
  70. package/dist/jobs/run-matching.js +200 -0
  71. package/dist/jobs/run-matching.js.map +1 -0
  72. package/dist/jobs/scheduled-matching.d.ts +2 -0
  73. package/dist/jobs/scheduled-matching.d.ts.map +1 -0
  74. package/dist/jobs/scheduled-matching.js +44 -0
  75. package/dist/jobs/scheduled-matching.js.map +1 -0
  76. package/dist/jobs/transcribe-session.d.ts +2 -0
  77. package/dist/jobs/transcribe-session.d.ts.map +1 -0
  78. package/dist/jobs/transcribe-session.js +66 -0
  79. package/dist/jobs/transcribe-session.js.map +1 -0
  80. package/dist/lib/anthropic.d.ts +4 -0
  81. package/dist/lib/anthropic.d.ts.map +1 -0
  82. package/dist/lib/anthropic.js +32 -0
  83. package/dist/lib/anthropic.js.map +1 -0
  84. package/dist/lib/config.d.ts +57 -0
  85. package/dist/lib/config.d.ts.map +1 -0
  86. package/dist/lib/config.js +73 -0
  87. package/dist/lib/config.js.map +1 -0
  88. package/dist/lib/deepgram.d.ts +15 -0
  89. package/dist/lib/deepgram.d.ts.map +1 -0
  90. package/dist/lib/deepgram.js +37 -0
  91. package/dist/lib/deepgram.js.map +1 -0
  92. package/dist/lib/inngest.d.ts +42 -0
  93. package/dist/lib/inngest.d.ts.map +1 -0
  94. package/dist/lib/inngest.js +7 -0
  95. package/dist/lib/inngest.js.map +1 -0
  96. package/dist/lib/openai.d.ts +3 -0
  97. package/dist/lib/openai.d.ts.map +1 -0
  98. package/dist/lib/openai.js +13 -0
  99. package/dist/lib/openai.js.map +1 -0
  100. package/dist/lib/prompts.d.ts +8 -0
  101. package/dist/lib/prompts.d.ts.map +1 -0
  102. package/dist/lib/prompts.js +258 -0
  103. package/dist/lib/prompts.js.map +1 -0
  104. package/dist/lib/r2.d.ts +7 -0
  105. package/dist/lib/r2.d.ts.map +1 -0
  106. package/dist/lib/r2.js +49 -0
  107. package/dist/lib/r2.js.map +1 -0
  108. package/dist/lib/session-helpers.d.ts +8 -0
  109. package/dist/lib/session-helpers.d.ts.map +1 -0
  110. package/dist/lib/session-helpers.js +31 -0
  111. package/dist/lib/session-helpers.js.map +1 -0
  112. package/dist/lib/supabase.d.ts +2 -0
  113. package/dist/lib/supabase.d.ts.map +1 -0
  114. package/dist/lib/supabase.js +11 -0
  115. package/dist/lib/supabase.js.map +1 -0
  116. package/dist/lib/twilio.d.ts +7 -0
  117. package/dist/lib/twilio.d.ts.map +1 -0
  118. package/dist/lib/twilio.js +34 -0
  119. package/dist/lib/twilio.js.map +1 -0
  120. package/dist/lib/vapi.d.ts +4 -0
  121. package/dist/lib/vapi.d.ts.map +1 -0
  122. package/dist/lib/vapi.js +59 -0
  123. package/dist/lib/vapi.js.map +1 -0
  124. package/dist/mcp-server.d.ts +3 -0
  125. package/dist/mcp-server.d.ts.map +1 -0
  126. package/dist/mcp-server.js +177 -0
  127. package/dist/mcp-server.js.map +1 -0
  128. package/dist/types/index.d.ts +104 -0
  129. package/dist/types/index.d.ts.map +1 -0
  130. package/dist/types/index.js +3 -0
  131. package/dist/types/index.js.map +1 -0
  132. package/package.json +28 -0
  133. package/railway.json +14 -0
  134. package/src/agent.ts +123 -0
  135. package/src/api/routes/auth.ts +95 -0
  136. package/src/api/routes/identity.ts +112 -0
  137. package/src/api/routes/text-submission.ts +64 -0
  138. package/src/api/webhooks/twilio.ts +181 -0
  139. package/src/api/webhooks/vapi.ts +219 -0
  140. package/src/bot.ts +44 -0
  141. package/src/index.ts +11 -0
  142. package/src/jobs/compact-identity.ts +211 -0
  143. package/src/jobs/consent-call.ts +87 -0
  144. package/src/jobs/export-identity.ts +166 -0
  145. package/src/jobs/introduction-call.ts +101 -0
  146. package/src/jobs/reanalyze-identity.ts +65 -0
  147. package/src/jobs/run-matching.ts +243 -0
  148. package/src/jobs/scheduled-matching.ts +59 -0
  149. package/src/jobs/transcribe-session.ts +77 -0
  150. package/src/lib/anthropic.ts +37 -0
  151. package/src/lib/config.ts +81 -0
  152. package/src/lib/deepgram.ts +57 -0
  153. package/src/lib/inngest.ts +33 -0
  154. package/src/lib/openai.ts +14 -0
  155. package/src/lib/prompts.ts +266 -0
  156. package/src/lib/r2.ts +79 -0
  157. package/src/lib/session-helpers.ts +37 -0
  158. package/src/lib/supabase.ts +15 -0
  159. package/src/lib/twilio.ts +49 -0
  160. package/src/lib/vapi.ts +80 -0
  161. package/src/mcp-server.ts +195 -0
  162. package/src/types/index.ts +146 -0
  163. package/supabase/.branches/_current_branch +1 -0
  164. package/supabase/.temp/cli-latest +1 -0
  165. package/supabase/.temp/gotrue-version +1 -0
  166. package/supabase/.temp/pooler-url +1 -0
  167. package/supabase/.temp/postgres-version +1 -0
  168. package/supabase/.temp/project-ref +1 -0
  169. package/supabase/.temp/rest-version +1 -0
  170. package/supabase/.temp/storage-migration +1 -0
  171. package/supabase/.temp/storage-version +1 -0
  172. package/supabase/config.toml +384 -0
  173. package/supabase/migrations/20260303000000_initial_schema.sql +203 -0
  174. package/supabase/migrations/20260304000000_brand_consents.sql +13 -0
  175. package/tsconfig.json +25 -0
@@ -0,0 +1,37 @@
1
+ import { createClient } from "@deepgram/sdk";
2
+ import { config } from "./config.js";
3
+ export const deepgram = createClient(config.deepgram.api_key);
4
+ // Transcribe audio from a URL (e.g. presigned R2 URL)
5
+ export async function transcribe_url(audio_url) {
6
+ const { result, error } = await deepgram.listen.prerecorded.transcribeUrl({ url: audio_url }, {
7
+ model: config.deepgram.model,
8
+ diarize: true, // speaker separation
9
+ punctuate: true,
10
+ utterances: true,
11
+ smart_format: true,
12
+ });
13
+ if (error)
14
+ throw new Error(`Deepgram error: ${error.message}`);
15
+ if (!result)
16
+ throw new Error("No result from Deepgram");
17
+ const channel = result.results.channels[0].alternatives[0];
18
+ return {
19
+ transcript: channel.transcript,
20
+ words: (channel.words ?? []).map((w) => ({
21
+ word: w.word,
22
+ start: w.start,
23
+ end: w.end,
24
+ confidence: w.confidence,
25
+ speaker: w.speaker ?? 0,
26
+ })),
27
+ duration_seconds: result.metadata.duration,
28
+ };
29
+ }
30
+ // Extract only user speech (speaker 1) from transcript words
31
+ export function user_speech_only(result) {
32
+ return result.words
33
+ .filter((w) => w.speaker === 1)
34
+ .map((w) => w.word)
35
+ .join(" ");
36
+ }
37
+ //# sourceMappingURL=deepgram.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deepgram.js","sourceRoot":"","sources":["../../src/lib/deepgram.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,CAAC,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AAc9D,sDAAsD;AACtD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,SAAiB;IAEjB,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,aAAa,CACvE,EAAE,GAAG,EAAE,SAAS,EAAE,EAClB;QACE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK;QAC5B,OAAO,EAAE,IAAI,EAAU,qBAAqB;QAC5C,SAAS,EAAE,IAAI;QACf,UAAU,EAAE,IAAI;QAChB,YAAY,EAAE,IAAI;KACnB,CACF,CAAC;IAEF,IAAI,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/D,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAExD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAE3D,OAAO;QACL,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,KAAK,EAAE,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACvC,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,CAAC;SACxB,CAAC,CAAC;QACH,gBAAgB,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ;KAC3C,CAAC;AACJ,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,gBAAgB,CAAC,MAAwB;IACvD,OAAO,MAAM,CAAC,KAAK;SAChB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC;SAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SAClB,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC"}
@@ -0,0 +1,42 @@
1
+ export declare const inngest: any;
2
+ export type Events = {
3
+ "session/completed": {
4
+ data: {
5
+ user_id: string;
6
+ session_id: string;
7
+ };
8
+ };
9
+ "session/transcribed": {
10
+ data: {
11
+ user_id: string;
12
+ session_id: string;
13
+ transcript_r2_key: string;
14
+ };
15
+ };
16
+ "identity/updated": {
17
+ data: {
18
+ user_id: string;
19
+ };
20
+ };
21
+ "match/confirmed": {
22
+ data: {
23
+ match_id: string;
24
+ };
25
+ };
26
+ "match/both-accepted": {
27
+ data: {
28
+ match_id: string;
29
+ };
30
+ };
31
+ "identity/reanalyze": {
32
+ data: {
33
+ user_id: string;
34
+ };
35
+ };
36
+ "identity/export": {
37
+ data: {
38
+ user_id: string;
39
+ };
40
+ };
41
+ };
42
+ //# sourceMappingURL=inngest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inngest.d.ts","sourceRoot":"","sources":["../../src/lib/inngest.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,OAAO,KAGlB,CAAC;AAIH,MAAM,MAAM,MAAM,GAAG;IACnB,mBAAmB,EAAE;QACnB,IAAI,EAAE;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAE,CAAC;KAC/C,CAAC;IACF,qBAAqB,EAAE;QACrB,IAAI,EAAE;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAC;YAAC,iBAAiB,EAAE,MAAM,CAAA;SAAE,CAAC;KAC1E,CAAC;IACF,kBAAkB,EAAE;QAClB,IAAI,EAAE;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC;KAC3B,CAAC;IACF,iBAAiB,EAAE;QACjB,IAAI,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC;KAC5B,CAAC;IACF,qBAAqB,EAAE;QACrB,IAAI,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC;KAC5B,CAAC;IACF,oBAAoB,EAAE;QACpB,IAAI,EAAE;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC;KAC3B,CAAC;IACF,iBAAiB,EAAE;QACjB,IAAI,EAAE;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC;KAC3B,CAAC;CACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { Inngest } from "inngest";
2
+ import { config } from "./config.js";
3
+ export const inngest = new Inngest({
4
+ id: "meet-the-one",
5
+ eventKey: config.inngest.event_key,
6
+ });
7
+ //# sourceMappingURL=inngest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inngest.js","sourceRoot":"","sources":["../../src/lib/inngest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC;IACjC,EAAE,EAAE,cAAc;IAClB,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,SAAS;CACnC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const openai: any;
2
+ export declare function embed(text: string): Promise<number[]>;
3
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/lib/openai.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,MAAM,KAAgD,CAAC;AAGpE,wBAAsB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAO3D"}
@@ -0,0 +1,13 @@
1
+ import OpenAI from "openai";
2
+ import { config } from "./config.js";
3
+ export const openai = new OpenAI({ apiKey: config.openai.api_key });
4
+ // Generate embedding vector for a text string
5
+ export async function embed(text) {
6
+ const response = await openai.embeddings.create({
7
+ model: config.openai.embedding_model,
8
+ input: text,
9
+ dimensions: config.openai.embedding_dimensions,
10
+ });
11
+ return response.data[0].embedding;
12
+ }
13
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/lib/openai.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;AAEpE,8CAA8C;AAC9C,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,IAAY;IACtC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;QAC9C,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,eAAe;QACpC,KAAK,EAAE,IAAI;QACX,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,oBAAoB;KAC/C,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACpC,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare const SYSTEM_INTAKE_FIRST_CALL: string;
2
+ export declare const SYSTEM_CONSENT_CALL: string;
3
+ export declare const SYSTEM_SIGNAL_EXTRACTION: string;
4
+ export declare const SYSTEM_IDENTITY_MERGE: string;
5
+ export declare const SYSTEM_IDENTITY_NARRATIVE: string;
6
+ export declare const SYSTEM_MODALITY_RENDER: string;
7
+ export declare const SYSTEM_MATCH_VALIDATION: string;
8
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/lib/prompts.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,wBAAwB,QA4B7B,CAAC;AAET,eAAO,MAAM,mBAAmB,QAuBxB,CAAC;AAIT,eAAO,MAAM,wBAAwB,QA4D7B,CAAC;AAET,eAAO,MAAM,qBAAqB,QAsE1B,CAAC;AAIT,eAAO,MAAM,yBAAyB,QAyB9B,CAAC;AAET,eAAO,MAAM,sBAAsB,QAY3B,CAAC;AAET,eAAO,MAAM,uBAAuB,QA2B5B,CAAC"}
@@ -0,0 +1,258 @@
1
+ // ─── Vapi Assistant System Prompts ────────────────────────────────────────────
2
+ // These are pasted into the Vapi dashboard as assistant system prompts.
3
+ // They are also stored here for version control and reference.
4
+ export const SYSTEM_INTAKE_FIRST_CALL = `
5
+ You are the voice of meet-the-one.ai — warm, curious, unhurried. Not a chatbot. Not a form.
6
+ You are having a real conversation to understand who this person is.
7
+
8
+ Your goal: draw out genuine psychological signal across four domains:
9
+ 1. Relationships — how they attach, trust, fight, connect
10
+ 2. Desire — what they want, what they're afraid to want
11
+ 3. Money — scarcity vs abundance, risk, ambition
12
+ 4. Health/energy — how they move through the world physically
13
+
14
+ Technique:
15
+ - Ask one question at a time. Never stack questions.
16
+ - Use projective prompts when direct questions hit walls:
17
+ "If money was handled — what would your week look like?"
18
+ "What's the last thing you did that felt completely alive?"
19
+ "Describe your ideal Sunday morning. Don't optimize it, just describe it."
20
+ - Go quiet. Let silence work. Don't fill it.
21
+ - If they say something surprising, follow it — don't railroad back to the script.
22
+ - 4AM signal: if this call is happening late at night, that's already a signal. Honor the intimacy of it.
23
+
24
+ Do NOT:
25
+ - Ask "what are you looking for in a partner" (too early, too abstract)
26
+ - Mention matching, algorithms, or AI
27
+ - Use therapy language ("boundaries", "healing journey", "red flags")
28
+ - Summarize back everything they said
29
+
30
+ End the call when you have enough signal across at least 3 domains, or after ~15 minutes.
31
+ Close warmly: "That's everything I need for now. Someone will be in touch."
32
+ `.trim();
33
+ export const SYSTEM_CONSENT_CALL = `
34
+ You are a warm, human matchmaker calling on behalf of meet-the-one.ai.
35
+ You have found someone you believe is a genuine match for this person.
36
+
37
+ Your job: present the match in a way that feels specific, not generic.
38
+ You have been given a framing statement — use it. Don't improvise around it.
39
+
40
+ The framing will describe a specific resonance. Lead with that.
41
+
42
+ Structure:
43
+ 1. Brief acknowledgment that you've been listening to them
44
+ 2. Deliver the framing — specific, warm, one sentence
45
+ 3. Ask: "Would you be open to a brief introduction call?"
46
+ 4. If yes: confirm they'll receive a scheduling link by SMS
47
+ 5. If no or hesitant: ask what would make them more open, or close gracefully ("Understood — we'll keep looking")
48
+
49
+ Do NOT:
50
+ - Describe the other person physically
51
+ - Share their name, job, or identifying details
52
+ - Oversell ("this is your soulmate")
53
+ - Rush the consent
54
+
55
+ If they ask how you found the match: "We look at how people think and feel, not what they look like."
56
+ `.trim();
57
+ // ─── Analysis Pipeline Prompts ────────────────────────────────────────────────
58
+ export const SYSTEM_SIGNAL_EXTRACTION = `
59
+ You are a depth psychologist and psychographic analyst. You will receive a transcript
60
+ of a person's voice session with an AI interviewer. Extract only what is genuinely
61
+ present in the transcript — never fabricate or infer beyond what's there.
62
+
63
+ Your job: extract signals across four domains and supporting dimensions.
64
+
65
+ Return a JSON object with this structure:
66
+ {
67
+ "relationships": {
68
+ "signals": [], // array of direct observations from transcript
69
+ "attachment_cues": [],
70
+ "trust_language": [],
71
+ "conflict_references": [],
72
+ "depth_breadth_indicators": []
73
+ },
74
+ "desire": {
75
+ "signals": [],
76
+ "expressed": [],
77
+ "inferred": [],
78
+ "kink_vanilla_indicators": [],
79
+ "shame_sovereignty_language": []
80
+ },
81
+ "money": {
82
+ "signals": [],
83
+ "scarcity_abundance_language": [],
84
+ "risk_language": [],
85
+ "ambition_indicators": []
86
+ },
87
+ "health": {
88
+ "signals": [],
89
+ "energy_descriptors": [],
90
+ "physicality_references": [],
91
+ "self_care_language": []
92
+ },
93
+ "worldview": {
94
+ "danger_adventure_signals": [],
95
+ "people_good_bad_signals": [],
96
+ "symbolic_responses": [], // from projective prompts if used
97
+ "fear_joy_valence": []
98
+ },
99
+ "modality_signals": {
100
+ "explicit_statements": [], // anything person directly said about relationship type
101
+ "inferred_from_language": []
102
+ },
103
+ "behavioral_signals": {
104
+ "travel_passport": null,
105
+ "communication_style": null,
106
+ "energy_level": null,
107
+ "yes_no_orientation": null
108
+ },
109
+ "vals_indicators": [],
110
+ "games_indicators": [] // Eight Games framework signals
111
+ }
112
+
113
+ Rules:
114
+ - Quote the transcript directly as evidence where possible
115
+ - If a domain has no signal in this session, return empty arrays — do not fabricate
116
+ - Do not interpret beyond what is present
117
+ - late_night sessions (after midnight) carry higher signal weight — note if relevant
118
+ `.trim();
119
+ export const SYSTEM_IDENTITY_MERGE = `
120
+ You are a depth psychologist building a cumulative psychological portrait of a person
121
+ across multiple conversation sessions. Your job is to merge new session signals into
122
+ an existing identity profile, producing an updated portrait.
123
+
124
+ Rules:
125
+ - Weight recent sessions slightly higher than older ones
126
+ - When signals contradict, note the evolution — do not erase old signals
127
+ - Divergence between stated preferences and implied ones is itself high signal — track it
128
+ - Increase confidence scores as evidence accumulates
129
+ - Never fabricate — only assert what the evidence supports
130
+
131
+ Return a single JSON object with exactly this structure:
132
+ {
133
+ "base_profile": {
134
+ "updated_at": "<ISO timestamp>",
135
+ "session_count": <number>,
136
+ "total_minutes": <number>,
137
+ "relationships": {
138
+ "attachment_style": "<string>",
139
+ "trust_pattern": "<string>",
140
+ "conflict_mode": "<string>",
141
+ "depth_vs_breadth": <0-1>,
142
+ "confidence": <0-1>,
143
+ "evidence": ["<quote>", ...]
144
+ },
145
+ "desire": {
146
+ "expressed_desires": [],
147
+ "inferred_desires": [],
148
+ "kink_vanilla_spectrum": <0-1>,
149
+ "shame_sovereignty_score": <0-1>,
150
+ "confidence": <0-1>,
151
+ "evidence": []
152
+ },
153
+ "money": {
154
+ "scarcity_abundance_orientation": <0-1>,
155
+ "risk_tolerance": <0-1>,
156
+ "ambition_contentment": <0-1>,
157
+ "financial_mythology_active": [],
158
+ "confidence": <0-1>,
159
+ "evidence": []
160
+ },
161
+ "health": {
162
+ "energy_pattern": "<string>",
163
+ "physicality_orientation": <0-1>,
164
+ "self_care_mode": "<string>",
165
+ "confidence": <0-1>,
166
+ "evidence": []
167
+ },
168
+ "worldview": {
169
+ "world_danger_adventure": <0-1>,
170
+ "people_good_bad": <0-1>,
171
+ "vals_type": "<Innovator|Thinker|Believer|Achiever|Striver|Experiencer|Maker|Survivor>",
172
+ "vals_confidence": <0-1>,
173
+ "games_active": [],
174
+ "symbolic_responses": []
175
+ }
176
+ },
177
+ "modality_weights": {
178
+ "long-term": <0-1>,
179
+ "casual": <0-1>,
180
+ "kink": <0-1>,
181
+ "open-relationship": <0-1>,
182
+ "polyamory": <0-1>,
183
+ "swinging": <0-1>,
184
+ "friends": <0-1>
185
+ }
186
+ }
187
+
188
+ All modality weights must sum to 1.0.
189
+ `.trim();
190
+ // ─── Identity Export Prompts ───────────────────────────────────────────────────
191
+ export const SYSTEM_IDENTITY_NARRATIVE = `
192
+ You are generating a portable identity document for a person — something they will read and
193
+ recognize as an accurate, humanizing portrait of themselves.
194
+
195
+ You will receive a structured identity profile and a domain name.
196
+ Return a markdown document for that domain with this exact structure:
197
+
198
+ 1. A narrative paragraph (100-200 words) written in second person ("You...").
199
+ Specific, personal, not generic. Use the actual signals from their profile.
200
+ Do NOT use therapy jargon. Do NOT say "you have a secure attachment style" —
201
+ say what that means in how they actually move through relationships.
202
+
203
+ 2. A "**Key signals:**" section with 4-8 bullet points. Short, factual, direct.
204
+ Include confidence scores where meaningful (e.g. "Depth orientation: strong (0.8/1.0)").
205
+
206
+ 3. If confidence is low in a domain (< 0.4), open with:
207
+ "This domain is still forming — we haven't heard enough from you yet to paint a full picture."
208
+ Then give what you have.
209
+
210
+ Rules:
211
+ - No fabrication. Only what the evidence supports.
212
+ - No generic phrases: "good communicator", "values connection", "looking for something real"
213
+ - Write like a very perceptive friend, not a therapist or an algorithm
214
+ - worldview.md: describe VALS type and bifurcation scores in plain language, not framework names
215
+ - modality_weights.md: describe orientation as tendency, not label
216
+ `.trim();
217
+ export const SYSTEM_MODALITY_RENDER = `
218
+ You are generating a focused psychographic text portrait of a person through the lens of a specific relationship modality.
219
+ You will receive a full base identity profile and a target modality.
220
+ Return a single dense paragraph (150-250 words) that captures who this person is specifically within that modality.
221
+
222
+ Rules:
223
+ - Draw only from the profile — do not invent
224
+ - Be specific: use their actual attachment style, values, desires, worldview language
225
+ - Write as if briefing a perceptive matchmaker who needs to understand this person's energy within this modality
226
+ - Do not mention the modality by name in the text
227
+ - Do not use generic phrases ("good communicator", "looking for connection")
228
+ - If the profile has low confidence in a domain, reflect that uncertainty rather than fabricating
229
+ `.trim();
230
+ export const SYSTEM_MATCH_VALIDATION = `
231
+ You are a precision matchmaker with deep psychological training. You will receive
232
+ compacted identity profiles for two people and must assess their compatibility.
233
+
234
+ Evaluate honestly. High confidence only when genuinely warranted.
235
+ A poor match surfaced destroys trust. A good match missed is an acceptable miss.
236
+ When in doubt: lower confidence, not false positivity.
237
+
238
+ Return a JSON object:
239
+ {
240
+ "compatible": <boolean>,
241
+ "confidence": <0-1>,
242
+ "primary_modality": "<modality>",
243
+ "cross_modality": <boolean>,
244
+ "cross_modality_bridge": "<string or null>",
245
+ "resonances": ["<specific shared quality>", ...],
246
+ "tensions": ["<specific potential friction>", ...],
247
+ "tension_fatal": <boolean>,
248
+ "consent_call_framing": "<2-3 sentences the AI matchmaker will speak to each person — warm, specific, not generic>",
249
+ "data_gaps": ["<what would increase confidence if known>"]
250
+ }
251
+
252
+ Rules:
253
+ - resonances must be specific — never say "compatible personalities"
254
+ - consent_call_framing must feel personal, not robotic
255
+ - tension_fatal = true only if the tension is a genuine dealbreaker
256
+ - confidence < 0.7: return compatible: false
257
+ `.trim();
258
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/lib/prompts.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,wEAAwE;AACxE,+DAA+D;AAE/D,MAAM,CAAC,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BvC,CAAC,IAAI,EAAE,CAAC;AAET,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuBlC,CAAC,IAAI,EAAE,CAAC;AAET,iFAAiF;AAEjF,MAAM,CAAC,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4DvC,CAAC,IAAI,EAAE,CAAC;AAET,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsEpC,CAAC,IAAI,EAAE,CAAC;AAET,kFAAkF;AAElF,MAAM,CAAC,MAAM,yBAAyB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;CAyBxC,CAAC,IAAI,EAAE,CAAC;AAET,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;;;;;;;CAYrC,CAAC,IAAI,EAAE,CAAC;AAET,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BtC,CAAC,IAAI,EAAE,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare function upload_buffer(key: string, body: Buffer, content_type: string): Promise<void>;
2
+ export declare function download_buffer(key: string): Promise<Buffer>;
3
+ export declare function upload_json(key: string, data: unknown): Promise<void>;
4
+ export declare function download_json<T = unknown>(key: string): Promise<T>;
5
+ export declare function generate_presigned_get_url(key: string, expires_in_seconds?: number): Promise<string>;
6
+ export declare function key_exists(key: string): Promise<boolean>;
7
+ //# sourceMappingURL=r2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"r2.d.ts","sourceRoot":"","sources":["../../src/lib/r2.ts"],"names":[],"mappings":"AAkBA,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CASf;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUlE;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAM3E;AAED,wBAAsB,aAAa,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAGxE;AAED,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,MAAM,EACX,kBAAkB,SAAO,GACxB,OAAO,CAAC,MAAM,CAAC,CAMjB;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAS9D"}
package/dist/lib/r2.js ADDED
@@ -0,0 +1,49 @@
1
+ import { S3Client, PutObjectCommand, GetObjectCommand, HeadObjectCommand, } from "@aws-sdk/client-s3";
2
+ import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
3
+ import { config } from "./config.js";
4
+ const client = new S3Client({
5
+ region: "auto",
6
+ endpoint: `https://${config.r2.account_id}.r2.cloudflarestorage.com`,
7
+ credentials: {
8
+ accessKeyId: config.r2.access_key_id,
9
+ secretAccessKey: config.r2.secret_access_key,
10
+ },
11
+ });
12
+ export async function upload_buffer(key, body, content_type) {
13
+ await client.send(new PutObjectCommand({
14
+ Bucket: config.r2.bucket,
15
+ Key: key,
16
+ Body: body,
17
+ ContentType: content_type,
18
+ }));
19
+ }
20
+ export async function download_buffer(key) {
21
+ const res = await client.send(new GetObjectCommand({ Bucket: config.r2.bucket, Key: key }));
22
+ if (!res.Body)
23
+ throw new Error(`R2: empty body for key ${key}`);
24
+ const chunks = [];
25
+ for await (const chunk of res.Body) {
26
+ chunks.push(chunk);
27
+ }
28
+ return Buffer.concat(chunks);
29
+ }
30
+ export async function upload_json(key, data) {
31
+ await upload_buffer(key, Buffer.from(JSON.stringify(data)), "application/json");
32
+ }
33
+ export async function download_json(key) {
34
+ const buf = await download_buffer(key);
35
+ return JSON.parse(buf.toString("utf8"));
36
+ }
37
+ export async function generate_presigned_get_url(key, expires_in_seconds = 3600) {
38
+ return getSignedUrl(client, new GetObjectCommand({ Bucket: config.r2.bucket, Key: key }), { expiresIn: expires_in_seconds });
39
+ }
40
+ export async function key_exists(key) {
41
+ try {
42
+ await client.send(new HeadObjectCommand({ Bucket: config.r2.bucket, Key: key }));
43
+ return true;
44
+ }
45
+ catch {
46
+ return false;
47
+ }
48
+ }
49
+ //# sourceMappingURL=r2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"r2.js","sourceRoot":"","sources":["../../src/lib/r2.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC;IAC1B,MAAM,EAAE,MAAM;IACd,QAAQ,EAAE,WAAW,MAAM,CAAC,EAAE,CAAC,UAAU,2BAA2B;IACpE,WAAW,EAAE;QACX,WAAW,EAAE,MAAM,CAAC,EAAE,CAAC,aAAa;QACpC,eAAe,EAAE,MAAM,CAAC,EAAE,CAAC,iBAAiB;KAC7C;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAW,EACX,IAAY,EACZ,YAAoB;IAEpB,MAAM,MAAM,CAAC,IAAI,CACf,IAAI,gBAAgB,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM;QACxB,GAAG,EAAE,GAAG;QACR,IAAI,EAAE,IAAI;QACV,WAAW,EAAE,YAAY;KAC1B,CAAC,CACH,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAW;IAC/C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAC3B,IAAI,gBAAgB,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAC7D,CAAC;IACF,IAAI,CAAC,GAAG,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,EAAE,CAAC,CAAC;IAChE,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,CAAC,IAAiC,EAAE,CAAC;QAChE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW,EAAE,IAAa;IAC1D,MAAM,aAAa,CACjB,GAAG,EACH,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,EACjC,kBAAkB,CACnB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAc,GAAW;IAC1D,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,CAAC;IACvC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAM,CAAC;AAC/C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,GAAW,EACX,kBAAkB,GAAG,IAAI;IAEzB,OAAO,YAAY,CACjB,MAAM,EACN,IAAI,gBAAgB,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAC5D,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAClC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW;IAC1C,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,CACf,IAAI,iBAAiB,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAC9D,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { TimeOfDayBucket, SessionSource } from "../types/index.js";
2
+ export declare function compute_time_of_day_bucket(date: Date): TimeOfDayBucket;
3
+ export declare function create_session(user_id: string, source: SessionSource, opts?: {
4
+ audio_r2_key?: string;
5
+ raw_text?: string;
6
+ duration_seconds?: number;
7
+ }): Promise<string>;
8
+ //# sourceMappingURL=session-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-helpers.d.ts","sourceRoot":"","sources":["../../src/lib/session-helpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAExE,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,IAAI,GAAG,eAAe,CAMtE;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,aAAa,EACrB,IAAI,GAAE;IACJ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACtB,GACL,OAAO,CAAC,MAAM,CAAC,CAiBjB"}
@@ -0,0 +1,31 @@
1
+ import { supabase } from "./supabase.js";
2
+ export function compute_time_of_day_bucket(date) {
3
+ const hour = date.getHours();
4
+ if (hour >= 5 && hour < 12)
5
+ return "morning";
6
+ if (hour >= 12 && hour < 17)
7
+ return "afternoon";
8
+ if (hour >= 17 && hour < 22)
9
+ return "evening";
10
+ return "late_night"; // 22:00–04:59
11
+ }
12
+ export async function create_session(user_id, source, opts = {}) {
13
+ const time_of_day = compute_time_of_day_bucket(new Date());
14
+ const { data, error } = await supabase
15
+ .from("sessions")
16
+ .insert({
17
+ user_id,
18
+ source,
19
+ time_of_day,
20
+ audio_r2_key: opts.audio_r2_key ?? null,
21
+ raw_text: opts.raw_text ?? null,
22
+ duration_seconds: opts.duration_seconds ?? null,
23
+ analysis_status: "pending",
24
+ })
25
+ .select("id")
26
+ .single();
27
+ if (error || !data)
28
+ throw new Error(`Failed to create session: ${error?.message}`);
29
+ return data.id;
30
+ }
31
+ //# sourceMappingURL=session-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-helpers.js","sourceRoot":"","sources":["../../src/lib/session-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,MAAM,UAAU,0BAA0B,CAAC,IAAU;IACnD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC7B,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,GAAG,EAAE;QAAE,OAAO,SAAS,CAAC;IAC7C,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,GAAG,EAAE;QAAE,OAAO,WAAW,CAAC;IAChD,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,GAAG,EAAE;QAAE,OAAO,SAAS,CAAC;IAC9C,OAAO,YAAY,CAAC,CAAC,cAAc;AACrC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAe,EACf,MAAqB,EACrB,OAII,EAAE;IAEN,MAAM,WAAW,GAAG,0BAA0B,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC3D,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ;SACnC,IAAI,CAAC,UAAU,CAAC;SAChB,MAAM,CAAC;QACN,OAAO;QACP,MAAM;QACN,WAAW;QACX,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,IAAI;QACvC,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI;QAC/B,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,IAAI,IAAI;QAC/C,eAAe,EAAE,SAAS;KAC3B,CAAC;SACD,MAAM,CAAC,IAAI,CAAC;SACZ,MAAM,EAAE,CAAC;IACZ,IAAI,KAAK,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IACnF,OAAO,IAAI,CAAC,EAAE,CAAC;AACjB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const supabase: any;
2
+ //# sourceMappingURL=supabase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabase.d.ts","sourceRoot":"","sources":["../../src/lib/supabase.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,QAAQ,KASpB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { createClient } from "@supabase/supabase-js";
2
+ import { config } from "./config.js";
3
+ // Server-side client — service role, bypasses RLS
4
+ // Never expose this to the client
5
+ export const supabase = createClient(config.supabase.url, config.supabase.service_role_key, {
6
+ auth: {
7
+ autoRefreshToken: false,
8
+ persistSession: false,
9
+ },
10
+ });
11
+ //# sourceMappingURL=supabase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabase.js","sourceRoot":"","sources":["../../src/lib/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,kDAAkD;AAClD,kCAAkC;AAClC,MAAM,CAAC,MAAM,QAAQ,GAAG,YAAY,CAClC,MAAM,CAAC,QAAQ,CAAC,GAAG,EACnB,MAAM,CAAC,QAAQ,CAAC,gBAAgB,EAChC;IACE,IAAI,EAAE;QACJ,gBAAgB,EAAE,KAAK;QACvB,cAAc,EAAE,KAAK;KACtB;CACF,CACF,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { Brand } from "../types/index.js";
2
+ export declare const twilio: any;
3
+ export declare function send_otp(phone_e164: string): Promise<void>;
4
+ export declare function verify_otp(phone_e164: string, code: string): Promise<boolean>;
5
+ export declare function send_sms(to: string, body: string, brand?: Brand): Promise<void>;
6
+ export declare function normalize_phone(raw: string): string;
7
+ //# sourceMappingURL=twilio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"twilio.d.ts","sourceRoot":"","sources":["../../src/lib/twilio.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE/C,eAAO,MAAM,MAAM,KAGlB,CAAC;AAGF,wBAAsB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhE;AAGD,wBAAsB,UAAU,CAC9B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CAKlB;AAGD,wBAAsB,QAAQ,CAC5B,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,KAAsB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAMf;AAID,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMnD"}
@@ -0,0 +1,34 @@
1
+ import Twilio from "twilio";
2
+ import { config } from "./config.js";
3
+ export const twilio = Twilio(config.twilio.account_sid, config.twilio.auth_token);
4
+ // Send SMS OTP via Twilio Verify
5
+ export async function send_otp(phone_e164) {
6
+ await twilio.verify.v2
7
+ .services(config.twilio.verify_service_sid)
8
+ .verifications.create({ to: phone_e164, channel: "sms" });
9
+ }
10
+ // Verify SMS OTP
11
+ export async function verify_otp(phone_e164, code) {
12
+ const result = await twilio.verify.v2
13
+ .services(config.twilio.verify_service_sid)
14
+ .verificationChecks.create({ to: phone_e164, code });
15
+ return result.status === "approved";
16
+ }
17
+ // Send an outbound SMS
18
+ export async function send_sms(to, body, brand = "meet-the-one") {
19
+ await twilio.messages.create({
20
+ to,
21
+ from: config.twilio.numbers[brand],
22
+ body,
23
+ });
24
+ }
25
+ // Normalize phone to E.164 — basic, assumes country code included
26
+ // Production: use libphonenumber-js for full parsing
27
+ export function normalize_phone(raw) {
28
+ const digits = raw.replace(/\D/g, "");
29
+ if (!digits.startsWith("1") && digits.length === 10) {
30
+ return `+1${digits}`;
31
+ }
32
+ return `+${digits}`;
33
+ }
34
+ //# sourceMappingURL=twilio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"twilio.js","sourceRoot":"","sources":["../../src/lib/twilio.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAC1B,MAAM,CAAC,MAAM,CAAC,WAAW,EACzB,MAAM,CAAC,MAAM,CAAC,UAAU,CACzB,CAAC;AAEF,iCAAiC;AACjC,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,UAAkB;IAC/C,MAAM,MAAM,CAAC,MAAM,CAAC,EAAE;SACnB,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC;SAC1C,aAAa,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;AAC9D,CAAC;AAED,iBAAiB;AACjB,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,UAAkB,EAClB,IAAY;IAEZ,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,EAAE;SAClC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC;SAC1C,kBAAkB,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,OAAO,MAAM,CAAC,MAAM,KAAK,UAAU,CAAC;AACtC,CAAC;AAED,uBAAuB;AACvB,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,EAAU,EACV,IAAY,EACZ,QAAe,cAAc;IAE7B,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC3B,EAAE;QACF,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;QAClC,IAAI;KACL,CAAC,CAAC;AACL,CAAC;AAED,kEAAkE;AAClE,qDAAqD;AACrD,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACtC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACpD,OAAO,KAAK,MAAM,EAAE,CAAC;IACvB,CAAC;IACD,OAAO,IAAI,MAAM,EAAE,CAAC;AACtB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function trigger_intake_call(to_phone: string, user_id: string): Promise<string>;
2
+ export declare function trigger_consent_call(to_phone: string, match_id: string, framing: string): Promise<string>;
3
+ export declare function get_call_status(call_id: string): Promise<string>;
4
+ //# sourceMappingURL=vapi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vapi.d.ts","sourceRoot":"","sources":["../../src/lib/vapi.ts"],"names":[],"mappings":"AAYA,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAuBjB;AAGD,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAuBjB;AAGD,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQtE"}