palbase 0.5.2 → 0.7.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/ai/index.js +2 -14
- package/dist/backend/engine.js +2 -2
- package/dist/backend/env.js +1 -1
- package/dist/backend/index.js +7 -7
- package/dist/backend/stack.js +1 -1
- package/dist/backend/test.js +2 -2
- package/dist/chunks/3ALGILOX.js +2 -0
- package/dist/chunks/{6I6CETZY.js → 5ZJCEQV5.js} +3 -3
- package/dist/chunks/AIIKXCWN.js +2 -0
- package/dist/chunks/{LHLMCQKI.js → BKVU4I5R.js} +2 -2
- package/dist/chunks/ELEE7XO2.js +18 -0
- package/dist/chunks/{ZJOO2XZ2.js → G3BK7L3J.js} +2 -2
- package/dist/chunks/G7E26S3Y.js +13 -0
- package/dist/chunks/H2EPK74V.js +20 -0
- package/dist/chunks/{EDVRVUCJ.js → HEXIIGWS.js} +2 -2
- package/dist/chunks/{HLYQRT7O.js → JS3TTUHS.js} +2 -2
- package/dist/chunks/{NQA7ZLGD.js → KDSWK3XW.js} +1 -1
- package/dist/chunks/{XRW7YOUQ.js → L3NTI4AZ.js} +2 -2
- package/dist/chunks/LEBVOSG6.js +4 -0
- package/dist/chunks/OIA7KLRW.js +2 -0
- package/dist/chunks/{4ZVJ62A3.js → PJVWGUIT.js} +1 -1
- package/dist/chunks/{MYNCDAKM.js → SU7BP6VF.js} +1 -1
- package/dist/chunks/{TPBWIRHS.js → X3MTLJRV.js} +1 -1
- package/dist/chunks/{5G3URQAW.js → ZBOJEH7K.js} +2 -2
- package/dist/cli.js +133 -133
- package/dist/refuse/ai.js +1 -1
- package/dist/refuse/backend.js +1 -1
- package/dist/refuse/server.js +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/testing.js +2 -2
- package/dist/web/index.js +2 -2
- package/dist/web/palbe.js +2 -2
- package/dist/web/paywall.js +2 -2
- package/dist/web/ssr.js +2 -0
- package/dist/web/vite.js +2 -2
- package/package.json +6 -2
- package/types/ai/src/ai.d.ts +2 -4
- package/types/ai/src/chats.d.ts +40 -10
- package/types/ai/src/index.d.ts +2 -2
- package/types/ai/src/tools.d.ts +3 -8
- package/types/backend/src/container.d.ts +2 -2
- package/types/backend/src/engine.d.ts +1 -4
- package/types/backend/src/gateways.d.ts +250 -0
- package/types/backend/src/index.d.ts +2 -2
- package/types/backend/src/openapi.d.ts +3 -6
- package/types/backend/src/runtime.d.ts +39 -2
- package/types/internal/src/chat.d.ts +7 -39
- package/types/internal/src/modules/ai.d.ts +68 -35
- package/types/internal/src/modules/realtime.d.ts +9 -1
- package/types/web/src/backends.d.ts +19 -12
- package/types/web/src/chat.d.ts +118 -0
- package/types/web/src/client.d.ts +3 -4
- package/types/web/src/gateways.d.ts +89 -0
- package/types/web/src/index.d.ts +4 -4
- package/types/web/src/session.d.ts +11 -0
- package/types/web/src/socket.d.ts +18 -2
- package/types/web/src/ssr.d.ts +86 -0
- package/dist/chunks/FNUO6DSY.js +0 -4
- package/dist/chunks/JHQDWDV3.js +0 -13
- package/dist/chunks/K2LVOEW3.js +0 -20
- package/dist/chunks/QHJ4OPPI.js +0 -2
- package/dist/chunks/QHPZF7VM.js +0 -6
- package/types/backend/src/channels.d.ts +0 -81
- package/types/backend/src/rooms.d.ts +0 -178
- package/types/web/src/ai.d.ts +0 -224
- package/types/web/src/rooms.d.ts +0 -61
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import type { realtime } from '../../internal/src/modules/index.js';
|
|
2
|
+
import { type StandardSchemaV1 } from './decorators.js';
|
|
3
|
+
import { type SignedUser } from './platform-calls.js';
|
|
4
|
+
export declare const GATEWAY: unique symbol;
|
|
5
|
+
export declare const GATEWAY_HOOKS: unique symbol;
|
|
6
|
+
/** The moments a gateway's methods are told of. */
|
|
7
|
+
export type GatewayHook = 'authorize' | 'first' | 'connect' | 'disconnect' | 'empty';
|
|
8
|
+
export interface GatewayOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Who may join, decided by realtime: 'owner' — the pattern's one {param}
|
|
11
|
+
* is the joining user's id; 'public' — any signed-in user. Left out, an
|
|
12
|
+
* @Authorize method decides.
|
|
13
|
+
*/
|
|
14
|
+
access?: 'owner' | 'public';
|
|
15
|
+
/**
|
|
16
|
+
* Members broadcast to each other, as realtime carries it — a gateway of
|
|
17
|
+
* no method only: one with methods takes its members' messages itself
|
|
18
|
+
* (@Subscribe).
|
|
19
|
+
*/
|
|
20
|
+
publish?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Keeps what it sends: true a day, or { keepSeconds } (1 to 604800). A
|
|
23
|
+
* member that was away is sent what it missed, in order, once — a chat's
|
|
24
|
+
* stream that a phone walking out of range does not lose.
|
|
25
|
+
*/
|
|
26
|
+
durable?: boolean | {
|
|
27
|
+
keepSeconds: number;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* How long it is held after its last member left before it is empty
|
|
31
|
+
* (@OnEmpty), in milliseconds: 60000 unless said.
|
|
32
|
+
*/
|
|
33
|
+
graceMs?: number;
|
|
34
|
+
/**
|
|
35
|
+
* It carries a chat of the project's agents (ctx.pipe(Palbase.ai.chats.events(id))):
|
|
36
|
+
* its event `chat` is the platform's — the chat's parts — and every
|
|
37
|
+
* generated client holds the chat's state for its view (messages, the
|
|
38
|
+
* answer as it is written, tools, approvals). Kept a day unless durable
|
|
39
|
+
* says how long: a member that comes later, or was away, has the chat.
|
|
40
|
+
*/
|
|
41
|
+
chat?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Something the platform writes into a gateway's channel itself, the backend
|
|
45
|
+
* not in it: a chat's stream (Palbase.ai.chats.events(id)).
|
|
46
|
+
*/
|
|
47
|
+
export interface PipeSource {
|
|
48
|
+
pipe(topic: string, options?: {
|
|
49
|
+
signal?: AbortSignal;
|
|
50
|
+
}): Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
/** The platform's event of a chat-carrying gateway: one part of the chat (its type, the journal's number, its data). */
|
|
53
|
+
export declare const ChatPart: StandardSchemaV1<{
|
|
54
|
+
type: string;
|
|
55
|
+
id?: number;
|
|
56
|
+
data: Record<string, unknown>;
|
|
57
|
+
}>;
|
|
58
|
+
/**
|
|
59
|
+
* Thrown by a @Subscribe: the member's message is refused, with this reason —
|
|
60
|
+
* the client's GatewayError.reason, a word the app chose for its own app to
|
|
61
|
+
* act on ('not_your_turn', 'too_many_messages'). What the method wrote is
|
|
62
|
+
* rolled back. Anything else a method throws is the app's log's: its words
|
|
63
|
+
* could carry anything, and the member is told handler_failed.
|
|
64
|
+
*/
|
|
65
|
+
export declare class GatewayRefusal extends Error {
|
|
66
|
+
readonly reason: string;
|
|
67
|
+
constructor(reason: string);
|
|
68
|
+
}
|
|
69
|
+
/** What a gateway class declares its events with: `static readonly events = { name: schema }`. */
|
|
70
|
+
export interface GatewayEvents {
|
|
71
|
+
readonly events?: Readonly<Record<string, StandardSchemaV1>>;
|
|
72
|
+
}
|
|
73
|
+
/** A gateway as its decorators declare it. */
|
|
74
|
+
export interface GatewayDeclaration {
|
|
75
|
+
/** The class's name: its client's, in every generated client. */
|
|
76
|
+
name: string;
|
|
77
|
+
pattern: string;
|
|
78
|
+
access?: 'owner' | 'public';
|
|
79
|
+
publish: boolean;
|
|
80
|
+
/** How long it keeps what it sends, in seconds: 0 keeps nothing. */
|
|
81
|
+
logKeepSeconds: number;
|
|
82
|
+
/** It carries a chat (GatewayOptions.chat): its event `chat` is the chat's parts. */
|
|
83
|
+
chat: boolean;
|
|
84
|
+
events: Record<string, StandardSchemaV1>;
|
|
85
|
+
graceMs: number;
|
|
86
|
+
/** Each moment, the method told of it. */
|
|
87
|
+
hooks: Partial<Record<GatewayHook, string>>;
|
|
88
|
+
/** Each message a member may send: its method, its payload's schema, and its ack's when said — an object of no prototype, whatever the names. */
|
|
89
|
+
messages: Record<string, {
|
|
90
|
+
fn: string;
|
|
91
|
+
schema: StandardSchemaV1;
|
|
92
|
+
reply?: StandardSchemaV1;
|
|
93
|
+
}>;
|
|
94
|
+
}
|
|
95
|
+
/** Whether the machine serves it — a method of it is told of something — or realtime decides it alone. */
|
|
96
|
+
export declare const servedByTheApp: (g: GatewayDeclaration) => boolean;
|
|
97
|
+
/** Who a member is, to a gateway's methods. */
|
|
98
|
+
export interface GatewayUser {
|
|
99
|
+
/** The user's id; "" in @OnFirst and @OnEmpty, which no one in particular caused. */
|
|
100
|
+
id: string;
|
|
101
|
+
}
|
|
102
|
+
/** What @Authorize is given: who asks to join, and the channel's parameters. */
|
|
103
|
+
export interface GatewayAuthorizeContext {
|
|
104
|
+
user: GatewayUser;
|
|
105
|
+
params: Readonly<Record<string, string>>;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* What @Authorize answers: true lets the user in to hear and to send; an
|
|
109
|
+
* object says which — { read: false } is no way in, { write: false } a
|
|
110
|
+
* listener who may not send; null, undefined or false keep the user out. So
|
|
111
|
+
* does any other answer, and a method that throws: only a grant lets anyone
|
|
112
|
+
* in, and the app's log says what was answered instead.
|
|
113
|
+
*/
|
|
114
|
+
export type GatewayGrant = boolean | null | undefined | {
|
|
115
|
+
read?: boolean;
|
|
116
|
+
write?: boolean;
|
|
117
|
+
};
|
|
118
|
+
/** What a gateway's moments are given (@OnFirst, @OnConnect, @OnDisconnect, @OnEmpty). */
|
|
119
|
+
export interface GatewayContext {
|
|
120
|
+
/** The channel: "chat:42". */
|
|
121
|
+
channel: string;
|
|
122
|
+
/** The pattern's parameters: { chatId: "42" }. */
|
|
123
|
+
params: Readonly<Record<string, string>>;
|
|
124
|
+
/**
|
|
125
|
+
* The channel's own: aborted when it empties (before @OnEmpty runs), or
|
|
126
|
+
* when owner.release() gives it up — what @OnFirst started stops on it.
|
|
127
|
+
*/
|
|
128
|
+
signal: AbortSignal;
|
|
129
|
+
/** Its members now, across realtime's replicas; 0 in a @Subscribe. */
|
|
130
|
+
count: number;
|
|
131
|
+
user: GatewayUser;
|
|
132
|
+
/**
|
|
133
|
+
* An event to the channel's members — in @OnConnect, to the member who
|
|
134
|
+
* joined alone. Sent in the order emitted, and never thrown: what could
|
|
135
|
+
* not be sent is in the app's log.
|
|
136
|
+
*/
|
|
137
|
+
emit(event: string, payload?: unknown): void;
|
|
138
|
+
/**
|
|
139
|
+
* The platform writes `source` into this channel from now on — a chat's
|
|
140
|
+
* stream: `ctx.pipe(Palbase.ai.chats.events(chatId))`. The backend is not
|
|
141
|
+
* in the stream after; the gateway's members hear it.
|
|
142
|
+
*/
|
|
143
|
+
pipe(source: PipeSource): Promise<void>;
|
|
144
|
+
owner: {
|
|
145
|
+
/** Runs `work` past the method, until the channel's signal aborts: an upstream's loop. Its failure is logged, never the app's crash. */
|
|
146
|
+
hold(work: (signal: AbortSignal) => unknown): void;
|
|
147
|
+
/** Gives the channel up now: its signal aborts, and the next member to come finds it unheld (@OnFirst again). */
|
|
148
|
+
release(): void;
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/** What a @Subscribe is given: the channel's context, the member, and the payload as its schema made it. */
|
|
152
|
+
export interface GatewayMessageContext<P = unknown> extends GatewayContext {
|
|
153
|
+
payload: P;
|
|
154
|
+
}
|
|
155
|
+
/** v2 held a room a minute after its last member: twice the slowest client's heartbeat, and margin. */
|
|
156
|
+
export declare const DEFAULT_GRACE_MS = 60000;
|
|
157
|
+
/** A durable gateway keeps what it sends a day unless it says; a week at most. */
|
|
158
|
+
export declare const DEFAULT_KEEP_SECONDS = 86400;
|
|
159
|
+
export declare const MAX_KEEP_SECONDS = 604800;
|
|
160
|
+
/** The most a @Subscribe's ack carries (realtime's roomReplyMax). */
|
|
161
|
+
export declare const MAX_REPLY_BYTES: number;
|
|
162
|
+
/**
|
|
163
|
+
* Why `pattern` is no gateway's, or undefined. A pattern is a channel's: ':'
|
|
164
|
+
* segments, a "{name}" segment taking exactly one — and realtime takes a
|
|
165
|
+
* pattern it cannot decide for no channel at all, silently: the gateway
|
|
166
|
+
* would compile, ship and never be joined. So everything it would not take is
|
|
167
|
+
* refused here, by name, while someone is looking.
|
|
168
|
+
*/
|
|
169
|
+
export declare function patternProblem(pattern: string): string | undefined;
|
|
170
|
+
/**
|
|
171
|
+
* A class whose methods manage the channels `pattern` names (see the top of
|
|
172
|
+
* this file). It is a provider a module lists (its constructor injected as
|
|
173
|
+
* any provider's), built once: what @OnFirst starts and @OnEmpty stops lives
|
|
174
|
+
* in it. Its events are its class's `static readonly events`.
|
|
175
|
+
*/
|
|
176
|
+
export declare function Gateway(pattern: string, options?: GatewayOptions): ClassDecorator;
|
|
177
|
+
/** Who may join: answers a GatewayGrant (GatewayAuthorizeContext) — for a gateway with no access of realtime's. */
|
|
178
|
+
export declare const Authorize: () => MethodDecorator;
|
|
179
|
+
/**
|
|
180
|
+
* The channel is occupied and held by no one: start what it needs. Told once
|
|
181
|
+
* across realtime's replicas when its first member comes — before that
|
|
182
|
+
* member is answered — and again only after it emptied.
|
|
183
|
+
*/
|
|
184
|
+
export declare const OnFirst: () => MethodDecorator;
|
|
185
|
+
/** A member joined (after it was answered): what it emits goes to that member alone. */
|
|
186
|
+
export declare const OnConnect: () => MethodDecorator;
|
|
187
|
+
/** A member left. */
|
|
188
|
+
export declare const OnDisconnect: () => MethodDecorator;
|
|
189
|
+
/** Nobody has been on the channel for its graceMs: stop what @OnFirst started. Its signal is aborted already. */
|
|
190
|
+
export declare const OnEmpty: () => MethodDecorator;
|
|
191
|
+
/**
|
|
192
|
+
* A message a member sends, `name`, its payload checked against `schema`
|
|
193
|
+
* before the method runs (GatewayMessageContext): a payload that does not
|
|
194
|
+
* fit never reaches it, and the member hears why. What the method returns
|
|
195
|
+
* is the member's ack — `reply` its schema in every generated client.
|
|
196
|
+
*/
|
|
197
|
+
export declare function Subscribe(name: string, schema: StandardSchemaV1, options?: {
|
|
198
|
+
reply?: StandardSchemaV1;
|
|
199
|
+
}): MethodDecorator;
|
|
200
|
+
/** The gateway a class declares, or undefined: a gateway is one by its decorator, never its name. */
|
|
201
|
+
export declare function gatewayOf(cls: Function): GatewayDeclaration | undefined;
|
|
202
|
+
/** A gateway's channel's parameters, or undefined when the channel is not one of its. */
|
|
203
|
+
export declare function matchChannel(pattern: string, channel: string): Record<string, string> | undefined;
|
|
204
|
+
/** The channel of a gateway's parameters: each named by its pattern, a whole segment — or why not. */
|
|
205
|
+
export declare function channelOf(pattern: string, params: Readonly<Record<string, unknown>>): string | {
|
|
206
|
+
problem: string;
|
|
207
|
+
};
|
|
208
|
+
/** One event to a gateway's members, as realtime's broadcast takes it: its channel (topic), and conn_id for one membership alone. */
|
|
209
|
+
type GatewayBroadcast = realtime.BroadcastMessage;
|
|
210
|
+
export interface GatewayDeps {
|
|
211
|
+
/**
|
|
212
|
+
* `work` as the platform's caller names it — in a transaction as `user`,
|
|
213
|
+
* or as the app itself when the moment is no one's (first, empty) —
|
|
214
|
+
* committed unless it throws, or the platform hung up before it ended.
|
|
215
|
+
*/
|
|
216
|
+
run<T>(user: SignedUser | undefined, where: string, signal: AbortSignal | undefined, work: () => Promise<T>): Promise<T>;
|
|
217
|
+
/** realtime's POST /realtime/broadcast, as the app (its secret key). */
|
|
218
|
+
broadcast(messages: GatewayBroadcast[]): Promise<unknown>;
|
|
219
|
+
/** The platform's infrastructure, not the method, failed: the call is answered 503, and realtime asks again. */
|
|
220
|
+
isOutage(e: unknown): boolean;
|
|
221
|
+
}
|
|
222
|
+
/** What a gateway's call is answered: JSON, nothing (204), or a refusal. */
|
|
223
|
+
export type GatewayAnswer = {
|
|
224
|
+
status: 200;
|
|
225
|
+
body: unknown;
|
|
226
|
+
} | {
|
|
227
|
+
status: 204;
|
|
228
|
+
} | {
|
|
229
|
+
status: number;
|
|
230
|
+
code: string;
|
|
231
|
+
message: string;
|
|
232
|
+
retryAfter?: number;
|
|
233
|
+
};
|
|
234
|
+
export interface Gateways {
|
|
235
|
+
readonly declarations: readonly GatewayDeclaration[];
|
|
236
|
+
/** The platform's call about a gateway — authorize, message or lifecycle — its JSON body. */
|
|
237
|
+
serve(kind: string, body: unknown, signal?: AbortSignal): Promise<GatewayAnswer>;
|
|
238
|
+
/** An event to a gateway's channel from anywhere in the app (Palbase.gateways.to). */
|
|
239
|
+
emit(cls: Function, params: Readonly<Record<string, unknown>>, event: string, payload: unknown): void;
|
|
240
|
+
/** A source piped into a gateway's channel from anywhere in the app (Palbase.gateways.to(…).pipe). */
|
|
241
|
+
pipe(cls: Function, params: Readonly<Record<string, unknown>>, source: PipeSource): Promise<void>;
|
|
242
|
+
/** Every channel let go: what was held is aborted (the app is stopping). */
|
|
243
|
+
close(): void;
|
|
244
|
+
}
|
|
245
|
+
/** The app's gateways, served: `classes` its providers that are gateways, each with its instance. */
|
|
246
|
+
export declare function createGateways(classes: {
|
|
247
|
+
cls: Function;
|
|
248
|
+
instance: object;
|
|
249
|
+
}[], deps: GatewayDeps): Gateways;
|
|
250
|
+
export {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
2
|
export { Body, Client, Controller, Delete, Get, getRegisteredControllers, getRoutes, Headers, Cron, Injectable, Module, On, OptionalUser, Param, Patch, Post, Put, Query, QueryParams, Req, RequestId, Resolve, TraceId, User, Webhook, type AuthConfig, type AuthSpec, type ControllerOptions, type EventHandler, type CronMeta, type CronOptions, type ModuleDef, type OnOptions, type ParamResolver, type RateLimitConfig, type ResolveContext, type RouteInfo, type RouteOptions, type SignatureSpec, type StandardSchemaV1, type Token, type WebhookOptions, type WebhookProvider, } from './decorators.js';
|
|
3
3
|
export { Task, TaskFailure, Tasks, type EnqueueOptions, type PayloadOf, type QueuedTask, type TaskClass, type TaskMeta, type TaskOptions, type TasksService } from './tasks.js';
|
|
4
|
-
export { defineChannels, ownerOnly, publicChannel, type ChannelAuthorizeCtx, type ChannelEntry, type ChannelGrant, type ChannelsDef, type ChannelsInput } from './channels.js';
|
|
5
4
|
export { Upload, UploadedObject, type UploadConfig } from './upload.js';
|
|
6
|
-
export {
|
|
5
|
+
export { Authorize, ChatPart, Gateway, GatewayRefusal, OnConnect, OnDisconnect, OnEmpty, OnFirst, Subscribe, type GatewayAuthorizeContext, type GatewayContext, type GatewayEvents, type GatewayGrant, type GatewayMessageContext, type GatewayOptions, type GatewayUser, type PipeSource, } from './gateways.js';
|
|
6
|
+
export type { GatewaysApi, GatewayTarget } from './runtime.js';
|
|
7
7
|
export { getWebhookManifest, type WebhookEventHandler, type WebhookMeta } from './webhooks.js';
|
|
8
8
|
export { DiError, type DiErrorKind } from './container.js';
|
|
9
9
|
export { BadRequest, Conflict, DeadlockDetected, Forbidden, HttpError, NotFound, PalError, SerializationFailure, TooManyRequests, Unauthorized, UniqueViolation, defineError, type DefinedError, type DefinedErrorWithData, type Envelope, type FieldIssue, } from './errors.js';
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { RateLimitConfig, StandardSchemaV1 } from './decorators.js';
|
|
2
2
|
import type { RegisteredError } from './errors.js';
|
|
3
|
-
import type
|
|
4
|
-
import type { RoomDeclaration } from './rooms.js';
|
|
3
|
+
import { type GatewayDeclaration } from './gateways.js';
|
|
5
4
|
import type { Route } from './router.js';
|
|
6
5
|
/** Where the platform delivers the project's events to the app. */
|
|
7
6
|
export declare const PLATFORM_EVENTS_PATH = "/webhooks/palbase";
|
|
@@ -33,10 +32,8 @@ export interface ContractOptions {
|
|
|
33
32
|
routes?: (route: Route) => RouteContract | undefined;
|
|
34
33
|
/** The release's errors by wire code (defineError's registry): what a thrown code is typed as. */
|
|
35
34
|
errors?: ReadonlyMap<string, RegisteredError>;
|
|
36
|
-
/** The app's @
|
|
37
|
-
|
|
38
|
-
/** The owner and public channels defineChannels declares, in its order: x-palbase-channels, decided by realtime itself. */
|
|
39
|
-
channels?: readonly ChannelRow[];
|
|
35
|
+
/** The app's @Gateway classes, as their decorators declare them. */
|
|
36
|
+
gateways?: readonly GatewayDeclaration[];
|
|
40
37
|
}
|
|
41
38
|
/** What a route answers and throws, as its source declares. */
|
|
42
39
|
export interface RouteContract {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { type AI } from '../../ai/src/index.js';
|
|
2
3
|
import type { PalbaseServer } from '../../server/src/index.js';
|
|
3
4
|
import type { AtomicDatabase as AtomicOf, EnvTypedDatabase } from 'palgres';
|
|
4
5
|
import type { Schemas, Tables } from './db-env.js';
|
|
@@ -29,8 +30,43 @@ export declare function scoped<T extends object>(name: string, impl: T): T;
|
|
|
29
30
|
*/
|
|
30
31
|
export declare function serviceOf<T extends object>(name: string, key: PropertyKey, impl: T): T;
|
|
31
32
|
export declare const requestScope: AsyncLocalStorage<RequestScope>;
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
type GatewayEventsOf<G> = G extends {
|
|
34
|
+
readonly events: infer E;
|
|
35
|
+
} ? E : Record<never, never>;
|
|
36
|
+
type GatewayPayloadOf<S> = S extends {
|
|
37
|
+
readonly '~standard': {
|
|
38
|
+
readonly types?: {
|
|
39
|
+
readonly input: infer I;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
} ? I : unknown;
|
|
43
|
+
/** A gateway's channel, to send its events to (Palbase.gateways.to). */
|
|
44
|
+
export interface GatewayTarget<G> {
|
|
45
|
+
/**
|
|
46
|
+
* `event` to every member of the channel, its payload as the gateway's
|
|
47
|
+
* static events type it. Sent in the order emitted, never thrown: what could
|
|
48
|
+
* not be sent is in the app's log. A durable gateway keeps it.
|
|
49
|
+
*/
|
|
50
|
+
emit<K extends keyof GatewayEventsOf<G> & string>(event: K, payload: GatewayPayloadOf<GatewayEventsOf<G>[K]>): void;
|
|
51
|
+
/** The platform writes `source` into the channel from now on: a chat's stream (Palbase.ai.chats.events(id)). */
|
|
52
|
+
pipe(source: {
|
|
53
|
+
pipe(topic: string): Promise<void>;
|
|
54
|
+
}): Promise<void>;
|
|
55
|
+
}
|
|
56
|
+
/** The app's gateways, from any service: Palbase.gateways.to(ChatGateway, { chatId }).emit('token', { text }). */
|
|
57
|
+
export interface GatewaysApi {
|
|
58
|
+
to<G extends Function>(gateway: G, params: Readonly<Record<string, string>>): GatewayTarget<G>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The project as the app's server reaches it: its modules — auth, storage, notify, secrets, flags, analytics,
|
|
62
|
+
* realtime, machines — its models and agents (Palbase.ai: ask, generate, stream, embed, tools, agents, chats), and
|
|
63
|
+
* the app's gateways (Palbase.gateways).
|
|
64
|
+
*/
|
|
65
|
+
export type PalbaseApp = Omit<PalbaseServer, 'ai'> & {
|
|
66
|
+
readonly ai: AI;
|
|
67
|
+
readonly gateways: GatewaysApi;
|
|
68
|
+
};
|
|
69
|
+
export declare const Palbase: PalbaseApp;
|
|
34
70
|
/**
|
|
35
71
|
* The request's database, as v2's: `Database.public.<table>`, `$query`,
|
|
36
72
|
* `$transaction`, `$atomic`, `$asService()`. It is the request's own
|
|
@@ -54,3 +90,4 @@ export declare const Log: {
|
|
|
54
90
|
warn: (message: string, fields?: Record<string, unknown>) => void;
|
|
55
91
|
error: (message: string, fields?: Record<string, unknown>) => void;
|
|
56
92
|
};
|
|
93
|
+
export {};
|
|
@@ -88,46 +88,14 @@ export interface AgentEvent {
|
|
|
88
88
|
reason?: string;
|
|
89
89
|
[field: string]: unknown;
|
|
90
90
|
}
|
|
91
|
-
|
|
92
|
-
export interface VoiceEvent {
|
|
93
|
-
type: 'voice';
|
|
94
|
-
seq: number;
|
|
95
|
-
voice_session_id: string;
|
|
96
|
-
kind: 'transcript' | 'started' | 'closed' | 'delegated';
|
|
97
|
-
/** A transcript's: the member speaking (user) or the voice answering (assistant). */
|
|
98
|
-
role?: 'user' | 'assistant';
|
|
99
|
-
text?: string;
|
|
100
|
-
/** A delegated task's: answer it with the voice's speak and this id. */
|
|
101
|
-
delegation_id?: string;
|
|
102
|
-
task?: string;
|
|
103
|
-
reason?: string;
|
|
104
|
-
seconds?: number;
|
|
105
|
-
[field: string]: unknown;
|
|
106
|
-
}
|
|
107
|
-
export type ChatEvent = MessageEvent | TurnEvent | TextEvent | ResetEvent | ToolEvent | AgentEvent | VoiceEvent;
|
|
108
|
-
/** Where a reader is: what it hands the stream to go on from there. */
|
|
109
|
-
export interface ChatPosition {
|
|
110
|
-
/** The id of the last journal event held. */
|
|
111
|
-
after?: number;
|
|
112
|
-
/** The response whose answer is being read, and the bytes of it held. */
|
|
113
|
-
response?: string;
|
|
114
|
-
offset?: number;
|
|
115
|
-
}
|
|
116
|
-
export interface FollowChatOptions extends ChatPosition {
|
|
117
|
-
signal?: AbortSignal;
|
|
118
|
-
/** How long a stream that keeps being cut is followed again before the reader is told (default 2 minutes). */
|
|
119
|
-
resumeFor?: number;
|
|
120
|
-
/** A stream with no byte for this long is taken for cut (default 45 s; the module's heartbeat is more often). */
|
|
121
|
-
idleFor?: number;
|
|
122
|
-
}
|
|
123
|
-
/** The stream's events; its position is where a reader that stops now would go on from. */
|
|
124
|
-
export interface ChatStream extends AsyncIterable<ChatEvent> {
|
|
125
|
-
readonly position: ChatPosition;
|
|
126
|
-
}
|
|
127
|
-
/** Opens the stream from a point: the generated client's followChat, through the caller's transport. */
|
|
128
|
-
export type OpenChatStream = (query: ChatPosition, signal: AbortSignal) => Promise<globalThis.Response>;
|
|
91
|
+
export type ChatEvent = MessageEvent | TurnEvent | TextEvent | ResetEvent | ToolEvent | AgentEvent;
|
|
129
92
|
/** A chat refusal of the module's, said in words its caller can act on; anything else (or one said already) as it was. */
|
|
130
93
|
export declare function chatRefusal(e: unknown): unknown;
|
|
131
94
|
/** The same promise, its chat refusals said as chatRefusal says them. */
|
|
132
95
|
export declare function told<T>(p: Promise<T>): Promise<T>;
|
|
133
|
-
|
|
96
|
+
/**
|
|
97
|
+
* One part of a chat's channel (the payload of its "chat" event) as a chat
|
|
98
|
+
* event — undefined for one this runtime does not read: a newer module's
|
|
99
|
+
* part, or one that is not a part at all.
|
|
100
|
+
*/
|
|
101
|
+
export declare function chatPart(payload: unknown): ChatEvent | undefined;
|
|
@@ -21,10 +21,6 @@ export type AgentDefinition = {
|
|
|
21
21
|
* The project's machine that defines the agent at each turn.
|
|
22
22
|
*/
|
|
23
23
|
backend?: string;
|
|
24
|
-
/**
|
|
25
|
-
* The app's users start chats with this named agent themselves (when the project lets them talk to its agents): an agent the server alone uses is not one they reach.
|
|
26
|
-
*/
|
|
27
|
-
clients?: boolean;
|
|
28
24
|
/**
|
|
29
25
|
* Its instructions.
|
|
30
26
|
*/
|
|
@@ -68,7 +64,7 @@ export type Chat = {
|
|
|
68
64
|
*/
|
|
69
65
|
created_at: string;
|
|
70
66
|
/**
|
|
71
|
-
*
|
|
67
|
+
* Null: the project's server started it, as it starts every chat (a user's id: a chat a user started before chats were the server's alone).
|
|
72
68
|
*/
|
|
73
69
|
created_by: string | null;
|
|
74
70
|
/**
|
|
@@ -153,6 +149,28 @@ export type ChatMessage = {
|
|
|
153
149
|
*/
|
|
154
150
|
text: string;
|
|
155
151
|
};
|
|
152
|
+
/**
|
|
153
|
+
* Where a chat's stream is written.
|
|
154
|
+
*/
|
|
155
|
+
export type ChatPipe = {
|
|
156
|
+
/**
|
|
157
|
+
* A channel of the project's realtime (not one of the platform's: roles:, flags:, purchases:, messaging:, debug:, nor phoenix, realtime's heartbeat).
|
|
158
|
+
*/
|
|
159
|
+
topic: string;
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* A chat's pipe.
|
|
163
|
+
*/
|
|
164
|
+
export type ChatPipeResult = {
|
|
165
|
+
/**
|
|
166
|
+
* The chat's id.
|
|
167
|
+
*/
|
|
168
|
+
chat_id: string;
|
|
169
|
+
/**
|
|
170
|
+
* The channel its stream is written into.
|
|
171
|
+
*/
|
|
172
|
+
topic: string;
|
|
173
|
+
};
|
|
156
174
|
/**
|
|
157
175
|
* One repository of a chat's workspace.
|
|
158
176
|
*/
|
|
@@ -167,11 +185,11 @@ export type ChatRepo = {
|
|
|
167
185
|
repo: string;
|
|
168
186
|
};
|
|
169
187
|
/**
|
|
170
|
-
* A chat to start.
|
|
188
|
+
* A chat to start: the project's server's alone.
|
|
171
189
|
*/
|
|
172
190
|
export type ChatRequest = {
|
|
173
191
|
/**
|
|
174
|
-
* The agent it talks to: a named agent of the project's — or,
|
|
192
|
+
* The agent it talks to: a named agent of the project's — or, with a definition of the chat's own, the server's name for it.
|
|
175
193
|
*/
|
|
176
194
|
agent: string;
|
|
177
195
|
definition?: AgentDefinition;
|
|
@@ -185,10 +203,6 @@ export type ChatRequest = {
|
|
|
185
203
|
metadata?: {
|
|
186
204
|
[key: string]: string;
|
|
187
205
|
};
|
|
188
|
-
/**
|
|
189
|
-
* A user who starts a chat is in it as its owner, under this name.
|
|
190
|
-
*/
|
|
191
|
-
name?: string;
|
|
192
206
|
/**
|
|
193
207
|
* Its title (256 bytes at most).
|
|
194
208
|
*/
|
|
@@ -229,6 +243,10 @@ export type DecisionRequest = {
|
|
|
229
243
|
* Yes, or no.
|
|
230
244
|
*/
|
|
231
245
|
approve: boolean;
|
|
246
|
+
/**
|
|
247
|
+
* The member the project's server acts as: held to that member's rules — their turn (403 not_your_turn) — and the decision is theirs (the server's alone: a user sending it is answered 400; one who is not a member of the chat, 403 not_a_member). Left out, the server acts as itself.
|
|
248
|
+
*/
|
|
249
|
+
as?: string;
|
|
232
250
|
/**
|
|
233
251
|
* Why (told to the agent; 1024 bytes at most).
|
|
234
252
|
*/
|
|
@@ -634,7 +652,7 @@ export type MessagePage = {
|
|
|
634
652
|
*/
|
|
635
653
|
export type MessageRequest = {
|
|
636
654
|
/**
|
|
637
|
-
* The member the server writes as (the server's alone).
|
|
655
|
+
* The member the server writes as (the server's alone: a user sending it is answered 400; one who is not a member of the chat, 403 not_a_member): the message is theirs, and counts toward their messages a minute (429 too_many_messages, as theirs would).
|
|
638
656
|
*/
|
|
639
657
|
as?: string;
|
|
640
658
|
budget?: TurnBudget;
|
|
@@ -928,6 +946,10 @@ export type RunMessageAccepted = {
|
|
|
928
946
|
* A message for a subagent at work.
|
|
929
947
|
*/
|
|
930
948
|
export type RunMessageRequest = {
|
|
949
|
+
/**
|
|
950
|
+
* The member the project's server acts as: held to that member's rules — their messages a minute (429 too_many_messages) — and the message is theirs (the server's alone: a user sending it is answered 400; one who is not a member of the chat, 403 not_a_member). Left out, the server acts as itself.
|
|
951
|
+
*/
|
|
952
|
+
as?: string;
|
|
931
953
|
/**
|
|
932
954
|
* The writer's id for it.
|
|
933
955
|
*/
|
|
@@ -942,7 +964,7 @@ export type RunMessageRequest = {
|
|
|
942
964
|
*/
|
|
943
965
|
export type Settings = {
|
|
944
966
|
/**
|
|
945
|
-
* Whether the app's users talk to the project's agents with their own session:
|
|
967
|
+
* Whether the app's users talk to the project's agents with their own session: read and write to the chats they are in (the project's server starts them).
|
|
946
968
|
*/
|
|
947
969
|
clients: boolean;
|
|
948
970
|
/**
|
|
@@ -1051,6 +1073,10 @@ export type ToolContent = {
|
|
|
1051
1073
|
* What an app's tool returned (1 MiB of text and 4 images at most).
|
|
1052
1074
|
*/
|
|
1053
1075
|
export type ToolOutput = {
|
|
1076
|
+
/**
|
|
1077
|
+
* The member the project's server acts as: held to that member's rules — their turn (403 not_your_turn) (the server's alone: a user sending it is answered 400; one who is not a member of the chat, 403 not_a_member). Left out, the server acts as itself.
|
|
1078
|
+
*/
|
|
1079
|
+
as?: string;
|
|
1054
1080
|
/**
|
|
1055
1081
|
* The tool failed; the output says why.
|
|
1056
1082
|
*/
|
|
@@ -1322,7 +1348,7 @@ export declare function client(t: Transport): {
|
|
|
1322
1348
|
/**
|
|
1323
1349
|
* Name an agent
|
|
1324
1350
|
*
|
|
1325
|
-
* An agent a chat
|
|
1351
|
+
* An agent a chat the server starts by its name talks to: its definition, or the backend machine that defines it at each turn.
|
|
1326
1352
|
*/
|
|
1327
1353
|
putAgent(input: {
|
|
1328
1354
|
path: {
|
|
@@ -1356,7 +1382,7 @@ export declare function client(t: Transport): {
|
|
|
1356
1382
|
/**
|
|
1357
1383
|
* Start a chat
|
|
1358
1384
|
*
|
|
1359
|
-
* The server starts a chat with a named agent or a definition of its own, and names its members
|
|
1385
|
+
* The project's server's alone: its backend, with the secret key, starts a chat with a named agent or a definition of its own, and names its members. A signed-in user is answered 403 server_only, whatever the project lets them (settings.clients is what they do in the chats they are in).
|
|
1360
1386
|
*/
|
|
1361
1387
|
createChat(input: {
|
|
1362
1388
|
body: ChatRequest; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
@@ -1387,7 +1413,7 @@ export declare function client(t: Transport): {
|
|
|
1387
1413
|
/**
|
|
1388
1414
|
* Decide a tool call
|
|
1389
1415
|
*
|
|
1390
|
-
* A tool call that waits for a person's yes: approved it is made; denied, the agent is told, with the reason, and goes on.
|
|
1416
|
+
* A tool call that waits for a person's yes: approved it is made; denied, the agent is told, with the reason, and goes on. Decided by the member whose message began the turn (403 not_your_turn for any other) — or by the project's server, for any turn, or as that member (as).
|
|
1391
1417
|
*/
|
|
1392
1418
|
decideChatApproval(input: {
|
|
1393
1419
|
path: {
|
|
@@ -1440,7 +1466,7 @@ export declare function client(t: Transport): {
|
|
|
1440
1466
|
/**
|
|
1441
1467
|
* Write to a chat
|
|
1442
1468
|
*
|
|
1443
|
-
* A message for the agent: a turn of its own when none runs; while one does, at its next step (next) or cutting the step it is in (now). The same client_id again is the same message. A user sends user_messages_per_minute a minute (429 too_many_messages); past the history the project keeps a message is refused (409 history_full).
|
|
1469
|
+
* A message for the agent: a turn of its own when none runs; while one does, at its next step (next) or cutting the step it is in (now). The same client_id again is the same message. A user sends user_messages_per_minute a minute — and so does the server writing as them (429 too_many_messages); past the history the project keeps a message is refused (409 history_full).
|
|
1444
1470
|
*/
|
|
1445
1471
|
sendChatMessage(input: {
|
|
1446
1472
|
path: {
|
|
@@ -1449,10 +1475,33 @@ export declare function client(t: Transport): {
|
|
|
1449
1475
|
body: MessageRequest; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
1450
1476
|
signal?: AbortSignal;
|
|
1451
1477
|
}): Promise<Reply<200, ChatMessage> | Reply<202, ChatMessage>>;
|
|
1478
|
+
/**
|
|
1479
|
+
* Pipe the chat into a channel
|
|
1480
|
+
*
|
|
1481
|
+
* Writes the chat's stream into a channel of the project's realtime from now on — a gateway's, durable — as the platform: the members' messages, the turns, the answer as it is written (gathered into a few writes a second), the tools and subagents, each the channel's event `chat` {type, id?, data}, under an id of its own so a retry is kept once. The types: `message` (a ChatMessage, as the agent got it), `turn` ({response_id, status: running|waiting|completed|failed|canceled|timed_out|budget_exceeded, user_id, solo, waiting: {reason: approval|tool_output|subagents|message, text_offset, approval_id, tool_call_id, tool_name, input}, error}), `text` ({response_id, offset, text}: the agent's answer as it is written, at its byte offset), `reset` ({response_id, offset}: discard the answer past offset), `tool` ({response_id, run_id, call_id, name, status: running|awaiting_output|awaiting_approval|approved|denied|expired|completed|failed|canceled, text_offset, input, output, image_count, is_error, approval_id, agent_response_id, …}), `agent` ({run_id, response_id, parent_response_id, name, required, status, text_offset}: a subagent at work), `voice` ({voice_session_id, kind: transcript|started|closed|delegated, role: user|assistant, text, delegation_id, task}: the chat's live voice — what was said either way), and `seen` (the journal moved past what was handed already). Every type but text and reset has the journal's sequence as its id; text_offset says where in the answer a tool or subagent part happened. The project's backend is not in the stream: the gateway's members hear the chat from realtime, and one that was away is given what it missed there. Put again with the same channel it goes on where it is — one realtime refused is tried again; with another, from the chat's start, and nothing more is written into the one before. The project's server's alone.
|
|
1482
|
+
*/
|
|
1483
|
+
putChatPipe(input: {
|
|
1484
|
+
path: {
|
|
1485
|
+
chat_id: string;
|
|
1486
|
+
};
|
|
1487
|
+
body: ChatPipe; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
1488
|
+
signal?: AbortSignal;
|
|
1489
|
+
}): Promise<Reply<200, ChatPipeResult>>;
|
|
1490
|
+
/**
|
|
1491
|
+
* Take the chat's pipe away
|
|
1492
|
+
*
|
|
1493
|
+
* The chat's stream is written nowhere from now on. The project's server's alone.
|
|
1494
|
+
*/
|
|
1495
|
+
deleteChatPipe(input: {
|
|
1496
|
+
path: {
|
|
1497
|
+
chat_id: string;
|
|
1498
|
+
}; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
1499
|
+
signal?: AbortSignal;
|
|
1500
|
+
}): Promise<Reply<204, undefined>>;
|
|
1452
1501
|
/**
|
|
1453
1502
|
* Write to a subagent at work
|
|
1454
1503
|
*
|
|
1455
|
-
* A message for one of the agent's subagents, at its next step.
|
|
1504
|
+
* A message for one of the agent's subagents, at its next step: a message of the chat like any other — its writer's (or the member's the server writes as) messages a minute (429 too_many_messages), the history the project keeps (409 history_full).
|
|
1456
1505
|
*/
|
|
1457
1506
|
sendSubagentMessage(input: {
|
|
1458
1507
|
path: {
|
|
@@ -1473,26 +1522,10 @@ export declare function client(t: Transport): {
|
|
|
1473
1522
|
}; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
1474
1523
|
signal?: AbortSignal;
|
|
1475
1524
|
}): Promise<Reply<200, StopResult>>;
|
|
1476
|
-
/**
|
|
1477
|
-
* Follow a chat
|
|
1478
|
-
*
|
|
1479
|
-
* What happens in the chat as typed parts, as it happens.
|
|
1480
|
-
*/
|
|
1481
|
-
followChat(input: {
|
|
1482
|
-
path: {
|
|
1483
|
-
chat_id: string;
|
|
1484
|
-
};
|
|
1485
|
-
query?: {
|
|
1486
|
-
after?: number; /** The response whose answer the reader was reading. */
|
|
1487
|
-
response?: string; /** The bytes of that answer the reader holds. */
|
|
1488
|
-
offset?: number;
|
|
1489
|
-
}; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
1490
|
-
signal?: AbortSignal;
|
|
1491
|
-
}): Promise<Reply<200, Response>>;
|
|
1492
1525
|
/**
|
|
1493
1526
|
* Answer an app's tool call
|
|
1494
1527
|
*
|
|
1495
|
-
* The answer of a client tool's call, made by the app's code: the turn waiting for it goes on. The first answer is the one.
|
|
1528
|
+
* The answer of a client tool's call, made by the app's code: the turn waiting for it goes on. The first answer is the one. Given by the app of the member whose message began the turn (403 not_your_turn for any other) — or by the project's server, for any turn, or as that member (as).
|
|
1496
1529
|
*/
|
|
1497
1530
|
answerChatToolCall(input: {
|
|
1498
1531
|
path: {
|
|
@@ -56,6 +56,14 @@ export type ChannelRule = {
|
|
|
56
56
|
* A public channel's subscribers may write its state.
|
|
57
57
|
*/
|
|
58
58
|
state_write?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* The channel keeps its broadcasts, numbered, and a member that was away is given what it missed, in order and once, when it rejoins after the number it had (phx_join config.log.after; the join's reply says the number it starts after, log_seq). A broadcast's number (seq) is its channel's own — the time it was written, in microseconds, rising in the channel — and says nothing of other channels. Kept a day unless log_keep_seconds says how long. What a project's durable channels write is held to a budget an hour, each message weighed by the hours it is kept: past it a durable broadcast is refused (log_budget) until the next hour.
|
|
61
|
+
*/
|
|
62
|
+
durable?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* How long a durable channel keeps its broadcasts, in seconds: 1 to 604800 (a week). Naming it makes the channel durable.
|
|
65
|
+
*/
|
|
66
|
+
log_keep_seconds?: number;
|
|
59
67
|
};
|
|
60
68
|
export type ChannelSubscribers = {
|
|
61
69
|
/**
|
|
@@ -255,7 +263,7 @@ export declare function client(t: Transport): {
|
|
|
255
263
|
/**
|
|
256
264
|
* Broadcast as the server
|
|
257
265
|
*
|
|
258
|
-
* Publishes events on the project's channels, to every subscriber on every replica, as the project's server (1 to 100 events). Delivered at most once, like every broadcast.
|
|
266
|
+
* Publishes events on the project's channels, to every subscriber on every replica, as the project's server (1 to 100 events). Delivered at most once, like every broadcast — but on a durable channel, kept and given to its members in order and once. A durable channel's event past the project's hourly budget is refused with 429 log_budget and when to try again (Retry-After); the events before it were published.
|
|
259
267
|
*/
|
|
260
268
|
broadcast(input: {
|
|
261
269
|
body: BroadcastBatch; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|