@usebitl/cli 0.1.15 → 0.1.17
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/adapters/dist/core.mjs +1 -1
- package/dist/chunks/{chunk-65TI66EM.mjs → chunk-3QUAEA6A.mjs} +2 -2
- package/dist/chunks/{src-TJPPU3TC.mjs → src-DWPF6JDY.mjs} +154 -10
- package/dist/cli.mjs +4 -4
- package/package.json +1 -1
- package/web/assets/index-BZc4CXOL.js +9 -0
- package/web/assets/index-Ojqm2US8.css +2 -0
- package/web/index.html +2 -2
- package/web/sw.js +1 -1
- package/web/assets/index-DKJ1-yaM.js +0 -9
- package/web/assets/index-pbEhErgU.css +0 -2
package/adapters/dist/core.mjs
CHANGED
|
@@ -20062,7 +20062,7 @@ function removeCloudLogin(home = bitlHome()) {
|
|
|
20062
20062
|
rmSync(cloudKeyPath(home), { force: true });
|
|
20063
20063
|
}
|
|
20064
20064
|
function clientVersionHeader() {
|
|
20065
|
-
const v = "0.1.
|
|
20065
|
+
const v = "0.1.17";
|
|
20066
20066
|
return v ? { "x-bitl-client": v } : {};
|
|
20067
20067
|
}
|
|
20068
20068
|
function resolveTarget(home = bitlHome()) {
|
|
@@ -20119,7 +20119,7 @@ async function latestVersion(home, now) {
|
|
|
20119
20119
|
return latest;
|
|
20120
20120
|
}
|
|
20121
20121
|
var updateCommand = (install = process.env.BITL_INSTALL) => install === "npx" ? "npx @usebitl/cli@latest start" : "npm i -g @usebitl/cli";
|
|
20122
|
-
async function checkCliUpdate(current = "0.1.
|
|
20122
|
+
async function checkCliUpdate(current = "0.1.17", opts = {}) {
|
|
20123
20123
|
if (!current || process.env.BITL_NO_UPDATE_CHECK === "1") return void 0;
|
|
20124
20124
|
const latest = await latestVersion(opts.home ?? bitlHome(), opts.now ?? Date.now());
|
|
20125
20125
|
if (!latest || compareVersions(latest, current) <= 0) return void 0;
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
isEmptySession,
|
|
12
12
|
parseWireRecord,
|
|
13
13
|
sessionKey
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-3QUAEA6A.mjs";
|
|
15
15
|
|
|
16
16
|
// ../../../node_modules/.pnpm/bn.js@4.12.5/node_modules/bn.js/lib/bn.js
|
|
17
17
|
var require_bn = __commonJS({
|
|
@@ -8842,6 +8842,102 @@ var ApprovalStore = class {
|
|
|
8842
8842
|
}
|
|
8843
8843
|
};
|
|
8844
8844
|
|
|
8845
|
+
// ../../server/src/store/entry-store.ts
|
|
8846
|
+
var ENTRY_SCHEMA = `
|
|
8847
|
+
CREATE TABLE IF NOT EXISTS entries (
|
|
8848
|
+
id TEXT NOT NULL,
|
|
8849
|
+
account_id TEXT NOT NULL,
|
|
8850
|
+
session_key TEXT,
|
|
8851
|
+
data TEXT NOT NULL,
|
|
8852
|
+
created_at TEXT NOT NULL,
|
|
8853
|
+
updated_at TEXT NOT NULL,
|
|
8854
|
+
PRIMARY KEY (account_id, id)
|
|
8855
|
+
);
|
|
8856
|
+
CREATE INDEX IF NOT EXISTS entries_time ON entries(account_id, created_at);
|
|
8857
|
+
CREATE INDEX IF NOT EXISTS entries_session ON entries(account_id, session_key, created_at);
|
|
8858
|
+
`;
|
|
8859
|
+
var MAX_ENTRIES = 5e4;
|
|
8860
|
+
var toEntry = (r) => ({
|
|
8861
|
+
id: r.id,
|
|
8862
|
+
sessionKey: r.session_key ?? void 0,
|
|
8863
|
+
data: r.data,
|
|
8864
|
+
createdAt: r.created_at,
|
|
8865
|
+
updatedAt: r.updated_at
|
|
8866
|
+
});
|
|
8867
|
+
var EntryStore = class {
|
|
8868
|
+
constructor(db) {
|
|
8869
|
+
this.db = db;
|
|
8870
|
+
}
|
|
8871
|
+
db;
|
|
8872
|
+
listeners = /* @__PURE__ */ new Set();
|
|
8873
|
+
subscribe(fn) {
|
|
8874
|
+
this.listeners.add(fn);
|
|
8875
|
+
return () => this.listeners.delete(fn);
|
|
8876
|
+
}
|
|
8877
|
+
emit(c) {
|
|
8878
|
+
for (const l of this.listeners) l(c);
|
|
8879
|
+
}
|
|
8880
|
+
/**
|
|
8881
|
+
* Newest first. session: only that card's entries. since/before: written at or after / strictly before (paging back).
|
|
8882
|
+
*/
|
|
8883
|
+
async list(accountId, opts = {}) {
|
|
8884
|
+
const where = ["account_id = ?"];
|
|
8885
|
+
const params = [accountId];
|
|
8886
|
+
if (opts.session !== void 0) {
|
|
8887
|
+
where.push("session_key = ?");
|
|
8888
|
+
params.push(opts.session);
|
|
8889
|
+
}
|
|
8890
|
+
if (opts.since) {
|
|
8891
|
+
where.push("created_at >= ?");
|
|
8892
|
+
params.push(opts.since);
|
|
8893
|
+
}
|
|
8894
|
+
if (opts.before) {
|
|
8895
|
+
where.push("created_at < ?");
|
|
8896
|
+
params.push(opts.before);
|
|
8897
|
+
}
|
|
8898
|
+
params.push(Math.min(Math.max(opts.limit ?? 200, 1), 1e3));
|
|
8899
|
+
const { rows } = await this.db.query(`SELECT * FROM entries WHERE ${where.join(" AND ")} ORDER BY created_at DESC, id DESC LIMIT ?`, params);
|
|
8900
|
+
return rows.map(toEntry);
|
|
8901
|
+
}
|
|
8902
|
+
/** The browser picks the id (it is part of the seal's AAD). undefined if it exists or the limit is reached */
|
|
8903
|
+
async create(accountId, id, data, sessionKey2, at = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
8904
|
+
const created = await this.db.transaction(async (q) => {
|
|
8905
|
+
const { rows } = await q("SELECT COUNT(*) AS n, SUM(CASE WHEN id = ? THEN 1 ELSE 0 END) AS dup FROM entries WHERE account_id = ?", [id, accountId]);
|
|
8906
|
+
if (Number(rows[0]?.n ?? 0) >= MAX_ENTRIES || Number(rows[0]?.dup ?? 0) > 0) return false;
|
|
8907
|
+
await q("INSERT INTO entries (id, account_id, session_key, data, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)", [
|
|
8908
|
+
id,
|
|
8909
|
+
accountId,
|
|
8910
|
+
sessionKey2 ?? null,
|
|
8911
|
+
data,
|
|
8912
|
+
at,
|
|
8913
|
+
at
|
|
8914
|
+
]);
|
|
8915
|
+
return true;
|
|
8916
|
+
});
|
|
8917
|
+
if (!created) return void 0;
|
|
8918
|
+
const entry = { id, ...sessionKey2 ? { sessionKey: sessionKey2 } : {}, data, createdAt: at, updatedAt: at };
|
|
8919
|
+
this.emit({ accountId, type: "entry", entry });
|
|
8920
|
+
return entry;
|
|
8921
|
+
}
|
|
8922
|
+
/** Rewrites the sealed content. The time it was written never changes */
|
|
8923
|
+
async update(accountId, id, data) {
|
|
8924
|
+
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
8925
|
+
const entry = await this.db.transaction(async (q) => {
|
|
8926
|
+
const { changes } = await q("UPDATE entries SET data = ?, updated_at = ? WHERE account_id = ? AND id = ?", [data, at, accountId, id]);
|
|
8927
|
+
if (!changes) return void 0;
|
|
8928
|
+
const { rows } = await q("SELECT * FROM entries WHERE account_id = ? AND id = ?", [accountId, id]);
|
|
8929
|
+
return rows[0] ? toEntry(rows[0]) : void 0;
|
|
8930
|
+
});
|
|
8931
|
+
if (entry) this.emit({ accountId, type: "entry", entry });
|
|
8932
|
+
return entry;
|
|
8933
|
+
}
|
|
8934
|
+
async delete(accountId, id) {
|
|
8935
|
+
const ok = await this.db.transaction(async (q) => (await q("DELETE FROM entries WHERE account_id = ? AND id = ?", [accountId, id])).changes > 0);
|
|
8936
|
+
if (ok) this.emit({ accountId, type: "entry-removed", id });
|
|
8937
|
+
return ok;
|
|
8938
|
+
}
|
|
8939
|
+
};
|
|
8940
|
+
|
|
8845
8941
|
// ../../server/src/store/goal-store.ts
|
|
8846
8942
|
var GOAL_SCHEMA = `
|
|
8847
8943
|
CREATE TABLE IF NOT EXISTS goals (
|
|
@@ -9385,7 +9481,7 @@ import { DatabaseSync } from "node:sqlite";
|
|
|
9385
9481
|
var LOCAL_ACCOUNT = "local";
|
|
9386
9482
|
|
|
9387
9483
|
// ../../server/src/store/sqlite.ts
|
|
9388
|
-
var SCHEMA_VERSION =
|
|
9484
|
+
var SCHEMA_VERSION = 11;
|
|
9389
9485
|
var SCHEMA = `
|
|
9390
9486
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
9391
9487
|
account_id TEXT NOT NULL,
|
|
@@ -9427,7 +9523,8 @@ CREATE INDEX IF NOT EXISTS events_session ON events(account_id, session_key, at)
|
|
|
9427
9523
|
CREATE INDEX IF NOT EXISTS events_at ON events(at);
|
|
9428
9524
|
${PUSH_SCHEMA}
|
|
9429
9525
|
${APPROVAL_SCHEMA}
|
|
9430
|
-
${GOAL_SCHEMA}
|
|
9526
|
+
${GOAL_SCHEMA}
|
|
9527
|
+
${ENTRY_SCHEMA}`;
|
|
9431
9528
|
var MIGRATE_2_TO_3 = `
|
|
9432
9529
|
ALTER TABLE sessions RENAME TO sessions_v2;
|
|
9433
9530
|
ALTER TABLE turns RENAME TO turns_v2;
|
|
@@ -12108,10 +12205,49 @@ var streamSSE = (c, cb, onError) => {
|
|
|
12108
12205
|
return c.newResponse(stream2.responseReadable);
|
|
12109
12206
|
};
|
|
12110
12207
|
|
|
12208
|
+
// ../../server/src/entries-api.ts
|
|
12209
|
+
var ENTRY_ID = /^[A-Za-z0-9_-]{8,32}$/;
|
|
12210
|
+
var MAX_DATA = 8e3;
|
|
12211
|
+
var MAX_KEY = 300;
|
|
12212
|
+
var validData = (v) => typeof v === "string" && v.length <= MAX_DATA && SEALED_PATTERN.test(v);
|
|
12213
|
+
var validTime = (v) => typeof v === "string" && !Number.isNaN(Date.parse(v));
|
|
12214
|
+
function mountEntries(app, entries, access = allowAll) {
|
|
12215
|
+
const notFound = { error: "not found" };
|
|
12216
|
+
const readonly = { error: "subscription_required" };
|
|
12217
|
+
app.get("/api/entries", async (c) => {
|
|
12218
|
+
const q = (k) => c.req.query(k) || void 0;
|
|
12219
|
+
const since = q("since");
|
|
12220
|
+
const before = q("before");
|
|
12221
|
+
if (since && !validTime(since) || before && !validTime(before)) return c.json({ error: "invalid time" }, 400);
|
|
12222
|
+
const limit = Number(q("limit") ?? 200);
|
|
12223
|
+
return c.json(await entries.list(c.var.accountId, { session: q("session"), since, before, limit: Number.isFinite(limit) ? limit : 200 }));
|
|
12224
|
+
});
|
|
12225
|
+
app.post("/api/entries", async (c) => {
|
|
12226
|
+
if (!await access.canWrite(c.var.accountId)) return c.json(readonly, 402);
|
|
12227
|
+
const body = await c.req.json().catch(() => null);
|
|
12228
|
+
if (typeof body?.id !== "string" || !ENTRY_ID.test(body.id) || !validData(body.data)) return c.json({ error: "invalid body" }, 400);
|
|
12229
|
+
if (body.sessionKey !== void 0 && (typeof body.sessionKey !== "string" || !body.sessionKey || body.sessionKey.length > MAX_KEY))
|
|
12230
|
+
return c.json({ error: "invalid sessionKey" }, 400);
|
|
12231
|
+
const entry = await entries.create(c.var.accountId, body.id, body.data, body.sessionKey);
|
|
12232
|
+
return entry ? c.json(entry, 201) : c.json({ error: "entry exists or too many entries" }, 409);
|
|
12233
|
+
});
|
|
12234
|
+
app.put("/api/entries/:id", async (c) => {
|
|
12235
|
+
if (!await access.canWrite(c.var.accountId)) return c.json(readonly, 402);
|
|
12236
|
+
const body = await c.req.json().catch(() => null);
|
|
12237
|
+
if (!validData(body?.data)) return c.json({ error: "invalid body" }, 400);
|
|
12238
|
+
const entry = await entries.update(c.var.accountId, c.req.param("id"), body.data);
|
|
12239
|
+
return entry ? c.json(entry) : c.json(notFound, 404);
|
|
12240
|
+
});
|
|
12241
|
+
app.delete(
|
|
12242
|
+
"/api/entries/:id",
|
|
12243
|
+
async (c) => await entries.delete(c.var.accountId, c.req.param("id")) ? c.json({ ok: true }) : c.json(notFound, 404)
|
|
12244
|
+
);
|
|
12245
|
+
}
|
|
12246
|
+
|
|
12111
12247
|
// ../../server/src/goals-api.ts
|
|
12112
12248
|
var GOAL_ID = /^[A-Za-z0-9_-]{8,32}$/;
|
|
12113
|
-
var
|
|
12114
|
-
var
|
|
12249
|
+
var MAX_DATA2 = 64e3;
|
|
12250
|
+
var validData2 = (v) => typeof v === "string" && v.length <= MAX_DATA2 && SEALED_PATTERN.test(v);
|
|
12115
12251
|
function mountGoals(app, goals, access = allowAll) {
|
|
12116
12252
|
const notFound = { error: "not found" };
|
|
12117
12253
|
const readonly = { error: "subscription_required" };
|
|
@@ -12119,7 +12255,7 @@ function mountGoals(app, goals, access = allowAll) {
|
|
|
12119
12255
|
app.post("/api/goals", async (c) => {
|
|
12120
12256
|
if (!await access.canWrite(c.var.accountId)) return c.json(readonly, 402);
|
|
12121
12257
|
const body = await c.req.json().catch(() => null);
|
|
12122
|
-
if (typeof body?.id !== "string" || !GOAL_ID.test(body.id) || !
|
|
12258
|
+
if (typeof body?.id !== "string" || !GOAL_ID.test(body.id) || !validData2(body.data)) return c.json({ error: "invalid body" }, 400);
|
|
12123
12259
|
const goal = await goals.create(c.var.accountId, body.id, body.data);
|
|
12124
12260
|
return goal ? c.json(goal, 201) : c.json({ error: "goal exists or too many goals" }, 409);
|
|
12125
12261
|
});
|
|
@@ -12127,7 +12263,7 @@ function mountGoals(app, goals, access = allowAll) {
|
|
|
12127
12263
|
if (!await access.canWrite(c.var.accountId)) return c.json(readonly, 402);
|
|
12128
12264
|
const body = await c.req.json().catch(() => null);
|
|
12129
12265
|
if (!body || !Number.isInteger(body.version)) return c.json({ error: "invalid body" }, 400);
|
|
12130
|
-
if (body.data !== void 0 && !
|
|
12266
|
+
if (body.data !== void 0 && !validData2(body.data)) return c.json({ error: "invalid data" }, 400);
|
|
12131
12267
|
if (body.closed !== void 0 && typeof body.closed !== "boolean") return c.json({ error: "invalid closed" }, 400);
|
|
12132
12268
|
const r = await goals.update(c.var.accountId, c.req.param("id"), body.version, {
|
|
12133
12269
|
data: body.data,
|
|
@@ -12147,7 +12283,7 @@ async function ingestRecord(store, accountId, body) {
|
|
|
12147
12283
|
const rec = parseWireRecord(body);
|
|
12148
12284
|
return rec ? store.ingest(accountId, rec) : null;
|
|
12149
12285
|
}
|
|
12150
|
-
function createApp({ store, webDist, account, push, approvals, goals, access = allowAll, extension, build }) {
|
|
12286
|
+
function createApp({ store, webDist, account, push, approvals, goals, entries, access = allowAll, extension, build }) {
|
|
12151
12287
|
const app = new Hono2();
|
|
12152
12288
|
const resolve2 = account ?? (() => LOCAL_ACCOUNT);
|
|
12153
12289
|
app.get("/api/health", (c) => c.json(build ? { ok: true, build } : { ok: true }));
|
|
@@ -12171,6 +12307,7 @@ function createApp({ store, webDist, account, push, approvals, goals, access = a
|
|
|
12171
12307
|
if (push) mountPush(app, push.store);
|
|
12172
12308
|
if (approvals) mountApprovals(app, approvals, access);
|
|
12173
12309
|
if (goals) mountGoals(app, goals, access);
|
|
12310
|
+
if (entries) mountEntries(app, entries, access);
|
|
12174
12311
|
app.post("/api/events", async (c) => {
|
|
12175
12312
|
let body;
|
|
12176
12313
|
try {
|
|
@@ -12264,10 +12401,16 @@ function createApp({ store, webDist, account, push, approvals, goals, access = a
|
|
|
12264
12401
|
queue.push(change);
|
|
12265
12402
|
wake?.();
|
|
12266
12403
|
});
|
|
12404
|
+
const offEntries = entries?.subscribe((change) => {
|
|
12405
|
+
if (change.accountId !== accountId) return;
|
|
12406
|
+
queue.push(change);
|
|
12407
|
+
wake?.();
|
|
12408
|
+
});
|
|
12267
12409
|
const unsubscribe = () => {
|
|
12268
12410
|
offSessions();
|
|
12269
12411
|
offApprovals?.();
|
|
12270
12412
|
offGoals?.();
|
|
12413
|
+
offEntries?.();
|
|
12271
12414
|
};
|
|
12272
12415
|
stream2.onAbort(() => {
|
|
12273
12416
|
unsubscribe();
|
|
@@ -12288,7 +12431,7 @@ function createApp({ store, webDist, account, push, approvals, goals, access = a
|
|
|
12288
12431
|
}
|
|
12289
12432
|
const change = queue.shift();
|
|
12290
12433
|
await stream2.writeSSE(
|
|
12291
|
-
change.type === "session" ? { event: "session", data: JSON.stringify(change.session) } : change.type === "approval" ? { event: "approval", data: JSON.stringify(change.approval) } : change.type === "goal" ? { event: "goal", data: JSON.stringify(change.goal) } : change.type === "goal-removed" ? { event: "goal-removed", data: JSON.stringify({ id: change.id }) } : { event: "removed", data: JSON.stringify({ key: change.key }) }
|
|
12434
|
+
change.type === "session" ? { event: "session", data: JSON.stringify(change.session) } : change.type === "approval" ? { event: "approval", data: JSON.stringify(change.approval) } : change.type === "goal" ? { event: "goal", data: JSON.stringify(change.goal) } : change.type === "goal-removed" ? { event: "goal-removed", data: JSON.stringify({ id: change.id }) } : change.type === "entry" ? { event: "entry", data: JSON.stringify(change.entry) } : change.type === "entry-removed" ? { event: "entry-removed", data: JSON.stringify({ id: change.id }) } : { event: "removed", data: JSON.stringify({ key: change.key }) }
|
|
12292
12435
|
);
|
|
12293
12436
|
}
|
|
12294
12437
|
unsubscribe();
|
|
@@ -12466,6 +12609,7 @@ function coreServices(store, access = allowAll) {
|
|
|
12466
12609
|
const pushStore = vapidPublic && vapidPrivate ? new PushStore(store.db) : void 0;
|
|
12467
12610
|
const approvals = new ApprovalStore(store.db);
|
|
12468
12611
|
const goals = new GoalStore(store.db);
|
|
12612
|
+
const entries = new EntryStore(store.db);
|
|
12469
12613
|
const offApprovalCleanup = closeApprovalsOnResume(store, approvals, logError("approval request cleanup"));
|
|
12470
12614
|
const notifier = pushStore ? startPushNotifier({
|
|
12471
12615
|
store,
|
|
@@ -12477,7 +12621,7 @@ function coreServices(store, access = allowAll) {
|
|
|
12477
12621
|
}) : void 0;
|
|
12478
12622
|
return {
|
|
12479
12623
|
/** Passed to createApp */
|
|
12480
|
-
app: { push: pushStore && { store: pushStore, publicKey: vapidPublic }, approvals, goals, access },
|
|
12624
|
+
app: { push: pushStore && { store: pushStore, publicKey: vapidPublic }, approvals, goals, entries, access },
|
|
12481
12625
|
approvals,
|
|
12482
12626
|
pushing: Boolean(notifier),
|
|
12483
12627
|
stop() {
|
package/dist/cli.mjs
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
unwrapMasterKey,
|
|
22
22
|
verifyPublicKey,
|
|
23
23
|
wrapMasterKey
|
|
24
|
-
} from "./chunks/chunk-
|
|
24
|
+
} from "./chunks/chunk-3QUAEA6A.mjs";
|
|
25
25
|
|
|
26
26
|
// ../src/index.ts
|
|
27
27
|
import { homedir as homedir2 } from "node:os";
|
|
@@ -453,7 +453,7 @@ async function logout() {
|
|
|
453
453
|
}
|
|
454
454
|
|
|
455
455
|
// ../src/update.ts
|
|
456
|
-
async function updateNotice(current = "0.1.
|
|
456
|
+
async function updateNotice(current = "0.1.17") {
|
|
457
457
|
const u = await checkCliUpdate(current);
|
|
458
458
|
return u && `${t("update.available", { ...u })}
|
|
459
459
|
${t("update.changelog")}`;
|
|
@@ -609,7 +609,7 @@ async function main(argv) {
|
|
|
609
609
|
if (String(typeof warning === "string" ? warning : warning.message).startsWith("SQLite is an experimental feature")) return;
|
|
610
610
|
emitWarning(warning, ...rest2);
|
|
611
611
|
});
|
|
612
|
-
const { startServer } = await import("./chunks/src-
|
|
612
|
+
const { startServer } = await import("./chunks/src-DWPF6JDY.mjs");
|
|
613
613
|
await startServer();
|
|
614
614
|
console.log(t("start.pair", { url: localPairUrl() }));
|
|
615
615
|
return;
|
|
@@ -631,7 +631,7 @@ async function main(argv) {
|
|
|
631
631
|
case "--version":
|
|
632
632
|
case "-v":
|
|
633
633
|
case "version":
|
|
634
|
-
console.log("0.1.
|
|
634
|
+
console.log("0.1.17");
|
|
635
635
|
return;
|
|
636
636
|
case "remote":
|
|
637
637
|
case "away":
|
package/package.json
CHANGED