@protobase/server 0.59.2 → 0.60.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.
Files changed (61) hide show
  1. package/dist/better-auth/store/migrations-table.js +1 -1
  2. package/dist/calls/admission.d.ts +4 -0
  3. package/dist/calls/admission.js +12 -0
  4. package/dist/calls/call-hub.js +170 -0
  5. package/dist/calls/call-member.d.ts +19 -6
  6. package/dist/calls/call-reads.d.ts +29 -0
  7. package/dist/calls/call-reads.js +79 -0
  8. package/dist/calls/call-signals-sql.d.ts +12 -0
  9. package/dist/calls/call-signals-sql.js +19 -0
  10. package/dist/calls/call-store.d.ts +30 -0
  11. package/dist/calls/call-store.js +112 -0
  12. package/dist/calls/call-sweep.js +26 -0
  13. package/dist/calls/call-watch.js +39 -0
  14. package/dist/calls/calls-access.d.ts +20 -5
  15. package/dist/calls/calls-access.js +38 -17
  16. package/dist/calls/calls-options.d.ts +9 -1
  17. package/dist/calls/calls-options.js +10 -2
  18. package/dist/calls/calls-runtime.d.ts +33 -0
  19. package/dist/calls/calls-runtime.js +94 -0
  20. package/dist/calls/calls-service-type.d.ts +11 -0
  21. package/dist/calls/calls-service.js +27 -0
  22. package/dist/calls/calls-sql.d.ts +7 -0
  23. package/dist/calls/calls-sql.js +66 -0
  24. package/dist/calls/calls-store.d.ts +23 -0
  25. package/dist/calls/calls-store.js +20 -0
  26. package/dist/calls/client-message.js +1 -0
  27. package/dist/calls/close-codes.js +17 -0
  28. package/dist/calls/livekit/livekit-session.js +1 -0
  29. package/dist/calls/member-relay.js +69 -17
  30. package/dist/calls/peer/peer-backend.js +68 -120
  31. package/dist/calls/record-calls.js +78 -0
  32. package/dist/create-admin.d.ts +4 -1
  33. package/dist/create-admin.js +21 -4
  34. package/dist/deps.d.ts +5 -0
  35. package/dist/functions/function-socket.d.ts +1 -0
  36. package/dist/functions/function-socket.js +14 -2
  37. package/dist/functions/routes.js +3 -4
  38. package/dist/index.d.ts +5 -1
  39. package/dist/index.js +5 -1
  40. package/dist/internal.d.ts +2 -1
  41. package/dist/internal.js +2 -1
  42. package/dist/meta.d.ts +2 -0
  43. package/dist/meta.js +1 -0
  44. package/dist/notifications/caller.js +2 -2
  45. package/dist/notifications/deliver.js +14 -2
  46. package/dist/notifications/push-job.js +5 -3
  47. package/dist/notifications/schema.js +7 -4
  48. package/dist/package.js +1 -1
  49. package/dist/routes/record.js +6 -0
  50. package/dist/status/do-not-disturb.d.ts +9 -0
  51. package/dist/status/do-not-disturb.js +15 -0
  52. package/dist/status/options.d.ts +15 -0
  53. package/dist/status/options.js +25 -0
  54. package/dist/status/routes.js +38 -0
  55. package/dist/status/schema-sql.js +19 -0
  56. package/dist/status/schema.d.ts +12 -0
  57. package/dist/status/schema.js +33 -0
  58. package/dist/status/status-input.js +33 -0
  59. package/dist/status/status-store.js +39 -0
  60. package/dist/webhooks/attempt.js +6 -1
  61. package/package.json +4 -4
@@ -1,131 +1,79 @@
1
1
  //#region src/calls/peer/peer-backend.ts
2
- /** How long a member whose socket was lost stays in the call for the others, waiting for their browser to resume. */
3
- const awayMs = 3e4;
4
2
  /**
5
- * The peer plugin: no media server. Protobase passes each member's descriptions and candidates to the member they name,
6
- * and tells every member who else is in the call and which of their tracks they hear; the browsers send their media to
7
- * each other directly. Members meet only within this process, which keeps who is in each call.
3
+ * The peer plugin: no media server. Protobase passes each member's descriptions and candidates to the member they name
4
+ * in the same call, and tells every member who else is in it and which of their tracks they hear; the browsers send
5
+ * their media to each other directly. Who is in the call, and the tracks each sends, are the call's record.
8
6
  */
9
- const peerBackend = (settings) => {
10
- const calls = /* @__PURE__ */ new Map();
11
- const membersOf = (call) => [...calls.get(call)?.values() ?? []];
12
- const announce = (call) => {
13
- const present = membersOf(call);
14
- for (const viewer of present) {
15
- if (viewer.away) continue;
16
- const others = present.filter((other) => other !== viewer);
17
- const hears = viewer.member.hears ?? (() => true);
18
- viewer.link.send({
7
+ const peerBackend = (settings) => ({ open: (member, link, room) => {
8
+ const own = /* @__PURE__ */ new Map();
9
+ const keep = (sid, kind, source) => own.set(sid, {
10
+ sid,
11
+ member: member.member,
12
+ kind,
13
+ source,
14
+ muted: false
15
+ });
16
+ const share = () => room.tracks([...own.values()]);
17
+ const receive = async (message) => {
18
+ switch (message.type) {
19
+ case "join":
20
+ link.send({
21
+ type: "joined",
22
+ call: room.call,
23
+ mode: "peer",
24
+ participant: member.member,
25
+ iceServers: settings.iceServers ?? []
26
+ });
27
+ return;
28
+ case "resume":
29
+ for (const track of message.tracks) keep(track.sid, track.kind, track.source);
30
+ link.send({ type: "resumed" });
31
+ return;
32
+ case "publish":
33
+ for (const track of message.tracks) keep(track.cid, track.kind, track.source);
34
+ link.send({
35
+ type: "published",
36
+ tracks: message.tracks.map((track) => ({
37
+ cid: track.cid,
38
+ sid: track.cid
39
+ }))
40
+ });
41
+ return share();
42
+ case "unpublish":
43
+ own.delete(message.sid);
44
+ return share();
45
+ case "mute": {
46
+ const track = own.get(message.sid);
47
+ if (!track) return;
48
+ track.muted = message.muted;
49
+ return share();
50
+ }
51
+ case "signal": return room.signal(message.to, {
52
+ ...message.description && { description: message.description },
53
+ ...message.candidate && { candidate: message.candidate }
54
+ });
55
+ case "leave": return link.close(1e3, "left");
56
+ case "offer":
57
+ case "candidate":
58
+ case "view": return;
59
+ }
60
+ };
61
+ return {
62
+ receive,
63
+ end: () => {},
64
+ roster: (members) => {
65
+ const others = members.filter((other) => other.member !== member.member);
66
+ const hears = member.hears ?? (() => true);
67
+ link.send({
19
68
  type: "peers",
20
- members: others.map((other) => other.member.member)
69
+ members: others.map((other) => other.member)
21
70
  });
22
- viewer.link.send({
71
+ link.send({
23
72
  type: "tracks",
24
- tracks: others.flatMap((other) => [...other.tracks.values()]).filter(hears)
73
+ tracks: others.flatMap((other) => other.tracks).filter(hears)
25
74
  });
26
75
  }
27
76
  };
28
- const remove = (self) => {
29
- const call = calls.get(self.member.call);
30
- if (call?.get(self.member.member) !== self) return;
31
- clearTimeout(self.away);
32
- call.delete(self.member.member);
33
- if (call.size === 0) calls.delete(self.member.call);
34
- announce(self.member.call);
35
- };
36
- const open = (member, link) => {
37
- const self = {
38
- member,
39
- link,
40
- tracks: /* @__PURE__ */ new Map()
41
- };
42
- const enter = () => {
43
- const call = calls.get(member.call) ?? /* @__PURE__ */ new Map();
44
- calls.set(member.call, call);
45
- const before = call.get(member.member);
46
- call.set(member.member, self);
47
- if (before) {
48
- clearTimeout(before.away);
49
- if (!before.away) {
50
- before.link.send({
51
- type: "left",
52
- reason: "removed"
53
- });
54
- before.link.close(1e3, "left");
55
- }
56
- }
57
- };
58
- const receive = (message) => {
59
- switch (message.type) {
60
- case "join":
61
- case "resume":
62
- if (message.type === "resume") for (const track of message.tracks) self.tracks.set(track.sid, {
63
- sid: track.sid,
64
- member: member.member,
65
- kind: track.kind,
66
- source: track.source,
67
- muted: false
68
- });
69
- enter();
70
- link.send(message.type === "join" ? {
71
- type: "joined",
72
- mode: "peer",
73
- participant: member.member,
74
- iceServers: settings.iceServers ?? []
75
- } : { type: "resumed" });
76
- return announce(member.call);
77
- case "publish":
78
- for (const track of message.tracks) self.tracks.set(track.cid, {
79
- sid: track.cid,
80
- member: member.member,
81
- kind: track.kind,
82
- source: track.source,
83
- muted: false
84
- });
85
- link.send({
86
- type: "published",
87
- tracks: message.tracks.map((track) => ({
88
- cid: track.cid,
89
- sid: track.cid
90
- }))
91
- });
92
- return announce(member.call);
93
- case "unpublish":
94
- self.tracks.delete(message.sid);
95
- return announce(member.call);
96
- case "mute": {
97
- const track = self.tracks.get(message.sid);
98
- if (!track) return;
99
- track.muted = message.muted;
100
- return announce(member.call);
101
- }
102
- case "signal": {
103
- const to = calls.get(member.call)?.get(message.to);
104
- if (!to || to.away || to === self) return;
105
- to.link.send({
106
- type: "signal",
107
- from: member.member,
108
- ...message.description && { description: message.description },
109
- ...message.candidate && { candidate: message.candidate }
110
- });
111
- return;
112
- }
113
- case "leave": return link.close(1e3, "left");
114
- case "offer":
115
- case "candidate":
116
- case "view": return;
117
- }
118
- };
119
- return {
120
- receive,
121
- end: (how) => {
122
- if (how === "left") return remove(self);
123
- if (calls.get(member.call)?.get(member.member) !== self) return;
124
- self.away = setTimeout(() => remove(self), awayMs);
125
- }
126
- };
127
- };
128
- return { open };
129
- };
77
+ } });
130
78
  //#endregion
131
79
  export { peerBackend };
@@ -0,0 +1,78 @@
1
+ import { HttpProblem, forbidden, notFound } from "../problem.js";
2
+ import { requestAccess, requireOperation } from "../request-access.js";
3
+ import { readTransaction } from "../transactions.js";
4
+ import { readableRecord } from "../comments/comment-access.js";
5
+ import { encodeKey } from "@protobase/schema/internal";
6
+ import { streamSSE } from "hono/streaming";
7
+ //#region src/calls/record-calls.ts
8
+ /** How often a page that follows a record's calls is checked again: whether its user still reads the record. */
9
+ const recheckMs = 6e4;
10
+ const heartbeatMs = 25e3;
11
+ /**
12
+ * Whether the caller may see the record's calls: signed in, and able to read the record (operation, tenant, row filter
13
+ * and record-level rule, as a get). A record they cannot read is the same 404 as one that does not exist.
14
+ */
15
+ const requireReader = async (deps, entry, session, key) => {
16
+ if (session.anonymous || session.user.id === "") throw forbidden("calls-need-user", "Sign in to see the calls");
17
+ const access = await requestAccess(deps, entry, session);
18
+ requireOperation(access, "read");
19
+ if (!await readTransaction(deps.db, deps.statementTimeoutMs, (trx) => readableRecord(trx, access, key, "hide"))) throw notFound(`No ${entry.name} with this key`);
20
+ };
21
+ const callsOf = (deps) => {
22
+ if (!deps.calls) throw notFound("This app has no calls");
23
+ return deps.calls;
24
+ };
25
+ /** `GET /{resource}/{key}:calls`: the record's latest calls, newest first, the one going on first. */
26
+ const readRecordCalls = async (deps, entry, session, key) => {
27
+ const calls = callsOf(deps);
28
+ await requireReader(deps, entry, session, key);
29
+ return { items: await (await calls.runtime()).of({
30
+ resource: entry.name,
31
+ key: encodeKey(key)
32
+ }) };
33
+ };
34
+ /**
35
+ * `GET /{resource}/{key}:calls?watch=true`: the same as a `text/event-stream`, each event's data `{ items }`, at once
36
+ * and whenever the calls change. The stream ends once its user can no longer read the record, at the next minute's
37
+ * check, or when the check fails.
38
+ */
39
+ const watchRecordCalls = async (c, deps, entry, key) => {
40
+ const calls = callsOf(deps);
41
+ const session = c.get("session");
42
+ await requireReader(deps, entry, session, key);
43
+ const runtime = await calls.runtime();
44
+ return streamSSE(c, async (stream) => {
45
+ const queue = [];
46
+ let wake = () => {};
47
+ let allowed = true;
48
+ stream.onAbort(() => wake());
49
+ const stop = await runtime.watch({
50
+ resource: entry.name,
51
+ key: encodeKey(key)
52
+ }, (items) => {
53
+ queue.push(items);
54
+ wake();
55
+ });
56
+ const recheck = setInterval(() => {
57
+ requireReader(deps, entry, session, key).catch((error) => {
58
+ if (!(error instanceof HttpProblem)) deps.report(error);
59
+ allowed = false;
60
+ wake();
61
+ });
62
+ }, recheckMs);
63
+ const heartbeat = setInterval(() => void stream.write(": ping\n\n"), heartbeatMs);
64
+ try {
65
+ while (!stream.aborted && allowed) {
66
+ const items = queue.shift();
67
+ if (items) await stream.writeSSE({ data: JSON.stringify({ items }) });
68
+ else await new Promise((resolve) => wake = resolve);
69
+ }
70
+ } finally {
71
+ clearInterval(recheck);
72
+ clearInterval(heartbeat);
73
+ stop();
74
+ }
75
+ });
76
+ };
77
+ //#endregion
78
+ export { readRecordCalls, watchRecordCalls };
@@ -10,6 +10,7 @@ import { HistoryOptions } from "./history/options.js";
10
10
  import { WebhooksOptions } from "./webhooks/table/options.js";
11
11
  import { NotificationsOptions } from "./notifications/options.js";
12
12
  import { CallsOptions } from "./calls/calls-options.js";
13
+ import { StatusOptions } from "./status/options.js";
13
14
  import { SubscriptionDefinition } from "./webhooks/subscription.js";
14
15
  import { FilesOptions } from "./files/options.js";
15
16
  import { Difficulty } from "./forms/challenge.js";
@@ -55,6 +56,8 @@ export type CreateAdminInput = {
55
56
  realtime?: RealtimeOptions;
56
57
  /** Each user's devices and the endpoints that register them, from `notifications: {}` (see `NotificationsOptions`). */
57
58
  notifications?: NotificationsOptions;
59
+ /** People's own status, from `status: {}` (see `StatusOptions`): it needs `auth` with organizations. */
60
+ status?: StatusOptions;
58
61
  /** The media server behind the calls functions admit members to with `calls.join` (see `CallsOptions`). */
59
62
  calls?: CallsOptions;
60
63
  /**
@@ -96,5 +99,5 @@ export type CreateAdminInput = {
96
99
  upgradeWebSocket?: UpgradeWebSocket;
97
100
  };
98
101
  /** The admin REST API as a Hono app. It uses only Web APIs, so it runs on Node, Workers and anywhere else Hono does. */
99
- export declare const createAdmin: ({ resources: appResources, views: appViews, pages, userMenu, bottomBars, db, authenticate, auth, functions, secret, files: filesOptions, events, history: historyOptions, jobs, subscriptions, webhooks: webhooksOptions, realtime, notifications, calls, mobile, app: identity, icons, bundlePlugins, fieldTypes, options, formsDifficulty, commentUsers: givenCommentUsers, verifyToken, upgradeWebSocket }: CreateAdminInput) => Admin;
102
+ export declare const createAdmin: ({ resources: appResources, views: appViews, pages, userMenu, bottomBars, db, authenticate, auth, functions, secret, files: filesOptions, events, history: historyOptions, jobs, subscriptions, webhooks: webhooksOptions, realtime, notifications, status, calls, mobile, app: identity, icons, bundlePlugins, fieldTypes, options, formsDifficulty, commentUsers: givenCommentUsers, verifyToken, upgradeWebSocket }: CreateAdminInput) => Admin;
100
103
  //#endregion
@@ -59,6 +59,7 @@ import { toApiFunction } from "./functions/define-function.js";
59
59
  import { createWebhooks } from "./webhooks/webhooks.js";
60
60
  import { webhookTable } from "./webhooks/table/webhook-table.js";
61
61
  import { subscriptionUrlCheck, subscriptionWriteCheck } from "./webhooks/table/validate-hook.js";
62
+ import { callsService } from "./calls/calls-service.js";
62
63
  import { deviceStore, removeDevicesWithUsers } from "./notifications/device-store-of.js";
63
64
  import { historyStore, removeHistoryWithUsers } from "./notifications/history-store-of.js";
64
65
  import { devicesPath, historyPath } from "./notifications/paths.js";
@@ -66,6 +67,10 @@ import { historyRoutes } from "./notifications/history-routes.js";
66
67
  import { deviceRoutes } from "./notifications/routes.js";
67
68
  import { notificationSenders, webPushKey } from "./notifications/senders-of.js";
68
69
  import { pushJob } from "./notifications/push-job.js";
70
+ import { onDoNotDisturb } from "./status/do-not-disturb.js";
71
+ import { checkStatusAuth, statusNames } from "./status/options.js";
72
+ import { statusRoutes } from "./status/routes.js";
73
+ import { storeSchema } from "./better-auth/store/store-names.js";
69
74
  import { liveSessions } from "./better-auth/live-sessions.js";
70
75
  import { checkBottomBars, checkShell } from "./check-shell.js";
71
76
  import { checkOwnerFields } from "./check-owners.js";
@@ -106,13 +111,14 @@ import { createScanGuard } from "./scan-guard.js";
106
111
  import { failedJobs, failedJobsView } from "./jobs/failed-jobs.js";
107
112
  import { Hono } from "hono";
108
113
  import { accountPage, accountPageName, checkPages, settingsResources, withSettingsFields } from "@protobase/layout";
114
+ import { statusPath } from "@protobase/schema/internal";
109
115
  //#region src/create-admin.ts
110
116
  const declaredRoles = (auth, roles) => {
111
117
  const names = [...auth?.roles ?? [], ...Object.keys(roles?.definitions ?? {})];
112
118
  return names.length > 0 ? [...new Set(names)] : void 0;
113
119
  };
114
120
  /** The admin REST API as a Hono app. It uses only Web APIs, so it runs on Node, Workers and anywhere else Hono does. */
115
- const createAdmin = ({ resources: appResources, views: appViews = [], pages = [], userMenu, bottomBars = [], db, authenticate, auth, functions = {}, secret, files: filesOptions, events, history: historyOptions, jobs = [], subscriptions = [], webhooks: webhooksOptions, realtime, notifications, calls, mobile, app: identity, icons, bundlePlugins = [], fieldTypes = {}, options = {}, formsDifficulty, commentUsers: givenCommentUsers, verifyToken, upgradeWebSocket }) => {
121
+ const createAdmin = ({ resources: appResources, views: appViews = [], pages = [], userMenu, bottomBars = [], db, authenticate, auth, functions = {}, secret, files: filesOptions, events, history: historyOptions, jobs = [], subscriptions = [], webhooks: webhooksOptions, realtime, notifications, status, calls, mobile, app: identity, icons, bundlePlugins = [], fieldTypes = {}, options = {}, formsDifficulty, commentUsers: givenCommentUsers, verifyToken, upgradeWebSocket }) => {
116
122
  const basePath = options.basePath ?? "/api/v1";
117
123
  const appModels = appResources.map((resource) => resource.toModel());
118
124
  const withComments = appModels.some((model) => model.comments);
@@ -173,6 +179,14 @@ const createAdmin = ({ resources: appResources, views: appViews = [], pages = []
173
179
  const errorReporting = errorReportingSettings(options.errorReporting, globalThis.process?.env ?? {});
174
180
  const maps = mapSettings(options.maps, globalThis.process?.env ?? {});
175
181
  const senders = notifications ? notificationSenders(notifications) : [];
182
+ if (status) checkStatusAuth(auth);
183
+ const statusTables = status && auth && {
184
+ statuses: statusNames(status),
185
+ members: {
186
+ schema: storeSchema(auth),
187
+ table: "member"
188
+ }
189
+ };
176
190
  const pushKey = webPushKey(senders);
177
191
  const locale = localeSetting(options.locale);
178
192
  const plugins = pluginOptions(options.plugins, globalThis.process?.env ?? {}, bundlePlugins);
@@ -231,6 +245,7 @@ const createAdmin = ({ resources: appResources, views: appViews = [], pages = []
231
245
  ...maps && { maps },
232
246
  ...notifications && notifications.ui !== false && { bell: true },
233
247
  ...pushKey && { webPushKey: pushKey },
248
+ ...statusTables && { status: true },
234
249
  ...locale && { locale },
235
250
  plugins,
236
251
  sources,
@@ -249,7 +264,8 @@ const createAdmin = ({ resources: appResources, views: appViews = [], pages = []
249
264
  ...withAi && { ai: {
250
265
  ...model && { model },
251
266
  ...options.onUnhandledError && { report: options.onUnhandledError }
252
- } }
267
+ } },
268
+ ...calls && { calls: callsService(() => deps, calls) }
253
269
  };
254
270
  const appName = shownAppName(auth, globalThis.process?.env ?? {});
255
271
  const meta = createMeta(deps, appName, icons?.favicon ? faviconPath : void 0);
@@ -395,7 +411,7 @@ const createAdmin = ({ resources: appResources, views: appViews = [], pages = []
395
411
  wake: () => wakeDispatch(deps),
396
412
  upgradeWebSocket,
397
413
  upgradeAuthenticate,
398
- ...calls && { calls },
414
+ ...deps.calls && { calls: deps.calls },
399
415
  report
400
416
  }));
401
417
  if (upgradeWebSocket) {
@@ -444,6 +460,7 @@ const createAdmin = ({ resources: appResources, views: appViews = [], pages = []
444
460
  if (auth) removeHistoryWithUsers(auth, history);
445
461
  app.route(historyPath(systemPath), guarded((routes) => void routes.route("/", historyRoutes(history, auth?.origins ?? []))));
446
462
  }
463
+ if (statusTables) app.route(statusPath(systemPath), guarded((routes) => void routes.route("/", statusRoutes(db, statusTables))));
447
464
  if (forms) app.route(`${systemPath}/forms`, formRoutes(deps, forms));
448
465
  const feed = tableFeed({
449
466
  db,
@@ -514,7 +531,7 @@ const createAdmin = ({ resources: appResources, views: appViews = [], pages = []
514
531
  ...withHistory && days !== void 0 ? [pruneHistoryJob(changes, days)] : [],
515
532
  ...mentions ? [mentions] : [],
516
533
  ...fill ? [fill] : [],
517
- ...notifications ? [pushJob(notifications, senders, auth && liveSessions(auth))] : []
534
+ ...notifications ? [pushJob(notifications, senders, auth && liveSessions(auth), statusTables ? (jobDb, userIds) => onDoNotDisturb(jobDb, statusTables.statuses, userIds) : void 0)] : []
518
535
  ]
519
536
  });
520
537
  };
package/dist/deps.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { AuditQueue, PipelineHook, WriteCheck } from "./types.js";
2
2
  import { CommentUsers } from "./comments/comment-users.js";
3
+ import { CallsService } from "./calls/calls-service-type.js";
3
4
  import { Registry } from "./registry.js";
4
5
  import { ErrorReportingSettings } from "./error-reporting/error-reporting-settings.js";
5
6
  import { mentionJob } from "./comments/mention-job.js";
@@ -53,6 +54,8 @@ export type Deps = {
53
54
  maps?: MapSettings;
54
55
  /** Whether the shell draws the notification bell: notifications are on and their `ui` is not false. */
55
56
  bell?: boolean;
57
+ /** Whether people set their own status (`status: {}`), which `/meta` names to everyone. */
58
+ status?: boolean;
56
59
  /** The VAPID public key browsers subscribe for Web Push with, when notifications have a web sender, which `/meta` names to everyone. */
57
60
  webPushKey?: string;
58
61
  /** The language the admin app's screens are in for everyone, which `/meta` names to everyone. */
@@ -89,5 +92,7 @@ export type Deps = {
89
92
  model?: ModelSettings;
90
93
  report?: (error: unknown) => void;
91
94
  };
95
+ /** With `calls`: the app's calls, which functions admit members to and the records' readers follow. */
96
+ calls?: CallsService;
92
97
  };
93
98
  //#endregion
@@ -13,6 +13,7 @@ export type SocketEvents = {
13
13
  onOpen?: (socket: FunctionSocket) => void | Promise<void>;
14
14
  /** Text arrives as a string, binary as an ArrayBuffer. The next message waits until a returned promise settles. */
15
15
  onMessage?: (data: string | ArrayBuffer, socket: FunctionSocket) => void | Promise<void>;
16
+ /** With the code the server closed the socket with, such as 1008 after a refused check, else the browser's. */
16
17
  onClose?: (code: number, reason: string) => void | Promise<void>;
17
18
  /**
18
19
  * Checked every minute after the framework's own check, while the socket is open; what it returns is ignored. Throw
@@ -18,9 +18,14 @@ const socketEvents = (events, { report, recheck }) => {
18
18
  let waiting = 0;
19
19
  let paused = false;
20
20
  let ended = false;
21
+ let closedWith;
21
22
  let stopRecheck = () => {};
22
23
  const end = (code, reason) => {
23
24
  ended = true;
25
+ closedWith ??= {
26
+ code,
27
+ reason
28
+ };
24
29
  stopRecheck();
25
30
  raw.close(code, reason);
26
31
  };
@@ -56,7 +61,13 @@ const socketEvents = (events, { report, recheck }) => {
56
61
  if (raw.readyState !== openState) return resolve();
57
62
  raw.send(data, () => resolve());
58
63
  }),
59
- close: (code, reason) => raw.close(code, reason),
64
+ close: (code, reason) => {
65
+ closedWith ??= {
66
+ code: code ?? 1e3,
67
+ reason: reason ?? ""
68
+ };
69
+ raw.close(code, reason);
70
+ },
60
71
  get bufferedAmount() {
61
72
  return raw.bufferedAmount;
62
73
  }
@@ -77,7 +88,8 @@ const socketEvents = (events, { report, recheck }) => {
77
88
  },
78
89
  onClose: (event) => {
79
90
  stopRecheck();
80
- enqueue(() => events.onClose?.(event.code, event.reason), true);
91
+ const { code, reason } = closedWith ?? event;
92
+ enqueue(() => events.onClose?.(code, reason), true);
81
93
  }
82
94
  };
83
95
  };
@@ -24,8 +24,7 @@ const isUpgrade = (request) => request.headers.get("upgrade")?.toLowerCase() ===
24
24
  * A function may answer an upgrade with a socket, only once it returned. While it is open, its caller is checked again
25
25
  * every minute: a protected function's always, a public one's once `caller()` resolved.
26
26
  */
27
- const functionRoutes = ({ basePath, functions, authenticate, access, db, records, channels, decryptField, onError, wake, upgradeWebSocket, upgradeAuthenticate = authenticate, calls: callsOptions, report }) => {
28
- const calls = callsAccess(callsOptions);
27
+ const functionRoutes = ({ basePath, functions, authenticate, access, db, records, channels, decryptField, onError, wake, upgradeWebSocket, upgradeAuthenticate = authenticate, calls, report }) => {
29
28
  const app = new Hono().basePath(basePath);
30
29
  app.onError(onError);
31
30
  const sessionOf = (request) => isUpgrade(request) ? upgradeAuthenticate(request) : authenticate(request);
@@ -71,7 +70,7 @@ const functionRoutes = ({ basePath, functions, authenticate, access, db, records
71
70
  channels,
72
71
  caller: resolveCaller,
73
72
  acceptWebSocket: acceptor.accept,
74
- calls
73
+ calls: callsAccess(calls, resolveCaller)
75
74
  };
76
75
  return acceptor.answer(name, await invokeFunction(name, fn, request, context));
77
76
  }
@@ -101,7 +100,7 @@ const functionRoutes = ({ basePath, functions, authenticate, access, db, records
101
100
  caller: async () => caller,
102
101
  decryptField: decryptField(reader),
103
102
  acceptWebSocket: acceptor.accept,
104
- calls
103
+ calls: callsAccess(calls, async () => caller)
105
104
  };
106
105
  return acceptor.answer(name, await invokeFunction(name, fn, request, context));
107
106
  }));
package/dist/index.d.ts CHANGED
@@ -22,6 +22,7 @@ import { HistoryStore, maxHistoryPage, maxUnreadCount } from "./notifications/hi
22
22
  import { PushAnswer, PushSender } from "./notifications/sender.js";
23
23
  import { DeviceColumn, HistoryColumn, NotificationsOptions } from "./notifications/options.js";
24
24
  import { CallBackend, CallsOptions, LiveKitBackend } from "./calls/calls-options.js";
25
+ import { StatusOptions, statusNames } from "./status/options.js";
25
26
  import { EventData, RunContext, SubscriptionDefinition, SubscriptionEvent, SubscriptionOptions, subscription } from "./webhooks/subscription.js";
26
27
  import { Sharp, renderVariant, thumbHash } from "./files/images.js";
27
28
  import { FileProvider, FileStore, StoredObject } from "./files/store.js";
@@ -103,6 +104,7 @@ import { checkWebhooksSchema, webhooksMigration } from "./webhooks/table/schema.
103
104
  import { checkRealtimeRelay, realtimeRelayMigration } from "./realtime/relay/relay-schema.js";
104
105
  import { channelSendsMigration, checkChannelSends } from "./channels/sends-schema.js";
105
106
  import { checkComments, commentsMigration } from "./comments/comments-sql.js";
107
+ import { callsMigration, checkCalls } from "./calls/calls-sql.js";
106
108
  import { CheckAiInput, checkAi } from "./ai/check-ai.js";
107
109
  import { CommentItem } from "./comments/comment-item.js";
108
110
  import { checkNotificationsSchema, notificationsMigration } from "./notifications/schema.js";
@@ -118,6 +120,8 @@ import { sendNotification } from "./notifications/send-notification.js";
118
120
  import { VapidSettings, readVapidSettings, vapidPrivateKeyVariable, vapidPublicKeyVariable, vapidSubjectVariable } from "./notifications/web-push/vapid-settings.js";
119
121
  import { WebPushOptions, webPushSender } from "./notifications/web-push/web-push-sender.js";
120
122
  import { generateVapidKeys } from "./notifications/web-push/keys.js";
123
+ import { checkStatusSchema, statusMigration } from "./status/schema.js";
124
+ import { onDoNotDisturb } from "./status/do-not-disturb.js";
121
125
  import { MemberInput, NewOrganization, addAppRoleToOwners, addMember, createOrganization, listOrganizations, removeMember, setMemberRoles } from "./better-auth/organizations/host.js";
122
126
  import { AssistantBackend, assistantProtocolRoutes } from "./assistant/protocol-routes.js";
123
127
  import { fileConversationStore } from "./assistant/file-conversation-store.js";
@@ -176,4 +180,4 @@ import { DrainResult, JobsRuntime, StartJobsOptions, startJobs } from "./jobs/ru
176
180
  import { jobsDrainApp } from "./jobs/drain-route.js";
177
181
  import { checkJobsSchema, jobsSchema, jobsSchemaMigration } from "./jobs/schema.js";
178
182
  import { AdminAuth, CreateAuthOptions, UserCreatedHook, normalizeRoles } from "./better-auth/create-auth.js";
179
- export { type Admin, type AdminAuth, type AdminOptions, type AggregateParams, type ApiFunction, type ApiKeys, type ApiKeysOptions, type ApnsEnvironment, type AppIcons, type AppIdentity, type AppPoolConfig, type ApplyOptions, type ApplyResult, type ApprovalAnswer, type ApprovalRequest, type ArgumentsPayload, type AssistantBackend, type AssistantOptions, type AssistantSettings, type AssistantTool, type AuditEvent, type AuditQueue, type AuthHooks, type AuthSettings, type AuthenticateSettings, type Authenticator, type BaseToolContext, type BatchOperation, type BatchResult, type BetterAuthAuthenticator, type BetterAuthAuthenticatorOptions, type CallBackend, type CallMember, type Caller, type CallerOptions, type CallsAccess, type CallsOptions, type CapturedRow, type CascadingKey, type ChannelBroadcast, type ChannelSender, type ChatMessage, type ChatTextPart, type CheckAiInput, type CleanupEntry, type CleanupReport, type CleanupSchedule, type CoalescedChange, type CommentItem, type CommentToolsInput, type CommentUsers, type Completion, type CompletionOptions, ConnectionsBusy, type Conversation, type ConversationRecord, type ConversationStore, type ConversationsOptions, type CorsOptions, type CorsOrigins, type CreateAdminInput, type CreateAuthOptions, type DecryptField, type Device, type DeviceColumn, type DeviceKind, type DeviceStore, DeviceStoreError, type DrainResult, type EmailComponent, type EmailOptions, type EmailTemplate, type EncryptionStatus, type EncryptionTools, type EncryptionToolsInput, type EnqueueJob, type EnqueueOptions, type ErrorReporter, type ErrorReportingOptions, type ErrorReportingSettings, type EventData, type EventsOptions, FatalJobError, type FieldApplied, type FieldDecrypter, type FieldReader, type FieldStatus, type FileCleanupInput, type FileLimits, type FileObject, type FileProvider, type FileProviderSettings, type FileRef, type FileStore, type FileVariantObject, type FilesOptions, type FunctionApp, type FunctionCaller, type FunctionContext, type FunctionEnv, type FunctionHandler, type FunctionOptions, type FunctionRecords, type FunctionSocket, type FunctionSource, type HistoryColumn, type HistoryOptions, type HistoryPosition, type HistoryStore, HistoryStoreError, type HookContext, HttpProblem, type IssueTokenOptions, type JobContext, type JobDeclaration, type JobDefinition, type JobName, type JobOptions, type JobPayload, type JobRun, type JobsRuntime, type JsonObject, type JsonValue, type JwtOptions, type JwtVerifyOptions, type KeyFunctionContext, type LinkedAccount, type ListParams, type LiveKitBackend, type LocalFilesOptions, type MailMessage, type Mailer, type MapLayer, type MapOptions, type MapSettings, type McpApprovals, type McpGateInput, type McpHandlerInput, type McpRoutesInput, type McpServerInput, type McpToolsInput, type McpWrites, type MemberInput, type Membership, MissingCredentials, type MobileConfig, ModelError, type ModelSettings, type NewDevice, type NewNotification, type NewOrganization, type NewUser, type NotificationRecipients, NotificationSendError, type NotificationsOptions, type OperatorProvider, type OrganizationRole, type OrganizationsOptions, type PgModule, type PipelineHook, type PlatformSignIn, type PluginOption, type PluginRef, type PngIcon, type ProtectedFunctionOptions, type PublicFunctionContext, type PublicFunctionEnv, type PublicFunctionHandler, type PublicFunctionOptions, type PushAnswer, type PushMessage, PushMessageError, type PushSender, type QueryOptions, type QueryResult, type ReadableResources, type RealtimeOptions, type RealtimePrune, type ReasoningDetail, type ReasoningEffort, type RebindOption, type RecordGroups, type RecordKey, type RecordKeyInput, type RecordPage, type RenderedEmail, type ResourceChange, type ResourceSource, type RoleDefinition, type RolesInput, type RunContext, type RuntimeOptions, type S3Bucket, type S3FilesOptions, type S3ListPage, type S3Object, type ScanGuardMode, type ScheduledDelete, type SendNotification, type Session, type SessionOrganization, type Sharp, type SignInPolicy, type SignInRule, type SignatureOptions, type SocketEvents, type SourceOption, type SourceRef, type StaffAccessRule, type StaffSignIn, type StandardSchema, type StandardWebhookOptions, type StartJobsOptions, type StoreFileInput, type StoredMember, type StoredNotification, type StoredObject, type StoredOrganization, type StoredUser, type StrayValues, type SubscriptionDefinition, type SubscriptionEvent, type SubscriptionOptions, type TenantValue, type ToolAnnotations, type ToolCall, type ToolComment, type ToolCommentPage, type ToolComments, type ToolContext, type ToolRecord, type ToolRecords, type ToolSpec, type TrustedApp, type TurnOptions, type UnreadableEntry, type Urgency, type User, type UserCreatedHook, type VapidSettings, type ViewSource, type WebPushFields, type WebPushOptions, type WebhooksOptions, type WidgetOptions, type WriteEvent, type WriteOperation, type WriteRecordToolsInput, addAppRoleToOwners, addCommentTool, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, appNameOver, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaDrift, authSchemaMigration, authStoreTables, backgroundSettled, badRequest, batchWriteTool, beforeSignInPluginsVariable, betterAuthTokens, capSocketMessages, changesMigration, channelSendsMigration, checkAi, checkAuthSchema, checkChanges, checkChannelSends, checkComments, checkComputed, checkJobsSchema, checkNotificationsSchema, checkQueryRunner, checkRealtimeRelay, checkResourcesOutsideAuthStore, checkSourceNames, checkViewQueries, checkWebhooksSchema, coalesce, commentTools, commentsMigration, computedMigration, configExports, consoleAuditQueue, conversationKey, countRecordsTool, createAdmin, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createRecordTool, createUser, defaultAppName, defaultHistoryPage, defaultSignInPolicy, defineEmail, defineFunction, defineJob, defineTool, deleteRecordTool, deleteUser, describeResourceTool, deviceIdParam, deviceStore, devicesPath, enqueueJob, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, generateVapidKeys, getRecordTool, goTruePath, handleDroppedConnections, hasUsers, historyIdParam, historyIdPattern, historyLimits, historyPath, historyStore, honorSocketMessageCaps, imageSize, isBackgroundWork, isCaptured, isJobDefinition, isOAuthWellKnownPath, isSchedule, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, jwtVerifier, limitedFileStore, listCommentsTool, listOrganizations, listRecordsTool, listResourcesTool, listUsers, localFileStore, longQueryTimeoutMs, mapSettings, mapStyleUrl, mapStyleVariable, maxDevicesPerUser, maxHistoryPage, maxMessageBytes, maxRecipients, maxTokenTtlSeconds, maxTtlSeconds, maxUnreadCount, maxWidgetPropsBytes, mcpApprovals, mcpGate, mcpHandler, mcpIcons, mcpInstructions, mcpRoutes, mcpServer, mcpToolContext, mcpTools, migrationCommand, newWebhookSecret, normalizeRoles, notFound, notificationSenders, notificationsMigration, oauthWellKnownPaths, objectKey, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, poolWaitMs, postgresDeviceStore, postgresHistoryStore, processor, pushMessage, queryRunnerMigration, readDbConnections, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readVapidSettings, readWriteQueryTool, readableResources, realtimeLimits, realtimeRelayMigration, recordOf, refusalOf, refused, relayed, removeDevicesWithUsers, removeHistoryWithUsers, removeMember, renderVariant, requestApproval, requireEnv, resourceChange, roleChoices, runInBackground, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, s3FileStore, seesAssistant, seesRuntime, sendNotification, sessionOf, setMemberRoles, setUserBanned, setUserRole, shownAppName, signInPolicyMethods, socketMessageCapOf, sourceOptions, sourcesFor, sourcesVariable, sqlSends, startErrorReporting, startJobs, storageCleanupSchedule, storageProvider, storeFile, storeUsage, streamChatCompletion, subscription, supabasePath, thumbHash, unauthorized, updateRecordTool, urgencies, vapidPrivateKeyVariable, vapidPublicKeyVariable, vapidSubjectVariable, variantPath, verifySignature, verifyStandardWebhook, waitUntil, wantsLongQueries, webManifestPath, webPushSender, webauthnPath, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps, writeRecordTools };
183
+ export { type Admin, type AdminAuth, type AdminOptions, type AggregateParams, type ApiFunction, type ApiKeys, type ApiKeysOptions, type ApnsEnvironment, type AppIcons, type AppIdentity, type AppPoolConfig, type ApplyOptions, type ApplyResult, type ApprovalAnswer, type ApprovalRequest, type ArgumentsPayload, type AssistantBackend, type AssistantOptions, type AssistantSettings, type AssistantTool, type AuditEvent, type AuditQueue, type AuthHooks, type AuthSettings, type AuthenticateSettings, type Authenticator, type BaseToolContext, type BatchOperation, type BatchResult, type BetterAuthAuthenticator, type BetterAuthAuthenticatorOptions, type CallBackend, type CallMember, type Caller, type CallerOptions, type CallsAccess, type CallsOptions, type CapturedRow, type CascadingKey, type ChannelBroadcast, type ChannelSender, type ChatMessage, type ChatTextPart, type CheckAiInput, type CleanupEntry, type CleanupReport, type CleanupSchedule, type CoalescedChange, type CommentItem, type CommentToolsInput, type CommentUsers, type Completion, type CompletionOptions, ConnectionsBusy, type Conversation, type ConversationRecord, type ConversationStore, type ConversationsOptions, type CorsOptions, type CorsOrigins, type CreateAdminInput, type CreateAuthOptions, type DecryptField, type Device, type DeviceColumn, type DeviceKind, type DeviceStore, DeviceStoreError, type DrainResult, type EmailComponent, type EmailOptions, type EmailTemplate, type EncryptionStatus, type EncryptionTools, type EncryptionToolsInput, type EnqueueJob, type EnqueueOptions, type ErrorReporter, type ErrorReportingOptions, type ErrorReportingSettings, type EventData, type EventsOptions, FatalJobError, type FieldApplied, type FieldDecrypter, type FieldReader, type FieldStatus, type FileCleanupInput, type FileLimits, type FileObject, type FileProvider, type FileProviderSettings, type FileRef, type FileStore, type FileVariantObject, type FilesOptions, type FunctionApp, type FunctionCaller, type FunctionContext, type FunctionEnv, type FunctionHandler, type FunctionOptions, type FunctionRecords, type FunctionSocket, type FunctionSource, type HistoryColumn, type HistoryOptions, type HistoryPosition, type HistoryStore, HistoryStoreError, type HookContext, HttpProblem, type IssueTokenOptions, type JobContext, type JobDeclaration, type JobDefinition, type JobName, type JobOptions, type JobPayload, type JobRun, type JobsRuntime, type JsonObject, type JsonValue, type JwtOptions, type JwtVerifyOptions, type KeyFunctionContext, type LinkedAccount, type ListParams, type LiveKitBackend, type LocalFilesOptions, type MailMessage, type Mailer, type MapLayer, type MapOptions, type MapSettings, type McpApprovals, type McpGateInput, type McpHandlerInput, type McpRoutesInput, type McpServerInput, type McpToolsInput, type McpWrites, type MemberInput, type Membership, MissingCredentials, type MobileConfig, ModelError, type ModelSettings, type NewDevice, type NewNotification, type NewOrganization, type NewUser, type NotificationRecipients, NotificationSendError, type NotificationsOptions, type OperatorProvider, type OrganizationRole, type OrganizationsOptions, type PgModule, type PipelineHook, type PlatformSignIn, type PluginOption, type PluginRef, type PngIcon, type ProtectedFunctionOptions, type PublicFunctionContext, type PublicFunctionEnv, type PublicFunctionHandler, type PublicFunctionOptions, type PushAnswer, type PushMessage, PushMessageError, type PushSender, type QueryOptions, type QueryResult, type ReadableResources, type RealtimeOptions, type RealtimePrune, type ReasoningDetail, type ReasoningEffort, type RebindOption, type RecordGroups, type RecordKey, type RecordKeyInput, type RecordPage, type RenderedEmail, type ResourceChange, type ResourceSource, type RoleDefinition, type RolesInput, type RunContext, type RuntimeOptions, type S3Bucket, type S3FilesOptions, type S3ListPage, type S3Object, type ScanGuardMode, type ScheduledDelete, type SendNotification, type Session, type SessionOrganization, type Sharp, type SignInPolicy, type SignInRule, type SignatureOptions, type SocketEvents, type SourceOption, type SourceRef, type StaffAccessRule, type StaffSignIn, type StandardSchema, type StandardWebhookOptions, type StartJobsOptions, type StatusOptions, type StoreFileInput, type StoredMember, type StoredNotification, type StoredObject, type StoredOrganization, type StoredUser, type StrayValues, type SubscriptionDefinition, type SubscriptionEvent, type SubscriptionOptions, type TenantValue, type ToolAnnotations, type ToolCall, type ToolComment, type ToolCommentPage, type ToolComments, type ToolContext, type ToolRecord, type ToolRecords, type ToolSpec, type TrustedApp, type TurnOptions, type UnreadableEntry, type Urgency, type User, type UserCreatedHook, type VapidSettings, type ViewSource, type WebPushFields, type WebPushOptions, type WebhooksOptions, type WidgetOptions, type WriteEvent, type WriteOperation, type WriteRecordToolsInput, addAppRoleToOwners, addCommentTool, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, appNameOver, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaDrift, authSchemaMigration, authStoreTables, backgroundSettled, badRequest, batchWriteTool, beforeSignInPluginsVariable, betterAuthTokens, callsMigration, capSocketMessages, changesMigration, channelSendsMigration, checkAi, checkAuthSchema, checkCalls, checkChanges, checkChannelSends, checkComments, checkComputed, checkJobsSchema, checkNotificationsSchema, checkQueryRunner, checkRealtimeRelay, checkResourcesOutsideAuthStore, checkSourceNames, checkStatusSchema, checkViewQueries, checkWebhooksSchema, coalesce, commentTools, commentsMigration, computedMigration, configExports, consoleAuditQueue, conversationKey, countRecordsTool, createAdmin, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createRecordTool, createUser, defaultAppName, defaultHistoryPage, defaultSignInPolicy, defineEmail, defineFunction, defineJob, defineTool, deleteRecordTool, deleteUser, describeResourceTool, deviceIdParam, deviceStore, devicesPath, enqueueJob, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, generateVapidKeys, getRecordTool, goTruePath, handleDroppedConnections, hasUsers, historyIdParam, historyIdPattern, historyLimits, historyPath, historyStore, honorSocketMessageCaps, imageSize, isBackgroundWork, isCaptured, isJobDefinition, isOAuthWellKnownPath, isSchedule, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, jwtVerifier, limitedFileStore, listCommentsTool, listOrganizations, listRecordsTool, listResourcesTool, listUsers, localFileStore, longQueryTimeoutMs, mapSettings, mapStyleUrl, mapStyleVariable, maxDevicesPerUser, maxHistoryPage, maxMessageBytes, maxRecipients, maxTokenTtlSeconds, maxTtlSeconds, maxUnreadCount, maxWidgetPropsBytes, mcpApprovals, mcpGate, mcpHandler, mcpIcons, mcpInstructions, mcpRoutes, mcpServer, mcpToolContext, mcpTools, migrationCommand, newWebhookSecret, normalizeRoles, notFound, notificationSenders, notificationsMigration, oauthWellKnownPaths, objectKey, onDoNotDisturb, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, poolWaitMs, postgresDeviceStore, postgresHistoryStore, processor, pushMessage, queryRunnerMigration, readDbConnections, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readVapidSettings, readWriteQueryTool, readableResources, realtimeLimits, realtimeRelayMigration, recordOf, refusalOf, refused, relayed, removeDevicesWithUsers, removeHistoryWithUsers, removeMember, renderVariant, requestApproval, requireEnv, resourceChange, roleChoices, runInBackground, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, s3FileStore, seesAssistant, seesRuntime, sendNotification, sessionOf, setMemberRoles, setUserBanned, setUserRole, shownAppName, signInPolicyMethods, socketMessageCapOf, sourceOptions, sourcesFor, sourcesVariable, sqlSends, startErrorReporting, startJobs, statusMigration, statusNames, storageCleanupSchedule, storageProvider, storeFile, storeUsage, streamChatCompletion, subscription, supabasePath, thumbHash, unauthorized, updateRecordTool, urgencies, vapidPrivateKeyVariable, vapidPublicKeyVariable, vapidSubjectVariable, variantPath, verifySignature, verifyStandardWebhook, waitUntil, wantsLongQueries, webManifestPath, webPushSender, webauthnPath, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps, writeRecordTools };
package/dist/index.js CHANGED
@@ -78,6 +78,8 @@ import { readVapidSettings, vapidPrivateKeyVariable, vapidPublicKeyVariable, vap
78
78
  import { webPushSender } from "./notifications/web-push/web-push-sender.js";
79
79
  import { notificationSenders } from "./notifications/senders-of.js";
80
80
  import { NotificationSendError, maxMessageBytes, maxRecipients } from "./notifications/send-input.js";
81
+ import { onDoNotDisturb } from "./status/do-not-disturb.js";
82
+ import { statusNames } from "./status/options.js";
81
83
  import { errorReportingSettings, errorReportingVariable } from "./error-reporting/error-reporting-settings.js";
82
84
  import { storageCleanupSchedule } from "./files/cleanup-schedule.js";
83
85
  import { limitedFileStore, storeUsage } from "./files/limits.js";
@@ -110,9 +112,11 @@ import { checkComputed, computedMigration } from "./computed/computed-schema.js"
110
112
  import { checkWebhooksSchema, webhooksMigration } from "./webhooks/table/schema.js";
111
113
  import { checkRealtimeRelay, realtimeRelayMigration } from "./realtime/relay/relay-schema.js";
112
114
  import { channelSendsMigration, checkChannelSends } from "./channels/sends-schema.js";
115
+ import { callsMigration, checkCalls } from "./calls/calls-sql.js";
113
116
  import { checkAi } from "./ai/check-ai.js";
114
117
  import { checkNotificationsSchema, notificationsMigration } from "./notifications/schema.js";
115
118
  import { sendNotification } from "./notifications/send-notification.js";
119
+ import { checkStatusSchema, statusMigration } from "./status/schema.js";
116
120
  import { maxWidgetPropsBytes, widget } from "./assistant/widget.js";
117
121
  import { checkQueryRunner, queryRunnerMigration } from "./assistant/query-runner/query-runner.js";
118
122
  import { startErrorReporting } from "./error-reporting/error-reporter.js";
@@ -128,4 +132,4 @@ import { enqueueJob } from "./jobs/declared-job.js";
128
132
  import { defineEmail } from "./mail/define-email.js";
129
133
  import { startJobs } from "./jobs/runtime.js";
130
134
  import { jobsDrainApp } from "./jobs/drain-route.js";
131
- export { ConnectionsBusy, DeviceStoreError, FatalJobError, HistoryStoreError, HttpProblem, MissingCredentials, ModelError, NotificationSendError, PushMessageError, addAppRoleToOwners, addCommentTool, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, appNameOver, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaDrift, authSchemaMigration, authStoreTables, backgroundSettled, badRequest, batchWriteTool, beforeSignInPluginsVariable, betterAuthTokens, capSocketMessages, changesMigration, channelSendsMigration, checkAi, checkAuthSchema, checkChanges, checkChannelSends, checkComments, checkComputed, checkJobsSchema, checkNotificationsSchema, checkQueryRunner, checkRealtimeRelay, checkResourcesOutsideAuthStore, checkSourceNames, checkViewQueries, checkWebhooksSchema, coalesce, commentTools, commentsMigration, computedMigration, configExports, consoleAuditQueue, conversationKey, countRecordsTool, createAdmin, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createRecordTool, createUser, defaultAppName, defaultHistoryPage, defaultSignInPolicy, defineEmail, defineFunction, defineJob, defineTool, deleteRecordTool, deleteUser, describeResourceTool, deviceIdParam, deviceStore, devicesPath, enqueueJob, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, generateVapidKeys, getRecordTool, goTruePath, handleDroppedConnections, hasUsers, historyIdParam, historyIdPattern, historyLimits, historyPath, historyStore, honorSocketMessageCaps, imageSize, isBackgroundWork, isCaptured, isJobDefinition, isOAuthWellKnownPath, isSchedule, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, jwtVerifier, limitedFileStore, listCommentsTool, listOrganizations, listRecordsTool, listResourcesTool, listUsers, localFileStore, longQueryTimeoutMs, mapSettings, mapStyleUrl, mapStyleVariable, maxDevicesPerUser, maxHistoryPage, maxMessageBytes, maxRecipients, maxTokenTtlSeconds, maxTtlSeconds, maxUnreadCount, maxWidgetPropsBytes, mcpApprovals, mcpGate, mcpHandler, mcpIcons, mcpInstructions, mcpRoutes, mcpServer, mcpToolContext, mcpTools, migrationCommand, newWebhookSecret, normalizeRoles, notFound, notificationSenders, notificationsMigration, oauthWellKnownPaths, objectKey, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, poolWaitMs, postgresDeviceStore, postgresHistoryStore, processor, pushMessage, queryRunnerMigration, readDbConnections, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readVapidSettings, readWriteQueryTool, readableResources, realtimeLimits, realtimeRelayMigration, recordOf, refusalOf, refused, relayed, removeDevicesWithUsers, removeHistoryWithUsers, removeMember, renderVariant, requestApproval, requireEnv, resourceChange, roleChoices, runInBackground, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, s3FileStore, seesAssistant, seesRuntime, sendNotification, sessionOf, setMemberRoles, setUserBanned, setUserRole, shownAppName, signInPolicyMethods, socketMessageCapOf, sourceOptions, sourcesFor, sourcesVariable, sqlSends, startErrorReporting, startJobs, storageCleanupSchedule, storageProvider, storeFile, storeUsage, streamChatCompletion, subscription, supabasePath, thumbHash, unauthorized, updateRecordTool, urgencies, vapidPrivateKeyVariable, vapidPublicKeyVariable, vapidSubjectVariable, variantPath, verifySignature, verifyStandardWebhook, waitUntil, wantsLongQueries, webManifestPath, webPushSender, webauthnPath, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps, writeRecordTools };
135
+ export { ConnectionsBusy, DeviceStoreError, FatalJobError, HistoryStoreError, HttpProblem, MissingCredentials, ModelError, NotificationSendError, PushMessageError, addAppRoleToOwners, addCommentTool, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, appNameOver, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaDrift, authSchemaMigration, authStoreTables, backgroundSettled, badRequest, batchWriteTool, beforeSignInPluginsVariable, betterAuthTokens, callsMigration, capSocketMessages, changesMigration, channelSendsMigration, checkAi, checkAuthSchema, checkCalls, checkChanges, checkChannelSends, checkComments, checkComputed, checkJobsSchema, checkNotificationsSchema, checkQueryRunner, checkRealtimeRelay, checkResourcesOutsideAuthStore, checkSourceNames, checkStatusSchema, checkViewQueries, checkWebhooksSchema, coalesce, commentTools, commentsMigration, computedMigration, configExports, consoleAuditQueue, conversationKey, countRecordsTool, createAdmin, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createRecordTool, createUser, defaultAppName, defaultHistoryPage, defaultSignInPolicy, defineEmail, defineFunction, defineJob, defineTool, deleteRecordTool, deleteUser, describeResourceTool, deviceIdParam, deviceStore, devicesPath, enqueueJob, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, generateVapidKeys, getRecordTool, goTruePath, handleDroppedConnections, hasUsers, historyIdParam, historyIdPattern, historyLimits, historyPath, historyStore, honorSocketMessageCaps, imageSize, isBackgroundWork, isCaptured, isJobDefinition, isOAuthWellKnownPath, isSchedule, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, jwtVerifier, limitedFileStore, listCommentsTool, listOrganizations, listRecordsTool, listResourcesTool, listUsers, localFileStore, longQueryTimeoutMs, mapSettings, mapStyleUrl, mapStyleVariable, maxDevicesPerUser, maxHistoryPage, maxMessageBytes, maxRecipients, maxTokenTtlSeconds, maxTtlSeconds, maxUnreadCount, maxWidgetPropsBytes, mcpApprovals, mcpGate, mcpHandler, mcpIcons, mcpInstructions, mcpRoutes, mcpServer, mcpToolContext, mcpTools, migrationCommand, newWebhookSecret, normalizeRoles, notFound, notificationSenders, notificationsMigration, oauthWellKnownPaths, objectKey, onDoNotDisturb, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, poolWaitMs, postgresDeviceStore, postgresHistoryStore, processor, pushMessage, queryRunnerMigration, readDbConnections, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readVapidSettings, readWriteQueryTool, readableResources, realtimeLimits, realtimeRelayMigration, recordOf, refusalOf, refused, relayed, removeDevicesWithUsers, removeHistoryWithUsers, removeMember, renderVariant, requestApproval, requireEnv, resourceChange, roleChoices, runInBackground, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, s3FileStore, seesAssistant, seesRuntime, sendNotification, sessionOf, setMemberRoles, setUserBanned, setUserRole, shownAppName, signInPolicyMethods, socketMessageCapOf, sourceOptions, sourcesFor, sourcesVariable, sqlSends, startErrorReporting, startJobs, statusMigration, statusNames, storageCleanupSchedule, storageProvider, storeFile, storeUsage, streamChatCompletion, subscription, supabasePath, thumbHash, unauthorized, updateRecordTool, urgencies, vapidPrivateKeyVariable, vapidPublicKeyVariable, vapidSubjectVariable, variantPath, verifySignature, verifyStandardWebhook, waitUntil, wantsLongQueries, webManifestPath, webPushSender, webauthnPath, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps, writeRecordTools };
@@ -1,5 +1,6 @@
1
1
  import { checkNotificationsOptions } from "./notifications/options.js";
2
2
  import { checkCallsOptions } from "./calls/calls-options.js";
3
+ import { checkStatusOptions } from "./status/options.js";
3
4
  import { isSubscription } from "./webhooks/subscription.js";
4
5
  import { appPool, longQueryPool } from "./app-pool.js";
5
6
  import { AppAuthInput, appAuthOptions, buildAppAuth } from "./better-auth/auth-settings.js";
@@ -11,4 +12,4 @@ import { fileProviderOf } from "./files/provider-settings.js";
11
12
  import { declaredJob } from "./jobs/declared-job.js";
12
13
  import { AuthPlugins, buildAuth, createAuth, loadAuthPlugins } from "./better-auth/create-auth.js";
13
14
  import { webhooksModule } from "./webhooks/table/webhooks-module.js";
14
- export { type AppAuthInput, type AuthPlugins, appAuthOptions, appPool, betterAuthAuthenticator, buildAppAuth, buildAuth, buildAuthenticator, checkCallsOptions, checkNotificationsOptions, createAuth, declaredJob, fileProviderOf, isSubscription, loadAuthPlugins, localFiles, longQueryPool, s3Files, webhooksModule };
15
+ export { type AppAuthInput, type AuthPlugins, appAuthOptions, appPool, betterAuthAuthenticator, buildAppAuth, buildAuth, buildAuthenticator, checkCallsOptions, checkNotificationsOptions, checkStatusOptions, createAuth, declaredJob, fileProviderOf, isSubscription, loadAuthPlugins, localFiles, longQueryPool, s3Files, webhooksModule };
package/dist/internal.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { buildAuth, createAuth, loadAuthPlugins } from "./better-auth/create-auth.js";
2
2
  import { isSubscription } from "./webhooks/subscription.js";
3
3
  import { checkNotificationsOptions } from "./notifications/options.js";
4
+ import { checkStatusOptions } from "./status/options.js";
4
5
  import { localFiles } from "./files/local-files.js";
5
6
  import { s3Files } from "./files/s3-files.js";
6
7
  import { appPool, longQueryPool } from "./app-pool.js";
@@ -11,4 +12,4 @@ import { appAuthOptions, buildAppAuth } from "./better-auth/auth-settings.js";
11
12
  import { buildAuthenticator } from "./better-auth/authenticate-settings.js";
12
13
  import { webhooksModule } from "./webhooks/table/webhooks-module.js";
13
14
  import { checkCallsOptions } from "./calls/calls-options.js";
14
- export { appAuthOptions, appPool, betterAuthAuthenticator, buildAppAuth, buildAuth, buildAuthenticator, checkCallsOptions, checkNotificationsOptions, createAuth, declaredJob, fileProviderOf, isSubscription, loadAuthPlugins, localFiles, longQueryPool, s3Files, webhooksModule };
15
+ export { appAuthOptions, appPool, betterAuthAuthenticator, buildAppAuth, buildAuth, buildAuthenticator, checkCallsOptions, checkNotificationsOptions, checkStatusOptions, createAuth, declaredJob, fileProviderOf, isSubscription, loadAuthPlugins, localFiles, longQueryPool, s3Files, webhooksModule };
package/dist/meta.d.ts CHANGED
@@ -59,6 +59,8 @@ export type CallerMeta = {
59
59
  bell?: true;
60
60
  webPushKey?: string;
61
61
  };
62
+ /** With `status: {}`: people set their own status, and see the statuses of those they share an organization with. */
63
+ status?: true;
62
64
  /** The language the admin app's screens are in, when the app sets one for everyone. */
63
65
  locale?: Locale;
64
66
  /** The hosts besides the app's own whose images the admin app draws with the page's referrer, when there are any. */