ch-rds 0.1.3

Runtime resource loading and local service orchestration
Documentation
diff --git a/src/app/api/api.interceptor.ts b/src/app/api/api.interceptor.ts
index 49a8a59..a1858a6 100644
--- a/src/app/api/api.interceptor.ts
+++ b/src/app/api/api.interceptor.ts
@@ -5,13 +5,19 @@ import { AppState } from "../app.state";
 
 export const addTokenInterceptor: HttpInterceptorFn = (req, next) => {
   const store = inject(Store);
+  const token = store.selectSnapshot(AppState.selectToken).trim();
   if (req.headers.has("Authorization")) return next(req);
+  if (!isBearerToken(token)) return next(req);
   return next(
     req.clone({
       headers: req.headers.set(
         "Authorization",
-        `Bearer ${store.selectSnapshot(AppState.selectToken)}`,
+        `Bearer ${token}`,
       ),
     }),
   );
 };
+
+function isBearerToken(token: string): boolean {
+  return token.split(".").filter(Boolean).length === 3;
+}
diff --git a/src/app/api/api.service.ts b/src/app/api/api.service.ts
index e1e5d82..a5078da 100644
--- a/src/app/api/api.service.ts
+++ b/src/app/api/api.service.ts
@@ -18,12 +18,12 @@ export class ApiService {
     database: string,
     token: string,
   ): Observable<{ error?: string }> {
+    const trimmedToken = token.trim();
+    const options = isBearerToken(trimmedToken)
+      ? { headers: { Authorization: "Bearer " + trimmedToken } }
+      : {};
     return this.http
-      .get(`${url}/v1/database/${database}/logs?num_lines=1`, {
-        headers: {
-          Authorization: "Bearer " + token,
-        },
-      })
+      .get(`${url}/v1/database/${database}/schema?version=9`, options)
       .pipe(
         map(() => ({ error: undefined })),
         catchError((err) => {
@@ -84,3 +84,7 @@ export class ApiService {
     return this.http.get<T>(`${dbInfo.url}/v1/database/${dbInfo.db}/${url}`);
   }
 }
+
+function isBearerToken(token: string): boolean {
+  return token.split(".").filter(Boolean).length === 3;
+}
diff --git a/src/app/api/logs-fetcher.ts b/src/app/api/logs-fetcher.ts
index c4e0f2b..ecb1703 100644
--- a/src/app/api/logs-fetcher.ts
+++ b/src/app/api/logs-fetcher.ts
@@ -17,10 +17,14 @@ export function streamLogs(
   const pump = async () => {
     console.log("PUMPING");
     while (!subject.closed) {
+      const trimmedToken = token.trim();
+      const requestInit: RequestInit = { signal: cancellation.signal };
+      if (isBearerToken(trimmedToken)) {
+        requestInit.headers = { Authorization: "Bearer " + trimmedToken };
+      }
       console.log("feetching data");
       await fetch(url, {
-        headers: { Authorization: "Bearer " + token },
-        signal: cancellation.signal,
+        ...requestInit,
       }).then((r) => readLogsFromResponse(r, subject));
     }
     console.log("WE OUT BABYYYYY");
@@ -65,3 +69,7 @@ function parseLogsChunk(chunk: Uint8Array, subject: Subject<LogLine[]>) {
     });
   subject.next(lines);
 }
+
+function isBearerToken(token: string): boolean {
+  return token.split(".").filter(Boolean).length === 3;
+}
diff --git a/src/app/app.state.ts b/src/app/app.state.ts
index 86384ac..ff67aeb 100644
--- a/src/app/app.state.ts
+++ b/src/app/app.state.ts
@@ -57,7 +57,7 @@ export class AppState {
 
   @Selector()
   static selectHasCredentialsSet(state: AppStateModel) {
-    return !!state.instanceUrl && !!state.token && !!state.database;
+    return !!state.instanceUrl && !!state.database;
   }
 
   @Action(TestDatabaseConnectionAction)
diff --git a/src/app/pages/settings/settings.component.html b/src/app/pages/settings/settings.component.html
index 47c7538..a7a1c0f 100644
--- a/src/app/pages/settings/settings.component.html
+++ b/src/app/pages/settings/settings.component.html
@@ -39,7 +39,7 @@
             pInputText
             formControlName="token"
           />
-          <label for="token-input">Token (eyJ...)</label>
+          <label for="token-input">Token (optional for public local DB)</label>
         </p-floatlabel>
         <div class="flex justify-between">
           <p-button
@@ -60,10 +60,10 @@
         </div>
       </form>
       <p class="text-center mt-8">
-        To find your token:<br />
-        1. Login to your instance using the CLI (spacetime login)<br />
-        2. Open: ~/.config/spacetime/cli.toml<br />
-        3. Your token should now be available after "spacetimedb_token"
+        Local public tables can be explored without a token.<br />
+        Logs still require a database owner token from the same SpacetimeDB
+        instance.<br />
+        Use the CLI only when owner-only actions are needed.
       </p>
     </p-card>
   </div>
diff --git a/src/app/pages/settings/settings.component.ts b/src/app/pages/settings/settings.component.ts
index 5e025f5..58f37af 100644
--- a/src/app/pages/settings/settings.component.ts
+++ b/src/app/pages/settings/settings.component.ts
@@ -34,7 +34,7 @@ export class SettingsComponent {
   private readonly toast = inject(MessageService);
 
   form = this.fb.group({
-    token: ["", Validators.required],
+    token: [""],
     instanceUrl: ["", Validators.required],
     database: ["", Validators.required],
   });
@@ -59,7 +59,7 @@ export class SettingsComponent {
         new SetDatabaseInfo(
           values.instanceUrl!,
           values.database!,
-          values.token!,
+          values.token ?? "",
         ),
       )
       .pipe(
@@ -80,7 +80,7 @@ export class SettingsComponent {
       new TestDatabaseConnectionAction(
         values.instanceUrl!,
         values.database!,
-        values.token!,
+        values.token ?? "",
       ),
     );
   }