stagent 0.9.0 → 0.9.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/package.json +1 -1
- package/src/app/auth/callback/route.ts +2 -8
- package/src/instrumentation.node.ts +44 -0
- package/src/instrumentation.ts +6 -43
- package/src/lib/agents/profiles/registry.ts +2 -1
- package/src/lib/billing/email.ts +3 -3
- package/src/lib/billing/stripe.ts +5 -5
- package/src/lib/cloud/supabase-browser.ts +2 -8
- package/src/lib/cloud/supabase-client.ts +11 -4
- package/src/lib/license/cloud-validation.ts +3 -7
- package/src/lib/marketplace/marketplace-client.ts +3 -3
- package/src/lib/sync/cloud-sync.ts +2 -4
- package/src/lib/telemetry/conversion-events.ts +3 -5
- package/src/lib/telemetry/queue.ts +3 -3
package/package.json
CHANGED
|
@@ -3,10 +3,7 @@ import { createClient } from "@supabase/supabase-js";
|
|
|
3
3
|
import { licenseManager } from "@/lib/license/manager";
|
|
4
4
|
import { validateLicenseWithCloud } from "@/lib/license/cloud-validation";
|
|
5
5
|
import { sendUpgradeConfirmation } from "@/lib/billing/email";
|
|
6
|
-
|
|
7
|
-
const DEFAULT_SUPABASE_URL = "https://yznantjbmacbllhcyzwc.supabase.co";
|
|
8
|
-
const DEFAULT_SUPABASE_ANON_KEY =
|
|
9
|
-
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl6bmFudGpibWFjYmxsaGN5endjIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzI1MDg1ODMsImV4cCI6MjA4ODA4NDU4M30.i-P7MXpR1_emBjhUkzbFeSX7fgjgPDv90_wkqF7sW3Y";
|
|
6
|
+
import { getSupabaseUrl, getSupabaseAnonKey } from "@/lib/cloud/supabase-client";
|
|
10
7
|
|
|
11
8
|
/**
|
|
12
9
|
* GET /auth/callback
|
|
@@ -30,10 +27,7 @@ export async function GET(req: NextRequest) {
|
|
|
30
27
|
return NextResponse.redirect(new URL("/settings?auth=error", req.url));
|
|
31
28
|
}
|
|
32
29
|
|
|
33
|
-
const
|
|
34
|
-
const anonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || DEFAULT_SUPABASE_ANON_KEY;
|
|
35
|
-
|
|
36
|
-
const supabase = createClient(url, anonKey, {
|
|
30
|
+
const supabase = createClient(getSupabaseUrl(), getSupabaseAnonKey(), {
|
|
37
31
|
auth: { persistSession: false },
|
|
38
32
|
});
|
|
39
33
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js-only instrumentation startup.
|
|
3
|
+
* Imported dynamically from instrumentation.ts with a bundler-ignore comment
|
|
4
|
+
* so the Edge runtime never analyzes this module's dependency tree.
|
|
5
|
+
*/
|
|
6
|
+
export async function registerNode() {
|
|
7
|
+
// License manager — initialize from DB (creates default row if needed)
|
|
8
|
+
const { licenseManager } = await import("@/lib/license/manager");
|
|
9
|
+
licenseManager.initialize();
|
|
10
|
+
licenseManager.startValidationTimer();
|
|
11
|
+
|
|
12
|
+
const { startScheduler } = await import("@/lib/schedules/scheduler");
|
|
13
|
+
startScheduler();
|
|
14
|
+
|
|
15
|
+
const { startChannelPoller } = await import("@/lib/channels/poller");
|
|
16
|
+
startChannelPoller();
|
|
17
|
+
|
|
18
|
+
const { startAutoBackup } = await import("@/lib/snapshots/auto-backup");
|
|
19
|
+
startAutoBackup();
|
|
20
|
+
|
|
21
|
+
// History retention cleanup — prunes old agent_logs and usage_ledger
|
|
22
|
+
// based on tier retention limit (Community: 30 days)
|
|
23
|
+
const CLEANUP_INTERVAL = 24 * 60 * 60 * 1000; // 24 hours
|
|
24
|
+
|
|
25
|
+
async function cleanup() {
|
|
26
|
+
const retentionDays = licenseManager.getLimit("historyRetentionDays");
|
|
27
|
+
if (!Number.isFinite(retentionDays)) return; // Unlimited retention
|
|
28
|
+
|
|
29
|
+
const { db } = await import("@/lib/db");
|
|
30
|
+
const { agentLogs, usageLedger } = await import("@/lib/db/schema");
|
|
31
|
+
const { lt } = await import("drizzle-orm");
|
|
32
|
+
|
|
33
|
+
const cutoff = new Date(Date.now() - retentionDays * 24 * 60 * 60 * 1000);
|
|
34
|
+
db.delete(agentLogs).where(lt(agentLogs.timestamp, cutoff)).run();
|
|
35
|
+
db.delete(usageLedger).where(lt(usageLedger.startedAt, cutoff)).run();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
cleanup().catch(() => {});
|
|
39
|
+
setInterval(() => cleanup().catch(() => {}), CLEANUP_INTERVAL);
|
|
40
|
+
|
|
41
|
+
// Telemetry batch flush (opt-in, every 5 minutes)
|
|
42
|
+
const { startTelemetryFlush } = await import("@/lib/telemetry/queue");
|
|
43
|
+
startTelemetryFlush();
|
|
44
|
+
}
|
package/src/instrumentation.ts
CHANGED
|
@@ -1,47 +1,10 @@
|
|
|
1
1
|
export async function register() {
|
|
2
|
-
// Only start background services on the server (not during build or edge)
|
|
3
2
|
if (process.env.NEXT_RUNTIME === "nodejs") {
|
|
4
|
-
//
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
startScheduler();
|
|
11
|
-
|
|
12
|
-
const { startChannelPoller } = await import("@/lib/channels/poller");
|
|
13
|
-
startChannelPoller();
|
|
14
|
-
|
|
15
|
-
const { startAutoBackup } = await import("@/lib/snapshots/auto-backup");
|
|
16
|
-
startAutoBackup();
|
|
17
|
-
|
|
18
|
-
// History retention cleanup — prunes old agent_logs and usage_ledger
|
|
19
|
-
// based on tier retention limit (Community: 30 days)
|
|
20
|
-
startHistoryCleanup(licenseManager);
|
|
21
|
-
|
|
22
|
-
// Telemetry batch flush (opt-in, every 5 minutes)
|
|
23
|
-
const { startTelemetryFlush } = await import("@/lib/telemetry/queue");
|
|
24
|
-
startTelemetryFlush();
|
|
3
|
+
// Single dynamic import with bundler-ignore so Turbopack's Edge analyzer
|
|
4
|
+
// never follows this module's Node.js dependency tree.
|
|
5
|
+
const { registerNode } = await import(
|
|
6
|
+
/* webpackIgnore: true */ "./instrumentation.node"
|
|
7
|
+
);
|
|
8
|
+
await registerNode();
|
|
25
9
|
}
|
|
26
10
|
}
|
|
27
|
-
|
|
28
|
-
async function startHistoryCleanup(licenseManager: { getLimit: (r: "historyRetentionDays") => number }) {
|
|
29
|
-
const CLEANUP_INTERVAL = 24 * 60 * 60 * 1000; // 24 hours
|
|
30
|
-
|
|
31
|
-
async function cleanup() {
|
|
32
|
-
const retentionDays = licenseManager.getLimit("historyRetentionDays");
|
|
33
|
-
if (!Number.isFinite(retentionDays)) return; // Unlimited retention
|
|
34
|
-
|
|
35
|
-
const { db } = await import("@/lib/db");
|
|
36
|
-
const { agentLogs, usageLedger } = await import("@/lib/db/schema");
|
|
37
|
-
const { lt } = await import("drizzle-orm");
|
|
38
|
-
|
|
39
|
-
const cutoff = new Date(Date.now() - retentionDays * 24 * 60 * 60 * 1000);
|
|
40
|
-
db.delete(agentLogs).where(lt(agentLogs.timestamp, cutoff)).run();
|
|
41
|
-
db.delete(usageLedger).where(lt(usageLedger.startedAt, cutoff)).run();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Run once at startup, then daily
|
|
45
|
-
cleanup().catch(() => {});
|
|
46
|
-
setInterval(() => cleanup().catch(() => {}), CLEANUP_INTERVAL);
|
|
47
|
-
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import yaml from "js-yaml";
|
|
4
5
|
import { ProfileConfigSchema } from "@/lib/validators/profile";
|
|
@@ -30,7 +31,7 @@ function getBuiltinsDir(): string {
|
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
const SKILLS_DIR = path.join(
|
|
33
|
-
process.env.HOME ?? process.env.USERPROFILE ??
|
|
34
|
+
process.env.HOME ?? process.env.USERPROFILE ?? homedir(),
|
|
34
35
|
".claude",
|
|
35
36
|
"skills"
|
|
36
37
|
);
|
package/src/lib/billing/email.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* the cloud backend is not configured.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { isCloudConfigured } from "@/lib/cloud/supabase-client";
|
|
9
|
+
import { isCloudConfigured, getSupabaseUrl, getSupabaseAnonKey } from "@/lib/cloud/supabase-client";
|
|
10
10
|
|
|
11
11
|
async function sendEmail(
|
|
12
12
|
template: string,
|
|
@@ -15,8 +15,8 @@ async function sendEmail(
|
|
|
15
15
|
): Promise<void> {
|
|
16
16
|
if (!isCloudConfigured()) return;
|
|
17
17
|
|
|
18
|
-
const supabaseUrl =
|
|
19
|
-
const anonKey =
|
|
18
|
+
const supabaseUrl = getSupabaseUrl();
|
|
19
|
+
const anonKey = getSupabaseAnonKey();
|
|
20
20
|
|
|
21
21
|
try {
|
|
22
22
|
await fetch(`${supabaseUrl}/functions/v1/send-email`, {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Edge Functions to create Checkout Sessions and Portal Sessions.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { isCloudConfigured } from "@/lib/cloud/supabase-client";
|
|
9
|
+
import { isCloudConfigured, getSupabaseUrl, getSupabaseAnonKey } from "@/lib/cloud/supabase-client";
|
|
10
10
|
import { getProductForTier } from "./products";
|
|
11
11
|
import type { LicenseTier } from "@/lib/license/tier-limits";
|
|
12
12
|
import type { BillingInterval } from "./products";
|
|
@@ -30,8 +30,8 @@ export async function createCheckoutSession(
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const priceId = product.prices[billingPeriod].id;
|
|
33
|
-
const supabaseUrl =
|
|
34
|
-
const anonKey =
|
|
33
|
+
const supabaseUrl = getSupabaseUrl();
|
|
34
|
+
const anonKey = getSupabaseAnonKey();
|
|
35
35
|
|
|
36
36
|
try {
|
|
37
37
|
const response = await fetch(
|
|
@@ -72,8 +72,8 @@ export async function createPortalSession(
|
|
|
72
72
|
return { error: "Cloud backend not configured" };
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
const supabaseUrl =
|
|
76
|
-
const anonKey =
|
|
75
|
+
const supabaseUrl = getSupabaseUrl();
|
|
76
|
+
const anonKey = getSupabaseAnonKey();
|
|
77
77
|
|
|
78
78
|
try {
|
|
79
79
|
const response = await fetch(
|
|
@@ -9,10 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { createClient, type SupabaseClient } from "@supabase/supabase-js";
|
|
12
|
-
|
|
13
|
-
const DEFAULT_SUPABASE_URL = "https://yznantjbmacbllhcyzwc.supabase.co";
|
|
14
|
-
const DEFAULT_SUPABASE_ANON_KEY =
|
|
15
|
-
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl6bmFudGpibWFjYmxsaGN5endjIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzI1MDg1ODMsImV4cCI6MjA4ODA4NDU4M30.i-P7MXpR1_emBjhUkzbFeSX7fgjgPDv90_wkqF7sW3Y";
|
|
12
|
+
import { getSupabaseUrl, getSupabaseAnonKey } from "@/lib/cloud/supabase-client";
|
|
16
13
|
|
|
17
14
|
let browserClient: SupabaseClient | null = null;
|
|
18
15
|
|
|
@@ -23,10 +20,7 @@ let browserClient: SupabaseClient | null = null;
|
|
|
23
20
|
export function getSupabaseBrowserClient(): SupabaseClient {
|
|
24
21
|
if (browserClient) return browserClient;
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
const anonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || DEFAULT_SUPABASE_ANON_KEY;
|
|
28
|
-
|
|
29
|
-
browserClient = createClient(url, anonKey, {
|
|
23
|
+
browserClient = createClient(getSupabaseUrl(), getSupabaseAnonKey(), {
|
|
30
24
|
auth: {
|
|
31
25
|
autoRefreshToken: true,
|
|
32
26
|
persistSession: true,
|
|
@@ -15,6 +15,16 @@ const DEFAULT_SUPABASE_URL = "https://yznantjbmacbllhcyzwc.supabase.co";
|
|
|
15
15
|
const DEFAULT_SUPABASE_ANON_KEY =
|
|
16
16
|
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl6bmFudGpibWFjYmxsaGN5endjIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzI1MDg1ODMsImV4cCI6MjA4ODA4NDU4M30.i-P7MXpR1_emBjhUkzbFeSX7fgjgPDv90_wkqF7sW3Y";
|
|
17
17
|
|
|
18
|
+
/** Resolved Supabase URL (env override or production default) */
|
|
19
|
+
export function getSupabaseUrl(): string {
|
|
20
|
+
return process.env.NEXT_PUBLIC_SUPABASE_URL || DEFAULT_SUPABASE_URL;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Resolved Supabase anon key (env override or production default) */
|
|
24
|
+
export function getSupabaseAnonKey(): string {
|
|
25
|
+
return process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || DEFAULT_SUPABASE_ANON_KEY;
|
|
26
|
+
}
|
|
27
|
+
|
|
18
28
|
let client: SupabaseClient | null = null;
|
|
19
29
|
let initialized = false;
|
|
20
30
|
|
|
@@ -27,10 +37,7 @@ export function getSupabaseClient(): SupabaseClient | null {
|
|
|
27
37
|
if (initialized) return client;
|
|
28
38
|
initialized = true;
|
|
29
39
|
|
|
30
|
-
|
|
31
|
-
const anonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || DEFAULT_SUPABASE_ANON_KEY;
|
|
32
|
-
|
|
33
|
-
client = createClient(url, anonKey, {
|
|
40
|
+
client = createClient(getSupabaseUrl(), getSupabaseAnonKey(), {
|
|
34
41
|
auth: {
|
|
35
42
|
autoRefreshToken: true,
|
|
36
43
|
persistSession: false, // Server-side — no browser session
|
|
@@ -6,13 +6,9 @@
|
|
|
6
6
|
* defaults as supabase-client.ts (production backend by default).
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { isCloudConfigured } from "@/lib/cloud/supabase-client";
|
|
9
|
+
import { isCloudConfigured, getSupabaseUrl, getSupabaseAnonKey } from "@/lib/cloud/supabase-client";
|
|
10
10
|
import type { LicenseTier } from "./tier-limits";
|
|
11
11
|
|
|
12
|
-
const DEFAULT_SUPABASE_URL = "https://yznantjbmacbllhcyzwc.supabase.co";
|
|
13
|
-
const DEFAULT_SUPABASE_ANON_KEY =
|
|
14
|
-
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl6bmFudGpibWFjYmxsaGN5endjIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzI1MDg1ODMsImV4cCI6MjA4ODA4NDU4M30.i-P7MXpR1_emBjhUkzbFeSX7fgjgPDv90_wkqF7sW3Y";
|
|
15
|
-
|
|
16
12
|
export interface CloudValidationResult {
|
|
17
13
|
valid: boolean;
|
|
18
14
|
tier: LicenseTier;
|
|
@@ -31,8 +27,8 @@ export async function validateLicenseWithCloud(
|
|
|
31
27
|
return { valid: false, tier: "community", error: "Cloud disabled or no email" };
|
|
32
28
|
}
|
|
33
29
|
|
|
34
|
-
const supabaseUrl =
|
|
35
|
-
const anonKey =
|
|
30
|
+
const supabaseUrl = getSupabaseUrl();
|
|
31
|
+
const anonKey = getSupabaseAnonKey();
|
|
36
32
|
|
|
37
33
|
try {
|
|
38
34
|
const response = await fetch(`${supabaseUrl}/functions/v1/validate-license`, {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Writes go directly to Supabase with RLS.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { getSupabaseClient, isCloudConfigured } from "@/lib/cloud/supabase-client";
|
|
7
|
+
import { getSupabaseClient, isCloudConfigured, getSupabaseUrl, getSupabaseAnonKey } from "@/lib/cloud/supabase-client";
|
|
8
8
|
|
|
9
9
|
export interface MarketplaceBlueprint {
|
|
10
10
|
id: string;
|
|
@@ -36,8 +36,8 @@ export async function browseBlueprints(
|
|
|
36
36
|
return { blueprints: [], total: 0, page, limit: 20 };
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
const supabaseUrl =
|
|
40
|
-
const anonKey =
|
|
39
|
+
const supabaseUrl = getSupabaseUrl();
|
|
40
|
+
const anonKey = getSupabaseAnonKey();
|
|
41
41
|
|
|
42
42
|
const params = new URLSearchParams({ page: String(page) });
|
|
43
43
|
if (category) params.set("category", category);
|
|
@@ -12,7 +12,7 @@ import { readFileSync, writeFileSync, existsSync, copyFileSync } from "fs";
|
|
|
12
12
|
import { join } from "path";
|
|
13
13
|
import { tmpdir } from "os";
|
|
14
14
|
import { getStagentDataDir } from "@/lib/utils/stagent-paths";
|
|
15
|
-
import { getSupabaseClient } from "@/lib/cloud/supabase-client";
|
|
15
|
+
import { getSupabaseClient, getSupabaseUrl, getSupabaseAnonKey } from "@/lib/cloud/supabase-client";
|
|
16
16
|
import { sqlite } from "@/lib/db";
|
|
17
17
|
|
|
18
18
|
const SYNC_VERSION = Buffer.from([0, 0, 0, 1]); // Version 1
|
|
@@ -89,9 +89,7 @@ export async function exportAndUpload(
|
|
|
89
89
|
// If an access token is provided, create an authenticated client for Storage RLS
|
|
90
90
|
if (accessToken) {
|
|
91
91
|
const { createClient } = await import("@supabase/supabase-js");
|
|
92
|
-
|
|
93
|
-
const anonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl6bmFudGpibWFjYmxsaGN5endjIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzI1MDg1ODMsImV4cCI6MjA4ODA4NDU4M30.i-P7MXpR1_emBjhUkzbFeSX7fgjgPDv90_wkqF7sW3Y";
|
|
94
|
-
supabase = createClient(url, anonKey, {
|
|
92
|
+
supabase = createClient(getSupabaseUrl(), getSupabaseAnonKey(), {
|
|
95
93
|
global: { headers: { Authorization: `Bearer ${accessToken}` } },
|
|
96
94
|
auth: { persistSession: false },
|
|
97
95
|
});
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* No-op if Supabase is not configured.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { isCloudConfigured } from "@/lib/cloud/supabase-client";
|
|
12
|
+
import { isCloudConfigured, getSupabaseUrl, getSupabaseAnonKey } from "@/lib/cloud/supabase-client";
|
|
13
13
|
import { getSettingSync, setSetting } from "@/lib/settings/helpers";
|
|
14
14
|
|
|
15
15
|
const SESSION_KEY = "conversion.sessionId";
|
|
@@ -49,10 +49,8 @@ export function trackConversionEvent(
|
|
|
49
49
|
if (!isCloudConfigured()) return;
|
|
50
50
|
|
|
51
51
|
const sessionId = getSessionId();
|
|
52
|
-
const supabaseUrl =
|
|
53
|
-
const anonKey =
|
|
54
|
-
|
|
55
|
-
if (!supabaseUrl || !anonKey) return;
|
|
52
|
+
const supabaseUrl = getSupabaseUrl();
|
|
53
|
+
const anonKey = getSupabaseAnonKey();
|
|
56
54
|
|
|
57
55
|
// Fire-and-forget — don't await, don't block
|
|
58
56
|
fetch(`${supabaseUrl}/functions/v1/conversion-ingest`, {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import { getSettingSync, setSetting } from "@/lib/settings/helpers";
|
|
13
13
|
import { SETTINGS_KEYS } from "@/lib/constants/settings";
|
|
14
|
-
import { isCloudConfigured } from "@/lib/cloud/supabase-client";
|
|
14
|
+
import { isCloudConfigured, getSupabaseUrl, getSupabaseAnonKey } from "@/lib/cloud/supabase-client";
|
|
15
15
|
|
|
16
16
|
const MAX_BATCH_SIZE = 200;
|
|
17
17
|
const FLUSH_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
|
|
@@ -75,8 +75,8 @@ export async function flushTelemetryBatch(): Promise<void> {
|
|
|
75
75
|
const batch = loadBatch();
|
|
76
76
|
if (batch.length === 0) return;
|
|
77
77
|
|
|
78
|
-
const supabaseUrl =
|
|
79
|
-
const anonKey =
|
|
78
|
+
const supabaseUrl = getSupabaseUrl();
|
|
79
|
+
const anonKey = getSupabaseAnonKey();
|
|
80
80
|
|
|
81
81
|
try {
|
|
82
82
|
const res = await fetch(`${supabaseUrl}/functions/v1/telemetry-ingest`, {
|