@alashi/cli 0.10.0 → 0.12.0
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/dist/cli.mjs +50 -9
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +311 -29
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{store-VoJe_U1Q.mjs → store-BNZqhcwm.mjs} +739 -70
- package/dist/store-BNZqhcwm.mjs.map +1 -0
- package/package.json +3 -3
- package/templates/basic-app/AGENTS.md +3 -1
- package/templates/basic-app/index.mjs +1 -1
- package/templates/basic-app/package.json +1 -1
- package/dist/store-VoJe_U1Q.mjs.map +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AIProvider, AppContext, AppDefinition, AppManifest, AppSdkError, ConfigObject } from "@alashi/apps-sdk";
|
|
2
|
-
import { Hono } from "hono";
|
|
1
|
+
import { AIProvider, AppContext, AppDefinition, AppManifest, AppSdkError, ConfigObject, ModelTokenUsage } from "@alashi/apps-sdk";
|
|
2
|
+
import { Context, Hono, MiddlewareHandler } from "hono";
|
|
3
3
|
//#region src/sources.d.ts
|
|
4
4
|
type AppSourceSpec = {
|
|
5
5
|
type: "git";
|
|
@@ -33,11 +33,43 @@ interface AppBudget {
|
|
|
33
33
|
*/
|
|
34
34
|
dailyUsd: number;
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* How the host decides whether a request must be authenticated.
|
|
38
|
+
*
|
|
39
|
+
* - `auto` (default): requests that verifiably come from the local console
|
|
40
|
+
* (loopback peer, local Host header, no forwarding headers) are trusted as
|
|
41
|
+
* the owner; everything else must present a credential. Note the limit: a
|
|
42
|
+
* proxy that strips its forwarding headers and rewrites Host is
|
|
43
|
+
* indistinguishable from a local request — anyone deliberately exposing the
|
|
44
|
+
* host through a tunnel should set `required`.
|
|
45
|
+
* - `required`: every request needs a credential, even on localhost.
|
|
46
|
+
* - `off`: no authentication at all (current behavior; loopback binds only).
|
|
47
|
+
*/
|
|
48
|
+
type AuthMode = "auto" | "required" | "off";
|
|
49
|
+
/** Host auth settings (`config.auth`) — a host concern, never app config. */
|
|
50
|
+
interface AuthConfig {
|
|
51
|
+
mode?: AuthMode;
|
|
52
|
+
/**
|
|
53
|
+
* App names whose UI and API (`/app/<name>/*`) need no identity. A grant,
|
|
54
|
+
* so it lives here where only the host's owner can set it — an app manifest
|
|
55
|
+
* can never declare itself public.
|
|
56
|
+
*/
|
|
57
|
+
public?: string[];
|
|
58
|
+
/**
|
|
59
|
+
* Trust `Tailscale-User-*` identity headers (set by `tailscale serve`) as a
|
|
60
|
+
* signed-in user. Only enable when the host is reachable exclusively
|
|
61
|
+
* through Tailscale — the headers are plain text to anyone who can connect
|
|
62
|
+
* directly.
|
|
63
|
+
*/
|
|
64
|
+
trustTailscaleHeaders?: boolean;
|
|
65
|
+
}
|
|
36
66
|
interface GlobalConfig {
|
|
37
67
|
registries: RegistryRef[];
|
|
38
68
|
port?: number;
|
|
39
69
|
/** Bind address for `alashi serve`; defaults to loopback (the dashboard has no auth). */
|
|
40
70
|
host?: string;
|
|
71
|
+
/** Host authentication; absent means `mode: "auto"` with no public apps. */
|
|
72
|
+
auth?: AuthConfig;
|
|
41
73
|
/** Per-app global overrides, keyed by app name (middle config layer). */
|
|
42
74
|
apps?: Record<string, ConfigObject>;
|
|
43
75
|
/**
|
|
@@ -74,18 +106,64 @@ interface JobState {
|
|
|
74
106
|
lastRun: Record<string, string>;
|
|
75
107
|
runs: JobRun[];
|
|
76
108
|
}
|
|
109
|
+
/** Tokens and cost one model consumed within a usage bucket (a day or a month). */
|
|
110
|
+
interface ModelUsageTotals {
|
|
111
|
+
inputTokens: number;
|
|
112
|
+
outputTokens: number;
|
|
113
|
+
cacheReadInputTokens: number;
|
|
114
|
+
cacheCreationInputTokens: number;
|
|
115
|
+
costUsd: number;
|
|
116
|
+
}
|
|
77
117
|
/** One UTC day of AI spend for an app. */
|
|
78
118
|
interface UsageDay {
|
|
79
119
|
/** UTC calendar day, `YYYY-MM-DD`. */
|
|
80
120
|
date: string;
|
|
81
121
|
/** Sum of the `costUsd` the provider reported for that day's turns. */
|
|
82
122
|
costUsd: number;
|
|
83
|
-
/** Turns that reported
|
|
123
|
+
/** Turns that reported cost or token usage (turns without either are not counted). */
|
|
124
|
+
turns: number;
|
|
125
|
+
/** Per-model token/cost totals, keyed by the engine's model id. Absent for days recorded before token metering. */
|
|
126
|
+
models?: Record<string, ModelUsageTotals>;
|
|
127
|
+
}
|
|
128
|
+
/** One UTC calendar month of AI spend; months are never pruned. */
|
|
129
|
+
interface UsageMonth {
|
|
130
|
+
/** UTC calendar month, `YYYY-MM`. */
|
|
131
|
+
month: string;
|
|
132
|
+
costUsd: number;
|
|
84
133
|
turns: number;
|
|
134
|
+
models?: Record<string, ModelUsageTotals>;
|
|
85
135
|
}
|
|
86
|
-
/**
|
|
136
|
+
/**
|
|
137
|
+
* Host-side AI spend for an app: daily series (oldest first, trimmed to the
|
|
138
|
+
* retention window) plus monthly rollups that survive daily pruning so
|
|
139
|
+
* long-term trends remain visible. `months` is absent only in files written
|
|
140
|
+
* before rollups existed; the recorder backfills it from `days` on first touch.
|
|
141
|
+
*/
|
|
87
142
|
interface UsageState {
|
|
88
143
|
days: UsageDay[];
|
|
144
|
+
months?: UsageMonth[];
|
|
145
|
+
}
|
|
146
|
+
/** A long-lived bearer credential; only the sha256 of the secret is stored. */
|
|
147
|
+
interface AuthTokenRecord {
|
|
148
|
+
id: string;
|
|
149
|
+
label?: string;
|
|
150
|
+
hash: string;
|
|
151
|
+
createdAt: string;
|
|
152
|
+
lastUsedAt?: string;
|
|
153
|
+
}
|
|
154
|
+
/** A browser session; only the sha256 of the cookie value is stored. */
|
|
155
|
+
interface AuthSessionRecord {
|
|
156
|
+
hash: string;
|
|
157
|
+
/** Display name for attribution (token label, tailscale login, or "owner"). */
|
|
158
|
+
name: string;
|
|
159
|
+
level: "owner" | "user";
|
|
160
|
+
createdAt: string;
|
|
161
|
+
expiresAt: string;
|
|
162
|
+
}
|
|
163
|
+
/** Host auth state (`auth.json` at the store root — OS bookkeeping, not app state). */
|
|
164
|
+
interface AuthState {
|
|
165
|
+
tokens: AuthTokenRecord[];
|
|
166
|
+
sessions: AuthSessionRecord[];
|
|
89
167
|
}
|
|
90
168
|
interface InstallRecord {
|
|
91
169
|
name: string;
|
|
@@ -130,9 +208,123 @@ declare class Store {
|
|
|
130
208
|
writeJobState(name: string, state: JobState): Promise<void>;
|
|
131
209
|
readUsageState(name: string): Promise<UsageState>;
|
|
132
210
|
writeUsageState(name: string, state: UsageState): Promise<void>;
|
|
211
|
+
get authStatePath(): string;
|
|
212
|
+
readAuthState(): Promise<AuthState>;
|
|
213
|
+
writeAuthState(state: AuthState): Promise<void>;
|
|
133
214
|
listInstalled(): Promise<InstallRecord[]>;
|
|
134
215
|
}
|
|
135
216
|
//#endregion
|
|
217
|
+
//#region src/auth.d.ts
|
|
218
|
+
declare const SESSION_COOKIE = "alashi_session";
|
|
219
|
+
/** Who a request is, once a credential (or the console heuristic) vouched for it. */
|
|
220
|
+
interface Identity {
|
|
221
|
+
level: "owner" | "user";
|
|
222
|
+
via: "console" | "boot" | "token" | "session" | "tailscale" | "off";
|
|
223
|
+
/** Display name for attribution: token label, tailscale login, or "owner". */
|
|
224
|
+
name: string;
|
|
225
|
+
}
|
|
226
|
+
/** What a route demands. `user` is any signed-in identity; `owner` outranks it. */
|
|
227
|
+
type AccessLevel = "public" | "user" | "owner";
|
|
228
|
+
declare module "hono" {
|
|
229
|
+
interface ContextVariableMap {
|
|
230
|
+
identity?: Identity;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* The console heuristic: is this request verifiably from the local machine?
|
|
235
|
+
*
|
|
236
|
+
* Requires all three of: a loopback peer address, a local request hostname,
|
|
237
|
+
* and no forwarding headers — because tunnels (ngrok, cloudflared, `tailscale
|
|
238
|
+
* serve`) connect from loopback too, and what gives them away is the forwarded
|
|
239
|
+
* hostname or the forwarding headers they add. A proxy configured to strip
|
|
240
|
+
* both is indistinguishable from a local request; `mode: "required"` exists
|
|
241
|
+
* for anyone deliberately exposing the host.
|
|
242
|
+
*
|
|
243
|
+
* `hostname` is the request URL's hostname (which the server derives from the
|
|
244
|
+
* Host header) rather than the raw header, because in-process requests carry
|
|
245
|
+
* no Host header at all. `remoteAddress === undefined` means an in-process
|
|
246
|
+
* request (tests, the host calling itself) — there is no socket, so it is by
|
|
247
|
+
* definition local.
|
|
248
|
+
*/
|
|
249
|
+
declare function isConsoleRequest(hostname: string, headers: {
|
|
250
|
+
get(name: string): string | null;
|
|
251
|
+
}, remoteAddress: string | undefined): boolean;
|
|
252
|
+
/**
|
|
253
|
+
* The access level a path demands. Deny-by-default shape: everything is at
|
|
254
|
+
* least `user` unless it is explicitly public, and the routes that change
|
|
255
|
+
* host state or spend-relevant settings (config, budgets, manual job runs)
|
|
256
|
+
* are `owner`.
|
|
257
|
+
*/
|
|
258
|
+
declare function requiredLevel(path: string, publicApps: readonly string[]): AccessLevel;
|
|
259
|
+
/** Public shape of a token for `alashi token list` — never includes the hash. */
|
|
260
|
+
interface TokenInfo {
|
|
261
|
+
id: string;
|
|
262
|
+
label?: string;
|
|
263
|
+
createdAt: string;
|
|
264
|
+
lastUsedAt?: string;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Host authentication: bearer tokens and browser sessions persisted in
|
|
268
|
+
* `auth.json` (hashes only), plus an in-memory one-time boot login token.
|
|
269
|
+
* Writes are serialized so concurrent logins cannot lose each other's update.
|
|
270
|
+
*/
|
|
271
|
+
declare class AuthService {
|
|
272
|
+
private readonly store;
|
|
273
|
+
private queue;
|
|
274
|
+
private bootHash;
|
|
275
|
+
constructor(store: Store);
|
|
276
|
+
/**
|
|
277
|
+
* Mints the one-time login secret printed at serve startup. In-memory only
|
|
278
|
+
* and consumed by the first successful login; restart the host (or mint a
|
|
279
|
+
* real token) to get another.
|
|
280
|
+
*/
|
|
281
|
+
issueBootToken(): string;
|
|
282
|
+
/** Creates a persistent owner bearer token; the secret is only returned here. */
|
|
283
|
+
mintToken(label?: string): Promise<{
|
|
284
|
+
id: string;
|
|
285
|
+
secret: string;
|
|
286
|
+
}>;
|
|
287
|
+
listTokens(): Promise<TokenInfo[]>;
|
|
288
|
+
/** Revokes a token and every session it created is left alone: sessions expire on their own. */
|
|
289
|
+
revokeToken(id: string): Promise<boolean>;
|
|
290
|
+
/**
|
|
291
|
+
* Exchanges a login secret (boot token or minted token) for an identity.
|
|
292
|
+
* A boot token is consumed by success; minted tokens are reusable.
|
|
293
|
+
*/
|
|
294
|
+
redeemLoginSecret(secret: string): Promise<Identity | undefined>;
|
|
295
|
+
/** Resolves `Authorization: Bearer <secret>`; undefined when absent or invalid. */
|
|
296
|
+
bearerIdentity(authorization: string | undefined): Promise<Identity | undefined>;
|
|
297
|
+
private tokenIdentity;
|
|
298
|
+
/** Creates a session for an already-verified identity; returns the cookie value. */
|
|
299
|
+
createSession(identity: Identity, at?: Date): Promise<string>;
|
|
300
|
+
/** Resolves a session cookie value; undefined when unknown or expired. */
|
|
301
|
+
sessionIdentity(value: string | undefined, at?: Date): Promise<Identity | undefined>;
|
|
302
|
+
/** Deletes the session behind a cookie value (logout). */
|
|
303
|
+
destroySession(value: string): Promise<void>;
|
|
304
|
+
/** Read-modify-write of auth.json, serialized, with expired sessions pruned. */
|
|
305
|
+
private mutate;
|
|
306
|
+
}
|
|
307
|
+
/** How the middleware learns the peer address; injectable for tests. */
|
|
308
|
+
type RemoteAddressResolver = (c: Context) => string | undefined;
|
|
309
|
+
interface AuthMiddlewareOptions {
|
|
310
|
+
getRemoteAddress?: RemoteAddressResolver;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* The host's front door. Resolves an identity for every request (bearer token,
|
|
314
|
+
* session cookie, tailscale headers, console heuristic — in that order) and
|
|
315
|
+
* enforces the path's required level. Auth config is read per request so
|
|
316
|
+
* settings changes apply without a restart.
|
|
317
|
+
*/
|
|
318
|
+
declare function createAuthMiddleware(store: Store, auth: AuthService, options?: AuthMiddlewareOptions): MiddlewareHandler;
|
|
319
|
+
/**
|
|
320
|
+
* The auth surface itself (all public in the policy map):
|
|
321
|
+
* GET /login login form; `?token=` redeems the printed one-time URL
|
|
322
|
+
* POST /login { token } (form-encoded) -> session cookie + redirect /
|
|
323
|
+
* GET /logout destroys the session, back to /login
|
|
324
|
+
* GET /api/me the resolved identity, or { identity: null }
|
|
325
|
+
*/
|
|
326
|
+
declare function registerAuthRoutes(app: Hono, auth: AuthService): void;
|
|
327
|
+
//#endregion
|
|
136
328
|
//#region src/usage.d.ts
|
|
137
329
|
/** Days of history kept in usage.json; older days are dropped on write. */
|
|
138
330
|
declare const USAGE_RETENTION_DAYS = 90;
|
|
@@ -140,6 +332,12 @@ declare const USAGE_RETENTION_DAYS = 90;
|
|
|
140
332
|
declare function utcDay(at?: Date): string;
|
|
141
333
|
/** Money for humans: sub-dollar spend needs the extra digits, larger sums don't. */
|
|
142
334
|
declare function formatUsd(value: number): string;
|
|
335
|
+
/** One turn's metering as reported by the engine; either part may be missing. */
|
|
336
|
+
interface TurnUsage {
|
|
337
|
+
costUsd?: number;
|
|
338
|
+
/** Per-turn token/cost deltas keyed by model id (provider-neutral). */
|
|
339
|
+
modelUsage?: Record<string, ModelTokenUsage>;
|
|
340
|
+
}
|
|
143
341
|
/** A summary of an app's recorded spend, as served by GET /api/apps/:name/usage. */
|
|
144
342
|
interface UsageSummary {
|
|
145
343
|
/** The UTC day "today" refers to. */
|
|
@@ -148,22 +346,39 @@ interface UsageSummary {
|
|
|
148
346
|
todayCostUsd: number;
|
|
149
347
|
/** Turns recorded so far today. */
|
|
150
348
|
todayTurns: number;
|
|
349
|
+
/** Per-model tokens/cost recorded so far today. */
|
|
350
|
+
todayModels: Record<string, ModelUsageTotals>;
|
|
151
351
|
/** Spend across the whole retention window. */
|
|
152
352
|
totalCostUsd: number;
|
|
353
|
+
/** Per-model tokens/cost across the whole retention window. */
|
|
354
|
+
models: Record<string, ModelUsageTotals>;
|
|
153
355
|
/** Days kept in the retention window. */
|
|
154
356
|
retentionDays: number;
|
|
357
|
+
/**
|
|
358
|
+
* Whether the host has ever metered a turn for this app (monthly rollups
|
|
359
|
+
* persist, so this survives the daily retention window). False means "no
|
|
360
|
+
* data at all" — which is not the same thing as a measured zero, and must
|
|
361
|
+
* not be rendered as `$0.0000`. The host meters only sessions an app opens
|
|
362
|
+
* through `ctx.ai`, so an app that tracks its own costs elsewhere can be
|
|
363
|
+
* unrecorded here while still reporting real spend of its own.
|
|
364
|
+
*/
|
|
365
|
+
recorded: boolean;
|
|
155
366
|
/** Daily series, oldest first; days with no spend are absent. */
|
|
156
367
|
days: UsageDay[];
|
|
368
|
+
/** Monthly rollups, oldest first; never pruned, so trends outlive the daily window. */
|
|
369
|
+
months: UsageMonth[];
|
|
157
370
|
}
|
|
158
371
|
/**
|
|
159
|
-
* Per-app
|
|
160
|
-
* container (`apps/<name>/usage.json`, next to jobs.json and chat.json)
|
|
372
|
+
* Per-app AI spend and token usage, persisted as OS bookkeeping in the app
|
|
373
|
+
* container (`apps/<name>/usage.json`, next to jobs.json and chat.json):
|
|
374
|
+
* a per-UTC-day series trimmed to the retention window, plus per-month
|
|
375
|
+
* rollups that are kept forever.
|
|
161
376
|
*
|
|
162
|
-
* Cost
|
|
163
|
-
* marks optional: engines that
|
|
164
|
-
* Writes are serialized per app so concurrent turns cannot lose an
|
|
165
|
-
* and each app has its own queue so a slow write for one app never
|
|
166
|
-
* another.
|
|
377
|
+
* Cost and per-model tokens arrive from the `result` event, whose fields the
|
|
378
|
+
* SDK contract marks optional: engines that report neither simply contribute
|
|
379
|
+
* nothing. Writes are serialized per app so concurrent turns cannot lose an
|
|
380
|
+
* update, and each app has its own queue so a slow write for one app never
|
|
381
|
+
* delays another.
|
|
167
382
|
*/
|
|
168
383
|
declare class UsageRecorder {
|
|
169
384
|
private readonly store;
|
|
@@ -172,16 +387,26 @@ declare class UsageRecorder {
|
|
|
172
387
|
private readonly queues;
|
|
173
388
|
constructor(store: Store, retentionDays?: number);
|
|
174
389
|
/**
|
|
175
|
-
* Adds one turn's cost to the app's
|
|
176
|
-
* A missing, non-finite, or negative `costUsd` is
|
|
177
|
-
*
|
|
390
|
+
* Adds one turn's cost and token usage to the app's totals for the UTC day
|
|
391
|
+
* and month of `at`. A missing, non-finite, or negative `costUsd` is
|
|
392
|
+
* ignored; a turn that reports neither valid cost nor any model usage is
|
|
393
|
+
* not counted and nothing is written, so a provider that omits metering
|
|
394
|
+
* cannot corrupt the totals.
|
|
178
395
|
*/
|
|
179
|
-
record(appName: string,
|
|
180
|
-
/** The app's recorded
|
|
181
|
-
read(appName: string, at?: Date): Promise<UsageState
|
|
182
|
-
/** Today's spend plus the daily series, for the dashboard and the usage
|
|
396
|
+
record(appName: string, turn: TurnUsage, at?: Date): Promise<void>;
|
|
397
|
+
/** The app's recorded usage, oldest first, with expired days filtered out. */
|
|
398
|
+
read(appName: string, at?: Date): Promise<Required<UsageState>>;
|
|
399
|
+
/** Today's spend plus the daily/monthly series, for the dashboard and the usage endpoints. */
|
|
183
400
|
summary(appName: string, at?: Date): Promise<UsageSummary>;
|
|
184
|
-
|
|
401
|
+
private apply;
|
|
402
|
+
/**
|
|
403
|
+
* One-time migration for files written before monthly rollups existed:
|
|
404
|
+
* absent `months` is seeded from the surviving days, so history inside the
|
|
405
|
+
* retention window is not lost to the rollups. After the first write the
|
|
406
|
+
* field is always present (possibly empty) and this is a no-op.
|
|
407
|
+
*/
|
|
408
|
+
private normalize;
|
|
409
|
+
/** Drops days outside the retention window and normalizes ordering/values. Months are kept forever. */
|
|
185
410
|
private prune;
|
|
186
411
|
private enqueue;
|
|
187
412
|
}
|
|
@@ -199,6 +424,12 @@ interface BudgetStatus {
|
|
|
199
424
|
date: string;
|
|
200
425
|
/** Spend recorded for that day. */
|
|
201
426
|
spentUsd: number;
|
|
427
|
+
/**
|
|
428
|
+
* Whether the host has any metered history for this app at all. When false,
|
|
429
|
+
* `spentUsd` is an absence of data rather than a measured zero, and should be
|
|
430
|
+
* rendered as such — never as `$0.0000`.
|
|
431
|
+
*/
|
|
432
|
+
recorded: boolean;
|
|
202
433
|
/** The configured daily cap; absent when the app has none. */
|
|
203
434
|
dailyUsd?: number;
|
|
204
435
|
/** Spend left before sessions are refused; absent when there is no cap. */
|
|
@@ -275,13 +506,24 @@ interface InstallOptions {
|
|
|
275
506
|
/** Expected app name (enforced against the manifest when set). */
|
|
276
507
|
expectName?: string;
|
|
277
508
|
}
|
|
509
|
+
/**
|
|
510
|
+
* What an install or update produced: the record that was persisted, plus the
|
|
511
|
+
* manifest warnings from loading the app. Warnings are deliberately *not* part
|
|
512
|
+
* of {@link InstallRecord} — they describe this host's SDK, not the app, and
|
|
513
|
+
* go stale the moment the host is upgraded.
|
|
514
|
+
*/
|
|
515
|
+
interface InstallResult {
|
|
516
|
+
record: InstallRecord;
|
|
517
|
+
/** Manifest keys this host's SDK ignored; never a reason to fail the command. */
|
|
518
|
+
warnings: string[];
|
|
519
|
+
}
|
|
278
520
|
/**
|
|
279
521
|
* Install flow: materialize the source into a staging dir, install deps
|
|
280
522
|
* (scripts disabled), import + validate the manifest, and only then move
|
|
281
523
|
* it into apps/<name>/repo. A failed validation never leaves a broken app.
|
|
282
524
|
*/
|
|
283
|
-
declare function installApp(store: Store, source: string | AppSourceSpec, options?: InstallOptions): Promise<
|
|
284
|
-
declare function updateApp(store: Store, name: string): Promise<
|
|
525
|
+
declare function installApp(store: Store, source: string | AppSourceSpec, options?: InstallOptions): Promise<InstallResult>;
|
|
526
|
+
declare function updateApp(store: Store, name: string): Promise<InstallResult>;
|
|
285
527
|
interface RemoveOptions {
|
|
286
528
|
/** Also delete the app's data/ and config (default keeps them). */
|
|
287
529
|
purge?: boolean;
|
|
@@ -293,13 +535,28 @@ interface LoadedApp {
|
|
|
293
535
|
definition: AppDefinition;
|
|
294
536
|
manifest: AppManifest;
|
|
295
537
|
entryPath: string;
|
|
538
|
+
/**
|
|
539
|
+
* One human-readable line per manifest key this host's SDK did not
|
|
540
|
+
* recognize and therefore dropped from {@link LoadedApp.manifest}. Never a
|
|
541
|
+
* reason to refuse the app: only `sdkVersion` decides version skew.
|
|
542
|
+
*/
|
|
543
|
+
warnings: string[];
|
|
544
|
+
}
|
|
545
|
+
interface LoadAppOptions {
|
|
546
|
+
/**
|
|
547
|
+
* Where manifest warnings go. Defaults to `console.warn`, prefixed with the
|
|
548
|
+
* app name — `getApp` in server.ts caches loads, so that is once per load,
|
|
549
|
+
* not once per request. Callers that surface the warnings themselves (the
|
|
550
|
+
* CLI on install/update) pass their own sink to avoid printing twice.
|
|
551
|
+
*/
|
|
552
|
+
warn?: (message: string) => void;
|
|
296
553
|
}
|
|
297
554
|
/**
|
|
298
555
|
* Imports an app's entry module and validates its default export.
|
|
299
556
|
* The manifest is always re-validated here — the host never trusts
|
|
300
557
|
* that an app used defineApp().
|
|
301
558
|
*/
|
|
302
|
-
declare function loadApp(repoDir: string): Promise<LoadedApp>;
|
|
559
|
+
declare function loadApp(repoDir: string, options?: LoadAppOptions): Promise<LoadedApp>;
|
|
303
560
|
//#endregion
|
|
304
561
|
//#region src/portability.d.ts
|
|
305
562
|
/**
|
|
@@ -439,18 +696,43 @@ interface AppServer {
|
|
|
439
696
|
app: Hono;
|
|
440
697
|
/** Cron scheduler for manifest-declared jobs; call start() to begin firing. */
|
|
441
698
|
scheduler: Scheduler;
|
|
699
|
+
/** Host auth: the CLI uses it to issue the boot login token and mint bearer tokens. */
|
|
700
|
+
auth: AuthService;
|
|
442
701
|
/** Stops the scheduler and closes all warm AI sessions. */
|
|
443
702
|
close(): Promise<void>;
|
|
444
703
|
}
|
|
704
|
+
interface ServerOptions {
|
|
705
|
+
/** Host auth service; created internally when not supplied. */
|
|
706
|
+
auth?: AuthService;
|
|
707
|
+
/**
|
|
708
|
+
* How the auth middleware learns the peer address. Defaults to
|
|
709
|
+
* @hono/node-server's conninfo; in-process requests (tests) have no socket
|
|
710
|
+
* and resolve to undefined, which the console heuristic treats as local.
|
|
711
|
+
*/
|
|
712
|
+
getRemoteAddress?: RemoteAddressResolver;
|
|
713
|
+
}
|
|
445
714
|
/**
|
|
446
|
-
* The host HTTP surface
|
|
715
|
+
* The host HTTP surface (all routes sit behind the auth policy middleware —
|
|
716
|
+
* see auth.ts: public/user/owner levels, config-driven via config.auth):
|
|
717
|
+
* GET /login sign-in form; ?token= redeems a printed login URL
|
|
718
|
+
* POST /login { token } form -> session cookie
|
|
719
|
+
* GET /logout destroy the session
|
|
720
|
+
* GET /api/me the request's resolved identity, or null
|
|
447
721
|
* GET / dashboard of installed apps
|
|
448
722
|
* GET /settings/:name per-app settings page (config form)
|
|
449
|
-
* GET /api/apps installed apps as JSON, each with todayCostUsd
|
|
450
|
-
*
|
|
723
|
+
* GET /api/apps installed apps as JSON, each with todayCostUsd,
|
|
724
|
+
* `recorded` (false when the host has never metered
|
|
725
|
+
* the app, so todayCostUsd is an absence rather than
|
|
726
|
+
* a measured zero), and its daily spend cap /
|
|
727
|
+
* over-budget state
|
|
728
|
+
* GET /api/usage host-wide usage: per-app summaries (cost, turns,
|
|
729
|
+
* per-model tokens, daily series, monthly rollups)
|
|
730
|
+
* plus combined totals across apps
|
|
451
731
|
* GET /api/apps/:name/usage recorded AI spend: today's total, a daily series,
|
|
452
|
-
*
|
|
453
|
-
*
|
|
732
|
+
* per-model token totals, monthly rollups,
|
|
733
|
+
* `recorded`, and the budget status
|
|
734
|
+
* GET /api/apps/:name/budget today's spend against the app's daily cap,
|
|
735
|
+
* plus `recorded`
|
|
454
736
|
* PUT /api/apps/:name/budget { dailyUsd: number | null } -> set or clear the cap
|
|
455
737
|
* (a host setting; apps cannot set their own)
|
|
456
738
|
* POST /api/apps/:name/chat { message, conversationId? } -> SSE stream of AgentEvents
|
|
@@ -476,7 +758,7 @@ interface AppServer {
|
|
|
476
758
|
* otherwise the app's fetch handler (/app/:name stripped),
|
|
477
759
|
* otherwise 404
|
|
478
760
|
*/
|
|
479
|
-
declare function createServer(store: Store, provider: AIProvider): AppServer;
|
|
761
|
+
declare function createServer(store: Store, provider: AIProvider, options?: ServerOptions): AppServer;
|
|
480
762
|
//#endregion
|
|
481
|
-
export { type AppBudget, type AppServer, type AppSourceSpec, BUDGET_EXCEEDED_CODE, BudgetExceededError, type BudgetStatus, EXPORT_FORMAT_VERSION, type ExportMetadata, type ExportOptions, type ExportResult, type GlobalConfig, type ImportResult, type InstallOptions, type InstallRecord, type LoadedApp, type RegistryApp, type RegistryIndex, type RegistryRef, type RemoveOptions, type ResolvedApp, type SourceArg, Store, USAGE_RETENTION_DAYS, type UsageDay, UsageRecorder, type UsageState, type UsageSummary, addRegistry, appBudget, assertWithinBudget, budgetStatus, budgetStatusFor, buildAppContext, checkSdkCompatibility, createServer, exportApp, fetchSource, formatUsd, importApp, installApp, installDependencies, loadApp, parseSourceArg, readCachedIndex, refreshRegistry, removeApp, removeRegistry, resolveApp, setAppBudget, updateApp, updateSource, utcDay };
|
|
763
|
+
export { type AccessLevel, type AppBudget, type AppServer, type AppSourceSpec, type AuthConfig, type AuthMode, AuthService, type AuthState, BUDGET_EXCEEDED_CODE, BudgetExceededError, type BudgetStatus, EXPORT_FORMAT_VERSION, type ExportMetadata, type ExportOptions, type ExportResult, type GlobalConfig, type Identity, type ImportResult, type InstallOptions, type InstallRecord, type InstallResult, type LoadAppOptions, type LoadedApp, type RegistryApp, type RegistryIndex, type RegistryRef, type RemoveOptions, type ResolvedApp, SESSION_COOKIE, type ServerOptions, type SourceArg, Store, type TokenInfo, USAGE_RETENTION_DAYS, type UsageDay, UsageRecorder, type UsageState, type UsageSummary, addRegistry, appBudget, assertWithinBudget, budgetStatus, budgetStatusFor, buildAppContext, checkSdkCompatibility, createAuthMiddleware, createServer, exportApp, fetchSource, formatUsd, importApp, installApp, installDependencies, isConsoleRequest, loadApp, parseSourceArg, readCachedIndex, refreshRegistry, registerAuthRoutes, removeApp, removeRegistry, requiredLevel, resolveApp, setAppBudget, updateApp, updateSource, utcDay };
|
|
482
764
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/sources.ts","../src/store.ts","../src/usage.ts","../src/budget.ts","../src/compat.ts","../src/installer.ts","../src/loader.ts","../src/portability.ts","../src/registry.ts","../src/runtime.ts","../src/scheduler.ts","../src/server.ts"],"mappings":";;;KAQY;EACN;EAAa;EAAa;;EAC1B;EAAe;;;KAGT,YAAY;EAAkB;EAAkB;;iBAE5C,eAAe,cAAc;;iBAwBvB,YAAY,MAAM,eAAe,kBAAkB;;iBAanD,aAAa,MAAM,eAAe,kBAAkB;;;UC9CzD;EACf;EACA;;;UAIe;;;;;EAKf;;UAGe;EACf,YAAY;EACZ;;EAEA;;EAEA,OAAO,eAAe;;;;;;;;;EAStB,UAAU,eAAe;;UAGV;EACf;;EAEA;EACA;EACA;;;UAIe;EACf,eAAe;;UAGA;EACf;EACA;EACA;EACA;EACA;EACA;;;UAIe;EACf,SAAS;EACT,MAAM;;;UAIS;;EAEf;;EAEA;;EAEA;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/sources.ts","../src/store.ts","../src/auth.ts","../src/usage.ts","../src/budget.ts","../src/compat.ts","../src/installer.ts","../src/loader.ts","../src/portability.ts","../src/registry.ts","../src/runtime.ts","../src/scheduler.ts","../src/server.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as UsageRecorder, C as BudgetExceededError, D as budgetStatusFor, E as budgetStatus, M as utcDay, O as setAppBudget, S as BUDGET_EXCEEDED_CODE, T as assertWithinBudget, _ as fetchSource, a as EXPORT_FORMAT_VERSION, b as loadApp, c as installApp, d as updateApp, f as addRegistry, g as resolveApp, h as removeRegistry, j as formatUsd, k as USAGE_RETENTION_DAYS, l as installDependencies, m as refreshRegistry, n as createServer, o as exportApp, p as readCachedIndex, r as buildAppContext, s as importApp, t as Store, u as removeApp, v as parseSourceArg, w as appBudget, x as checkSdkCompatibility, y as updateSource } from "./store-
|
|
2
|
-
export { BUDGET_EXCEEDED_CODE, BudgetExceededError, EXPORT_FORMAT_VERSION, Store, USAGE_RETENTION_DAYS, UsageRecorder, addRegistry, appBudget, assertWithinBudget, budgetStatus, budgetStatusFor, buildAppContext, checkSdkCompatibility, createServer, exportApp, fetchSource, formatUsd, importApp, installApp, installDependencies, loadApp, parseSourceArg, readCachedIndex, refreshRegistry, removeApp, removeRegistry, resolveApp, setAppBudget, updateApp, updateSource, utcDay };
|
|
1
|
+
import { A as UsageRecorder, C as BudgetExceededError, D as budgetStatusFor, E as budgetStatus, F as createAuthMiddleware, I as isConsoleRequest, L as registerAuthRoutes, M as utcDay, N as AuthService, O as setAppBudget, P as SESSION_COOKIE, R as requiredLevel, S as BUDGET_EXCEEDED_CODE, T as assertWithinBudget, _ as fetchSource, a as EXPORT_FORMAT_VERSION, b as loadApp, c as installApp, d as updateApp, f as addRegistry, g as resolveApp, h as removeRegistry, j as formatUsd, k as USAGE_RETENTION_DAYS, l as installDependencies, m as refreshRegistry, n as createServer, o as exportApp, p as readCachedIndex, r as buildAppContext, s as importApp, t as Store, u as removeApp, v as parseSourceArg, w as appBudget, x as checkSdkCompatibility, y as updateSource } from "./store-BNZqhcwm.mjs";
|
|
2
|
+
export { AuthService, BUDGET_EXCEEDED_CODE, BudgetExceededError, EXPORT_FORMAT_VERSION, SESSION_COOKIE, Store, USAGE_RETENTION_DAYS, UsageRecorder, addRegistry, appBudget, assertWithinBudget, budgetStatus, budgetStatusFor, buildAppContext, checkSdkCompatibility, createAuthMiddleware, createServer, exportApp, fetchSource, formatUsd, importApp, installApp, installDependencies, isConsoleRequest, loadApp, parseSourceArg, readCachedIndex, refreshRegistry, registerAuthRoutes, removeApp, removeRegistry, requiredLevel, resolveApp, setAppBudget, updateApp, updateSource, utcDay };
|