mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-17 09:41:28 +08:00
feat: wire Supabase credentials and expose tables via Data API
Add supabase/config.sh with project URL and publishable key (safe to commit — RLS restricts to INSERT only). Update telemetry-sync, community-dashboard, and update-check to source the config and include proper auth headers for the Supabase REST API. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,10 @@ set -uo pipefail
|
|||||||
|
|
||||||
GSTACK_DIR="${GSTACK_DIR:-$(cd "$(dirname "$0")/.." && pwd)}"
|
GSTACK_DIR="${GSTACK_DIR:-$(cd "$(dirname "$0")/.." && pwd)}"
|
||||||
|
|
||||||
# Supabase connection — will be populated once project is created
|
# Source Supabase config if not overridden by env
|
||||||
|
if [ -z "${GSTACK_SUPABASE_URL:-}" ] && [ -f "$GSTACK_DIR/supabase/config.sh" ]; then
|
||||||
|
. "$GSTACK_DIR/supabase/config.sh"
|
||||||
|
fi
|
||||||
SUPABASE_URL="${GSTACK_SUPABASE_URL:-}"
|
SUPABASE_URL="${GSTACK_SUPABASE_URL:-}"
|
||||||
ANON_KEY="${GSTACK_SUPABASE_ANON_KEY:-}"
|
ANON_KEY="${GSTACK_SUPABASE_ANON_KEY:-}"
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,12 @@ CURSOR_FILE="$ANALYTICS_DIR/.last-sync-line"
|
|||||||
RATE_FILE="$ANALYTICS_DIR/.last-sync-time"
|
RATE_FILE="$ANALYTICS_DIR/.last-sync-time"
|
||||||
CONFIG_CMD="$GSTACK_DIR/bin/gstack-config"
|
CONFIG_CMD="$GSTACK_DIR/bin/gstack-config"
|
||||||
|
|
||||||
# Default endpoint — will be updated once Supabase project is created
|
# Source Supabase config if not overridden by env
|
||||||
|
if [ -z "${GSTACK_TELEMETRY_ENDPOINT:-}" ] && [ -f "$GSTACK_DIR/supabase/config.sh" ]; then
|
||||||
|
. "$GSTACK_DIR/supabase/config.sh"
|
||||||
|
fi
|
||||||
ENDPOINT="${GSTACK_TELEMETRY_ENDPOINT:-}"
|
ENDPOINT="${GSTACK_TELEMETRY_ENDPOINT:-}"
|
||||||
|
ANON_KEY="${GSTACK_SUPABASE_ANON_KEY:-}"
|
||||||
|
|
||||||
# ─── Pre-checks ──────────────────────────────────────────────
|
# ─── Pre-checks ──────────────────────────────────────────────
|
||||||
# No endpoint configured yet → exit silently
|
# No endpoint configured yet → exit silently
|
||||||
@@ -98,8 +102,11 @@ BATCH="$BATCH]"
|
|||||||
|
|
||||||
# ─── POST to Supabase ────────────────────────────────────────
|
# ─── POST to Supabase ────────────────────────────────────────
|
||||||
RESPONSE="$(curl -sf --max-time 10 \
|
RESPONSE="$(curl -sf --max-time 10 \
|
||||||
-X POST "$ENDPOINT" \
|
-X POST "${ENDPOINT}/telemetry_events" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
|
-H "apikey: ${ANON_KEY}" \
|
||||||
|
-H "Authorization: Bearer ${ANON_KEY}" \
|
||||||
|
-H "Prefer: return=minimal" \
|
||||||
-d "$BATCH" 2>/dev/null || true)"
|
-d "$BATCH" 2>/dev/null || true)"
|
||||||
|
|
||||||
# ─── Update cursor on success ────────────────────────────────
|
# ─── Update cursor on success ────────────────────────────────
|
||||||
|
|||||||
@@ -143,13 +143,21 @@ mkdir -p "$STATE_DIR"
|
|||||||
# Fire Supabase install ping in background (parallel, non-blocking)
|
# Fire Supabase install ping in background (parallel, non-blocking)
|
||||||
# This logs an update check event for community health metrics.
|
# This logs an update check event for community health metrics.
|
||||||
# If the endpoint isn't configured or Supabase is down, this is a no-op.
|
# If the endpoint isn't configured or Supabase is down, this is a no-op.
|
||||||
|
# Source Supabase config for install ping
|
||||||
|
if [ -z "${GSTACK_TELEMETRY_ENDPOINT:-}" ] && [ -f "$GSTACK_DIR/supabase/config.sh" ]; then
|
||||||
|
. "$GSTACK_DIR/supabase/config.sh"
|
||||||
|
fi
|
||||||
_SUPA_ENDPOINT="${GSTACK_TELEMETRY_ENDPOINT:-}"
|
_SUPA_ENDPOINT="${GSTACK_TELEMETRY_ENDPOINT:-}"
|
||||||
if [ -n "$_SUPA_ENDPOINT" ]; then
|
_SUPA_KEY="${GSTACK_SUPABASE_ANON_KEY:-}"
|
||||||
|
if [ -n "$_SUPA_ENDPOINT" ] && [ -n "$_SUPA_KEY" ]; then
|
||||||
_OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
_OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||||
curl -sf --max-time 5 \
|
curl -sf --max-time 5 \
|
||||||
-X POST "${_SUPA_ENDPOINT%/telemetry-ingest}/update-check" \
|
-X POST "${_SUPA_ENDPOINT}/update_checks" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d "{\"version\":\"$LOCAL\",\"os\":\"$_OS\"}" \
|
-H "apikey: ${_SUPA_KEY}" \
|
||||||
|
-H "Authorization: Bearer ${_SUPA_KEY}" \
|
||||||
|
-H "Prefer: return=minimal" \
|
||||||
|
-d "{\"gstack_version\":\"$LOCAL\",\"os\":\"$_OS\"}" \
|
||||||
>/dev/null 2>&1 &
|
>/dev/null 2>&1 &
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
10
supabase/config.sh
Normal file
10
supabase/config.sh
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Supabase project config for gstack telemetry
|
||||||
|
# These are PUBLIC keys — safe to commit (like Firebase public config).
|
||||||
|
# RLS policies restrict what the anon/publishable key can do (INSERT only).
|
||||||
|
|
||||||
|
GSTACK_SUPABASE_URL="https://frugpmstpnojnhfyimgv.supabase.co"
|
||||||
|
GSTACK_SUPABASE_ANON_KEY="sb_publishable_tR4i6cyMIrYTE3s6OyHGHw_ppx2p6WK"
|
||||||
|
|
||||||
|
# Telemetry ingest endpoint (Data API)
|
||||||
|
GSTACK_TELEMETRY_ENDPOINT="${GSTACK_SUPABASE_URL}/rest/v1"
|
||||||
@@ -257,9 +257,22 @@ describe('gstack-telemetry-sync', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('gstack-community-dashboard', () => {
|
describe('gstack-community-dashboard', () => {
|
||||||
test('shows unconfigured message when no Supabase URL', () => {
|
test('shows unconfigured message when no Supabase config available', () => {
|
||||||
const output = run(`${BIN}/gstack-community-dashboard`);
|
// Use a fake GSTACK_DIR with no supabase/config.sh
|
||||||
|
const output = run(`${BIN}/gstack-community-dashboard`, {
|
||||||
|
GSTACK_DIR: tmpDir,
|
||||||
|
GSTACK_SUPABASE_URL: '',
|
||||||
|
GSTACK_SUPABASE_ANON_KEY: '',
|
||||||
|
});
|
||||||
expect(output).toContain('Supabase not configured');
|
expect(output).toContain('Supabase not configured');
|
||||||
expect(output).toContain('gstack-analytics');
|
expect(output).toContain('gstack-analytics');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('connects to Supabase when config exists', () => {
|
||||||
|
// Use the real GSTACK_DIR which has supabase/config.sh
|
||||||
|
const output = run(`${BIN}/gstack-community-dashboard`);
|
||||||
|
expect(output).toContain('gstack community dashboard');
|
||||||
|
// Should not show "not configured" since config.sh exists
|
||||||
|
expect(output).not.toContain('Supabase not configured');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user