@fugood/buttress-server 2.26.0-beta.1 → 2.26.0-beta.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.
@@ -1,6 +1,7 @@
1
1
  import type { Backend } from '../index';
2
2
  import type { Config } from '../types';
3
3
  import type { VerifiedIdentity } from '../utils/buttressAuth';
4
+ import type { WorkspaceState } from '../utils/workspaceState';
4
5
  /**
5
6
  * Declarative metadata a local function file exports alongside its handler.
6
7
  *
@@ -12,6 +13,23 @@ export type FunctionMeta = {
12
13
  parameters?: Record<string, any>;
13
14
  /** Per-function deadline. Number of ms, or an `ms()` string like "10m". */
14
15
  timeout?: number | string;
16
+ /**
17
+ * `true` declares the file as a daemon: a long-lived background function.
18
+ * Its default export runs once, with a `DaemonContext`, and stays alive —
19
+ * timers (`context.setInterval`), Data Bank subscriptions
20
+ * (`context.bank.subscribe`) and event handlers (`context.onEvent`) keep
21
+ * firing until the file changes or the server stops. Daemon files are not
22
+ * exposed as MCP tools or callable endpoints, and `timeout` does not apply
23
+ * to them.
24
+ */
25
+ daemon?: boolean;
26
+ };
27
+ /** An event another local function sent via `context.daemons.emit`. */
28
+ export type DaemonEmittedEvent = {
29
+ event: string;
30
+ data?: unknown;
31
+ /** Name of the local function (or daemon) that emitted it. */
32
+ source: string;
15
33
  };
16
34
  export type FunctionEmit = (event: string, data?: unknown) => void;
17
35
  export type SpawnOptions = {
@@ -102,6 +120,72 @@ export type SynthesizeResult = {
102
120
  sampling_rate: number;
103
121
  channels: number;
104
122
  };
123
+ /** 'InSubspace' scopes a property to the space; 'Global' is cross-application. */
124
+ export type BankPropertyMeta = 'InSubspace' | 'Global';
125
+ export type BankProperty = {
126
+ propertyId: string;
127
+ meta: BankPropertyMeta;
128
+ definition: Record<string, any> | null;
129
+ value: any;
130
+ tags: string[] | null;
131
+ lastUpdateHash: string | null;
132
+ lastUpdateNote: string | null;
133
+ lastUpdateKey: string | null;
134
+ createAt: string | null;
135
+ updateAt: string | null;
136
+ };
137
+ export type BankListOptions = {
138
+ /** Match against definition title/description or tags. */
139
+ keyword?: string;
140
+ meta?: BankPropertyMeta;
141
+ /** Restrict to these property ids. */
142
+ ids?: string[];
143
+ };
144
+ /**
145
+ * The Bank replaces `value` unconditionally on update — an omitted `value`
146
+ * clears the stored one. Read-merge first when a partial update is intended.
147
+ */
148
+ export type BankPropertyInput = {
149
+ propertyId: string;
150
+ /** Defaults to 'InSubspace'. */
151
+ meta?: BankPropertyMeta;
152
+ definition?: Record<string, any>;
153
+ newDefinitionFallback?: Record<string, any>;
154
+ value?: any;
155
+ updateNote?: string;
156
+ /** Bank defaults upsert to true; pass false to require an existing property. */
157
+ upsert?: boolean;
158
+ tags?: string[];
159
+ };
160
+ export type BankUpdateOptions = {
161
+ /** Skip notifying subscribed devices about this update. */
162
+ dontNotify?: boolean;
163
+ };
164
+ /** A live Data Bank change subscription (daemon functions only). */
165
+ export type BankSubscriptionHandle = {
166
+ close: () => void;
167
+ };
168
+ /** Remote Data Bank access for the bound workspace. */
169
+ export type BankContext = {
170
+ list: (options?: BankListOptions) => Promise<BankProperty[]>;
171
+ /** Null when the property does not exist. */
172
+ get: (propertyId: string) => Promise<BankProperty | null>;
173
+ update: (properties: BankPropertyInput[], options?: BankUpdateOptions) => Promise<BankProperty[]>;
174
+ remove: (propertyId: string) => Promise<boolean>;
175
+ /**
176
+ * Watch property ids for remote changes. Only available inside daemon
177
+ * functions — a call-scoped function has no lifetime to attach it to.
178
+ * Closed automatically when the daemon stops.
179
+ */
180
+ subscribe: (propertyIds: string[], onChange: (properties: BankProperty[]) => void) => BankSubscriptionHandle;
181
+ };
182
+ /** What the executor needs to route `context.daemons` calls. */
183
+ export type DaemonsHub = {
184
+ /** Enqueue an `event` invocation on a running daemon; throws when unknown. */
185
+ emit: (name: string, event: string, data: unknown, source: string) => void;
186
+ /** Names of the daemons currently running. */
187
+ names: () => string[];
188
+ };
105
189
  /** The second argument every local function handler receives. */
106
190
  export type FunctionContext = {
107
191
  spawn: (command: string, args?: string[], options?: SpawnOptions) => Promise<SpawnResult>;
@@ -114,6 +198,18 @@ export type FunctionContext = {
114
198
  transcribe: (options: TranscribeOptions) => Promise<any>;
115
199
  synthesize: (options: SynthesizeOptions) => Promise<SynthesizeResult>;
116
200
  };
201
+ /**
202
+ * Workspace Data Bank (read/write, v1 — no subscribe). Every method throws
203
+ * until credentials are stored via `bricks buttress bank-key`.
204
+ */
205
+ bank: BankContext;
206
+ /** Signal running daemon functions from any local function (or daemon). */
207
+ daemons: {
208
+ /** Deliver an event to the named daemon. Throws when it is not running. */
209
+ emit: (name: string, event: string, data?: unknown) => void;
210
+ /** Names of the daemons currently running. */
211
+ list: () => string[];
212
+ };
117
213
  fetch: typeof fetch;
118
214
  log: (...args: unknown[]) => void;
119
215
  emit: FunctionEmit;
@@ -131,12 +227,30 @@ export type FunctionContext = {
131
227
  libs: Record<string, any>;
132
228
  };
133
229
  export type FunctionHandler = (input: any, context: FunctionContext) => any;
230
+ /**
231
+ * The context a daemon's default export receives (as its only argument):
232
+ * everything a function gets, plus lifetime APIs. Registered timers,
233
+ * subscriptions and event handlers stay live after the invocation returns.
234
+ */
235
+ export type DaemonContext = FunctionContext & {
236
+ /**
237
+ * A managed `setInterval`: the callback keeps firing until cleared or the
238
+ * daemon stops; a callback that throws is logged and never stops the timer.
239
+ */
240
+ setInterval: (callback: () => unknown, ms: number) => NodeJS.Timeout;
241
+ clearInterval: (handle: NodeJS.Timeout) => void;
242
+ /** Receive events other local functions send via `context.daemons.emit`. */
243
+ onEvent: (handler: (event: DaemonEmittedEvent) => unknown) => void;
244
+ };
245
+ export type DaemonHandler = (context: DaemonContext) => any;
134
246
  export type LoadedFunction = {
135
247
  name: string;
136
248
  file: string;
137
249
  meta: FunctionMeta;
138
250
  handler: FunctionHandler;
139
251
  timeoutMs: number;
252
+ /** True for daemon files (`meta.daemon = true`). */
253
+ daemon?: boolean;
140
254
  /** Every file in this function's module graph → mtimeMs when it was loaded. */
141
255
  files: Map<string, number>;
142
256
  };
@@ -145,6 +259,11 @@ export type FunctionSummary = {
145
259
  description: string;
146
260
  parameters: Record<string, any>;
147
261
  };
262
+ /** What `GET /functions` and the status page report about a daemon. */
263
+ export type DaemonSummary = {
264
+ name: string;
265
+ description: string;
266
+ };
148
267
  export type FunctionsConfig = {
149
268
  enabled: boolean;
150
269
  dir: string;
@@ -162,6 +281,8 @@ export type FunctionsConfig = {
162
281
  export type FunctionRuntime = {
163
282
  backend: Backend;
164
283
  config: Config;
284
+ /** Carries the Data Bank binding; absent means `context.bank` is unconfigured. */
285
+ workspaceState?: WorkspaceState;
165
286
  };
166
287
  /** Metadata an `_auth` file exports alongside its authorize handler. */
167
288
  export type AuthMeta = {