northbase 0.1.1 → 0.1.2

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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # mybot-notes-cli
1
+ # northbase
2
2
 
3
3
  A local-first CLI for reading and writing text files stored in a Supabase `public.files` table. Uses email/password auth with RLS so each user only sees their own files. Session is stored locally — no env file required.
4
4
 
@@ -40,7 +40,7 @@ create trigger files_updated_at
40
40
 
41
41
  ```bash
42
42
  npm install
43
- npm link # makes `mybot` available globally on your PATH
43
+ npm link # makes `northbase` available globally on your PATH
44
44
  ```
45
45
 
46
46
  No environment file needed. The Supabase project URL and anon key are public constants baked into the CLI.
@@ -52,27 +52,27 @@ No environment file needed. The Supabase project URL and anon key are public con
52
52
  Prompts for your email and password interactively (password is not echoed):
53
53
 
54
54
  ```bash
55
- mybot login
55
+ northbase login
56
56
  # Email: you@example.com
57
57
  # Password:
58
58
  # Logged in.
59
59
  ```
60
60
 
61
- Your session (access + refresh tokens) is stored at `~/.mybot/session.json` with mode `600`. Tokens are refreshed automatically when they expire — you should only need to log in once.
61
+ Your session (access + refresh tokens) is stored at `~/.northbase/session.json` with mode `600`. Tokens are refreshed automatically when they expire — you should only need to log in once.
62
62
 
63
63
  ### Log out
64
64
 
65
65
  ```bash
66
- mybot logout
66
+ northbase logout
67
67
  # Logged out.
68
68
  ```
69
69
 
70
- Deletes `~/.mybot/session.json` and signs out server-side.
70
+ Deletes `~/.northbase/session.json` and signs out server-side.
71
71
 
72
72
  ### Check who you are
73
73
 
74
74
  ```bash
75
- mybot whoami
75
+ northbase whoami
76
76
  # Logged in as you@example.com (uuid...)
77
77
  ```
78
78
 
@@ -80,11 +80,11 @@ mybot whoami
80
80
 
81
81
  ### Get a file
82
82
 
83
- Fetches file content and prints it to stdout. Uses a local cache at `~/.mybot/files/` and only downloads from Supabase when the remote `updated_at` timestamp differs from the cached value.
83
+ Fetches file content and prints it to stdout. Uses a local cache at `~/.northbase/files/` and only downloads from Supabase when the remote `updated_at` timestamp differs from the cached value.
84
84
 
85
85
  ```bash
86
- mybot get ideas.md
87
- mybot get notes/todo.txt
86
+ northbase get ideas.md
87
+ northbase get notes/todo.txt
88
88
  ```
89
89
 
90
90
  ### Put a file
@@ -92,9 +92,9 @@ mybot get notes/todo.txt
92
92
  Reads content from stdin, upserts it to Supabase, then updates the local cache.
93
93
 
94
94
  ```bash
95
- printf "hello world\n" | mybot put test/cli.md
96
- cat my-local-file.md | mybot put ideas.md
97
- echo "updated content" | mybot put notes/todo.txt
95
+ printf "hello world\n" | northbase put test/cli.md
96
+ cat my-local-file.md | northbase put ideas.md
97
+ echo "updated content" | northbase put notes/todo.txt
98
98
  ```
99
99
 
100
100
  On success, prints a single confirmation line to stdout:
@@ -108,19 +108,19 @@ PUT ok test/cli.md bytes=12 updated_at=2024-01-15T10:30:00.000Z
108
108
  All files are mirrored at:
109
109
 
110
110
  ```
111
- ~/.mybot/files/<path>
111
+ ~/.northbase/files/<path>
112
112
  ```
113
113
 
114
114
  Metadata (timestamps and byte counts) is stored at:
115
115
 
116
116
  ```
117
- ~/.mybot/index.json
117
+ ~/.northbase/index.json
118
118
  ```
119
119
 
120
120
  Session tokens are stored at:
121
121
 
122
122
  ```
123
- ~/.mybot/session.json (mode 600 — readable only by you)
123
+ ~/.northbase/session.json (mode 600 — readable only by you)
124
124
  ```
125
125
 
126
126
  The CLI compares `updated_at` timestamps before downloading — if your local copy is current, no content fetch is made.
@@ -135,8 +135,8 @@ The CLI compares `updated_at` timestamps before downloading — if your local co
135
135
  Debug logs go to stderr so they never pollute stdout pipelines:
136
136
 
137
137
  ```
138
- MYBOT GET local-hit ideas.md # served from local cache
139
- MYBOT GET remote-refresh ideas.md # downloaded from Supabase
140
- MYBOT PUT test/cli.md bytes=12 updated_at=2024-01-15T10:30:00.000Z
141
- MYBOT session refreshing # printed when access token is silently renewed
138
+ NORTHBASE GET local-hit ideas.md # served from local cache
139
+ NORTHBASE GET remote-refresh ideas.md # downloaded from Supabase
140
+ NORTHBASE PUT test/cli.md bytes=12 updated_at=2024-01-15T10:30:00.000Z
141
+ NORTHBASE session refreshing # printed when access token is silently renewed
142
142
  ```
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "northbase",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Local-first CLI for reading and writing text files stored in Supabase",
5
5
  "type": "module",
6
6
  "bin": {
7
- "northbase": "./src/mybot.mjs"
7
+ "northbase": "src/northbase.mjs"
8
8
  },
9
9
  "engines": {
10
10
  "node": ">=18"
@@ -10,11 +10,11 @@ import { createClient } from "@supabase/supabase-js";
10
10
  const SUPABASE_URL = "https://ivxgpjracfctkkdhlwgm.supabase.co";
11
11
  const SUPABASE_KEY = "sb_publishable_LZkkAwsx9q5KgIAeoZAO_A_U88rfFHL";
12
12
 
13
- const MYBOT_DIR = path.join(os.homedir(), ".mybot");
14
- const ROOT = path.join(MYBOT_DIR, "files");
15
- const INDEX_PATH = path.join(MYBOT_DIR, "index.json");
16
- const SESSION_PATH = path.join(MYBOT_DIR, "session.json");
17
- const MAX_BYTES = 500_000;
13
+ const NORTHBASE_DIR = path.join(os.homedir(), ".northbase");
14
+ const ROOT = path.join(NORTHBASE_DIR, "files");
15
+ const INDEX_PATH = path.join(NORTHBASE_DIR, "index.json");
16
+ const SESSION_PATH = path.join(NORTHBASE_DIR, "session.json");
17
+ const MAX_BYTES = 500_000;
18
18
 
19
19
  // ── directory / index helpers ─────────────────────────────────────────────────
20
20
 
@@ -43,12 +43,12 @@ function loadSession() {
43
43
  if (!s?.access_token || !s?.refresh_token) throw new Error("incomplete");
44
44
  return s;
45
45
  } catch {
46
- throw new Error("Not logged in. Run `mybot login`.");
46
+ throw new Error("Not logged in. Run `northbase login`.");
47
47
  }
48
48
  }
49
49
 
50
50
  function saveSession(session) {
51
- ensureDir(MYBOT_DIR);
51
+ ensureDir(NORTHBASE_DIR);
52
52
  fs.writeFileSync(SESSION_PATH, JSON.stringify(session, null, 2), { mode: 0o600 });
53
53
  }
54
54
 
@@ -65,15 +65,15 @@ async function getAuthenticatedClient() {
65
65
  auth: { persistSession: false, autoRefreshToken: false },
66
66
  });
67
67
 
68
- const nowSec = Math.floor(Date.now() / 1000);
68
+ const nowSec = Math.floor(Date.now() / 1000);
69
69
  const isExpired = stored.expires_at && nowSec >= stored.expires_at - 60;
70
70
 
71
71
  if (isExpired) {
72
- console.error("MYBOT session refreshing");
72
+ console.error("NORTHBASE session refreshing");
73
73
  const { data, error } = await supabase.auth.refreshSession({
74
74
  refresh_token: stored.refresh_token,
75
75
  });
76
- if (error) throw new Error("Session expired. Run `mybot login` again.");
76
+ if (error) throw new Error("Session expired. Run `northbase login` again.");
77
77
  saveSession(data.session);
78
78
  const { error: setErr } = await supabase.auth.setSession({
79
79
  access_token: data.session.access_token,
@@ -85,7 +85,7 @@ async function getAuthenticatedClient() {
85
85
  access_token: stored.access_token,
86
86
  refresh_token: stored.refresh_token,
87
87
  });
88
- if (error) throw new Error("Session invalid. Run `mybot login` again.");
88
+ if (error) throw new Error("Session invalid. Run `northbase login` again.");
89
89
  }
90
90
 
91
91
  return supabase;
@@ -153,7 +153,7 @@ async function getFile(rel) {
153
153
  const cached = idx.files?.[relSafe];
154
154
 
155
155
  if (local === null) {
156
- console.error("MYBOT GET remote-refresh", relSafe);
156
+ console.error("NORTHBASE GET remote-refresh", relSafe);
157
157
  const { content, updated_at } = await fetchRemoteContent(supabase, relSafe);
158
158
  const bytes = Buffer.byteLength(content, "utf8");
159
159
  if (bytes > MAX_BYTES) throw new Error(`File too large (${bytes} bytes)`);
@@ -167,11 +167,11 @@ async function getFile(rel) {
167
167
  if (!remoteUpdatedAt) return local;
168
168
 
169
169
  if (cached?.updated_at === remoteUpdatedAt) {
170
- console.error("MYBOT GET local-hit", relSafe);
170
+ console.error("NORTHBASE GET local-hit", relSafe);
171
171
  return local;
172
172
  }
173
173
 
174
- console.error("MYBOT GET remote-refresh", relSafe);
174
+ console.error("NORTHBASE GET remote-refresh", relSafe);
175
175
  const { content, updated_at } = await fetchRemoteContent(supabase, relSafe);
176
176
  const bytes = Buffer.byteLength(content, "utf8");
177
177
  if (bytes > MAX_BYTES) throw new Error(`File too large (${bytes} bytes)`);
@@ -201,7 +201,7 @@ async function putFile(rel, content) {
201
201
  idx.files[relSafe] = { updated_at, bytes };
202
202
  saveIndex(idx);
203
203
 
204
- console.error("MYBOT PUT", relSafe, `bytes=${bytes}`, `updated_at=${updated_at}`);
204
+ console.error("NORTHBASE PUT", relSafe, `bytes=${bytes}`, `updated_at=${updated_at}`);
205
205
  return { bytes, updated_at };
206
206
  }
207
207
 
@@ -218,7 +218,7 @@ async function promptLine(question) {
218
218
 
219
219
  async function promptPassword(question) {
220
220
  if (!process.stdin.isTTY) {
221
- throw new Error("`mybot login` requires an interactive terminal (stdin is not a TTY).");
221
+ throw new Error("`northbase login` requires an interactive terminal (stdin is not a TTY).");
222
222
  }
223
223
  return new Promise((resolve) => {
224
224
  process.stdout.write(question);
@@ -305,7 +305,7 @@ async function main() {
305
305
 
306
306
  if (cmd === "get") {
307
307
  const rel = args[0];
308
- if (!rel) { console.log("Usage: mybot get <path>"); process.exit(1); }
308
+ if (!rel) { console.log("Usage: northbase get <path>"); process.exit(1); }
309
309
  const content = await getFile(rel);
310
310
  process.stdout.write(content);
311
311
  return;
@@ -313,7 +313,7 @@ async function main() {
313
313
 
314
314
  if (cmd === "put") {
315
315
  const rel = args[0];
316
- if (!rel) { console.log("Usage: mybot put <path>"); process.exit(1); }
316
+ if (!rel) { console.log("Usage: northbase put <path>"); process.exit(1); }
317
317
  const chunks = [];
318
318
  for await (const chunk of process.stdin) chunks.push(chunk);
319
319
  const content = Buffer.concat(chunks).toString("utf8");
@@ -323,15 +323,15 @@ async function main() {
323
323
  }
324
324
 
325
325
  console.log("Usage:");
326
- console.log(" mybot login");
327
- console.log(" mybot logout");
328
- console.log(" mybot whoami");
329
- console.log(" mybot get <path>");
330
- console.log(" mybot put <path>");
326
+ console.log(" northbase login");
327
+ console.log(" northbase logout");
328
+ console.log(" northbase whoami");
329
+ console.log(" northbase get <path>");
330
+ console.log(" northbase put <path>");
331
331
  process.exit(1);
332
332
  }
333
333
 
334
334
  main().catch((e) => {
335
- console.error("MYBOT:", e?.message ?? e);
335
+ console.error("NORTHBASE:", e?.message ?? e);
336
336
  process.exit(1);
337
337
  });