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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Transport } from '../../internal/src/transport.js';
|
|
2
2
|
import { BackendError } from './backend-error.js';
|
|
3
|
-
import { type
|
|
3
|
+
import { type GatewayDescriptor, type GatewayEvent, type JoinedGateway, type JoinOptions } from './gateways.js';
|
|
4
4
|
import type { RealtimeSocket } from './socket.js';
|
|
5
5
|
export interface CallOptions {
|
|
6
6
|
headers?: Record<string, string>;
|
|
@@ -59,22 +59,29 @@ export interface BackendBase {
|
|
|
59
59
|
*/
|
|
60
60
|
call<O = unknown>(name: string, input?: unknown, options?: CallOptions): Promise<O>;
|
|
61
61
|
/**
|
|
62
|
-
* Joins a
|
|
63
|
-
* module's, `params` its pattern's `{param}` values: resolves once
|
|
64
|
-
* backend let the user in, with the handle its events arrive on and its
|
|
65
|
-
* messages go through
|
|
62
|
+
* Joins a gateway the backend declared with `@Gateway` — `gateway` is the
|
|
63
|
+
* generated module's, `params` its pattern's `{param}` values: resolves once
|
|
64
|
+
* the backend let the user in, with the handle its events arrive on and its
|
|
65
|
+
* messages go through (each answered with its ack); rejects with a
|
|
66
|
+
* GatewayError (its reason) when it did not. A durable gateway's handle is
|
|
67
|
+
* sent what it keeps first, unless `{ history: false }`; a chat gateway's
|
|
68
|
+
* holds the chat its server piped there (`handle.chat`).
|
|
66
69
|
*
|
|
67
|
-
* const
|
|
68
|
-
*
|
|
69
|
-
* await
|
|
70
|
-
*
|
|
70
|
+
* const chat = await pb.api.join(ChatGateway, { chatId });
|
|
71
|
+
* chat.chat.subscribe((s) => render(s.items));
|
|
72
|
+
* const { id } = await chat.send('say', { text: 'hello' });
|
|
73
|
+
* chat.leave();
|
|
71
74
|
*/
|
|
72
|
-
join<E extends
|
|
75
|
+
join<E extends GatewayEvent, S, R, P extends readonly string[], C extends boolean = false>(gateway: GatewayDescriptor<E, S, R, P, C>, params: Record<P[number], string>, options?: JoinOptions): Promise<JoinedGateway<E, S, R, C>>;
|
|
73
76
|
}
|
|
74
77
|
/** What every client createClient makes inherits: one getter per registered backend name. */
|
|
75
78
|
export declare const clientBase: object;
|
|
76
|
-
/**
|
|
77
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Gives a client made by createClient its project's origin, its way to the
|
|
81
|
+
* machines, its project's transport (an upload's way, through storage), its
|
|
82
|
+
* socket (a gateway's) and its signed-in user (a chat gateway's own turns).
|
|
83
|
+
*/
|
|
84
|
+
export declare function bindMachines(client: object, project: string, machine: (url: string) => Transport, storage: Transport, socket: RealtimeSocket, me?: () => string | undefined): void;
|
|
78
85
|
/**
|
|
79
86
|
* Registers a backend under `client` for the clients of `project` (the
|
|
80
87
|
* address createClient is given) — the machine `machine`, at `url` — called
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { type AgentEvent, type ChatEvent, type ToolEvent, type TurnEvent } from '../../internal/src/chat.js';
|
|
2
|
+
export type { AgentEvent, ChatEvent, ToolEvent, TurnEvent } from '../../internal/src/chat.js';
|
|
3
|
+
/** A member's (or the server's) message, as the agent got it. */
|
|
4
|
+
export interface ChatMessageView {
|
|
5
|
+
/** The writer's id for it: the same id is the same message. */
|
|
6
|
+
clientId: string;
|
|
7
|
+
id: string | null;
|
|
8
|
+
text: string;
|
|
9
|
+
/** The member who wrote it; null: the project's server. */
|
|
10
|
+
author: string | null;
|
|
11
|
+
authorName: string;
|
|
12
|
+
delivery: string;
|
|
13
|
+
/** pending until the agent has it, delivered once it does, failed when it could not be given. */
|
|
14
|
+
status: 'pending' | 'delivered' | 'failed';
|
|
15
|
+
/** Why it failed: the module's code. */
|
|
16
|
+
error: string | null;
|
|
17
|
+
/** The turn it started or reached. */
|
|
18
|
+
responseId: string | null;
|
|
19
|
+
createdAt: string;
|
|
20
|
+
/** The signed-in user wrote it. */
|
|
21
|
+
mine: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** A piece of an answer, in order: its text, split where a tool was called or a subagent handed work. */
|
|
24
|
+
export type ChatPart = {
|
|
25
|
+
type: 'text';
|
|
26
|
+
text: string;
|
|
27
|
+
} | {
|
|
28
|
+
type: 'tool';
|
|
29
|
+
tool: ToolEvent;
|
|
30
|
+
} | {
|
|
31
|
+
type: 'agent';
|
|
32
|
+
agent: AgentEvent;
|
|
33
|
+
};
|
|
34
|
+
/** One answer of the agent's (or of one of its subagents). */
|
|
35
|
+
export interface ChatResponse {
|
|
36
|
+
id: string;
|
|
37
|
+
status: TurnEvent['status'] | null;
|
|
38
|
+
waiting: TurnEvent['waiting'];
|
|
39
|
+
error: TurnEvent['error'];
|
|
40
|
+
/** The whole answer so far. */
|
|
41
|
+
text: string;
|
|
42
|
+
parts: ChatPart[];
|
|
43
|
+
/** A subagent's: its run, its name, and the response that handed it the work. */
|
|
44
|
+
runId: string | null;
|
|
45
|
+
agent: string | null;
|
|
46
|
+
parentId: string | null;
|
|
47
|
+
/** The member whose turn it is (a subagent's: its turn's); null: the project's server's, or the engine's. */
|
|
48
|
+
startedBy: string | null;
|
|
49
|
+
/** The signed-in user's own turn. */
|
|
50
|
+
mine: boolean;
|
|
51
|
+
}
|
|
52
|
+
export type ChatItem = {
|
|
53
|
+
type: 'message';
|
|
54
|
+
message: ChatMessageView;
|
|
55
|
+
} | {
|
|
56
|
+
type: 'response';
|
|
57
|
+
response: ChatResponse;
|
|
58
|
+
};
|
|
59
|
+
export interface ChatState {
|
|
60
|
+
/** The conversation in order: the members' messages and the agent's answers (a subagent's is in its parent's parts). */
|
|
61
|
+
items: ChatItem[];
|
|
62
|
+
messages: ChatMessageView[];
|
|
63
|
+
/** Every answer, the subagents' too, as they began. */
|
|
64
|
+
responses: ChatResponse[];
|
|
65
|
+
/** The last turn's state. */
|
|
66
|
+
turn: TurnEvent | null;
|
|
67
|
+
/**
|
|
68
|
+
* What waits for the signed-in user: the tool calls of their own turns
|
|
69
|
+
* waiting for their yes, and the client tool calls of their own turns
|
|
70
|
+
* waiting for their app's answer — each said back through the gateway's
|
|
71
|
+
* own messages, its backend deciding. Another member's turn is theirs.
|
|
72
|
+
*/
|
|
73
|
+
waiting: {
|
|
74
|
+
approvals: ToolEvent[];
|
|
75
|
+
outputs: ToolEvent[];
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** A gateway's chat: its state now, and told each time it changes. */
|
|
79
|
+
export interface GatewayChat extends AsyncIterable<ChatState> {
|
|
80
|
+
/** The chat as the channel holds it now: the same object until it changes. */
|
|
81
|
+
readonly state: ChatState;
|
|
82
|
+
/** Told each time the state changes (at most once a microtask); returns the unsubscribe. */
|
|
83
|
+
subscribe(listener: (state: ChatState) => void): () => void;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A chat folded from its channel's parts. It holds no connection: a part is
|
|
87
|
+
* handed to take() as the channel gives it — once, in order — and the state
|
|
88
|
+
* is built from them; me is the signed-in user, read as the state is built.
|
|
89
|
+
*/
|
|
90
|
+
export declare class ChatLog implements GatewayChat {
|
|
91
|
+
private readonly me;
|
|
92
|
+
private readonly messages;
|
|
93
|
+
private readonly responses;
|
|
94
|
+
private readonly order;
|
|
95
|
+
private turn;
|
|
96
|
+
private readonly calls;
|
|
97
|
+
private readonly listeners;
|
|
98
|
+
/** The iterations waiting for a change: woken when the gateway is left. */
|
|
99
|
+
private readonly enders;
|
|
100
|
+
private snapshot;
|
|
101
|
+
private told;
|
|
102
|
+
private ended;
|
|
103
|
+
constructor(me?: () => string | undefined);
|
|
104
|
+
get state(): ChatState;
|
|
105
|
+
subscribe(listener: (state: ChatState) => void): () => void;
|
|
106
|
+
/** The state now, then each time it changes, until the gateway is left. */
|
|
107
|
+
[Symbol.asyncIterator](): AsyncGenerator<ChatState, void, undefined>;
|
|
108
|
+
/** The gateway was left: an iteration ends, and no part is taken any more. */
|
|
109
|
+
end(): void;
|
|
110
|
+
/** One payload of the channel's "chat" event; one that is no part this runtime reads is let be. */
|
|
111
|
+
takePayload(payload: unknown): void;
|
|
112
|
+
take(e: ChatEvent): void;
|
|
113
|
+
private heard;
|
|
114
|
+
private place;
|
|
115
|
+
private response;
|
|
116
|
+
private changed;
|
|
117
|
+
private build;
|
|
118
|
+
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { type Fetch, type Transport } from '../../internal/src/transport.js';
|
|
2
2
|
import { Auth, type CredentialsLike } from './auth.js';
|
|
3
3
|
import { type RetryPolicy } from '../../internal/src/retry.js';
|
|
4
|
-
import { type SessionStore } from './session.js';
|
|
4
|
+
import { type RefreshMode, type SessionStore } from './session.js';
|
|
5
5
|
import { RealtimeSocket } from './socket.js';
|
|
6
6
|
import { Analytics, type AnalyticsOptions } from './analytics.js';
|
|
7
7
|
import { Purchases } from './purchases.js';
|
|
8
|
-
import { AI } from './ai.js';
|
|
9
8
|
export interface ClientOptions {
|
|
10
9
|
/** The project's address: https://<ref>.<domain> */
|
|
11
10
|
url: string;
|
|
@@ -13,6 +12,8 @@ export interface ClientOptions {
|
|
|
13
12
|
publishableKey: string;
|
|
14
13
|
/** Where the session is kept: localStorage in a browser, memory elsewhere, unless the app gives its own. */
|
|
15
14
|
storage?: SessionStore;
|
|
15
|
+
/** When the access token is renewed (RefreshMode): behind the call unless said — palbase/web/ssr says it for a server. */
|
|
16
|
+
refresh?: RefreshMode;
|
|
16
17
|
fetch?: Fetch;
|
|
17
18
|
webSocket?: typeof WebSocket;
|
|
18
19
|
/**
|
|
@@ -61,7 +62,5 @@ export interface PalbaseClient {
|
|
|
61
62
|
analytics: Analytics;
|
|
62
63
|
/** What the signed-in customer has (live, onCustomerInfo), the paywall's catalog, and buying on the web. */
|
|
63
64
|
purchases: Purchases;
|
|
64
|
-
/** The project's agents, for the signed-in user (when the project lets its users talk to them): their chats, followed as typed parts. */
|
|
65
|
-
ai: AI;
|
|
66
65
|
}
|
|
67
66
|
export declare function createClient(opts: ClientOptions): PalbaseClient;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { type GatewayChat } from './chat.js';
|
|
2
|
+
import type { RealtimeSocket } from './socket.js';
|
|
3
|
+
/** One event of a gateway, as a generated module's union has it. */
|
|
4
|
+
export type GatewayEvent = {
|
|
5
|
+
event: string;
|
|
6
|
+
payload: unknown;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* A gateway, as the generator writes one. `send`, `reply` and `event` carry
|
|
10
|
+
* types alone — their values are never read: `gateway.send('say', { … })` is
|
|
11
|
+
* checked against the message's shape and resolves with its ack's, and a
|
|
12
|
+
* handler's event against the gateway's events.
|
|
13
|
+
*/
|
|
14
|
+
export interface GatewayDescriptor<E extends GatewayEvent, S, R = Record<keyof S, unknown>, P extends readonly string[] = readonly string[], C extends boolean = false> {
|
|
15
|
+
/** The backend's class: `ChatGateway`. */
|
|
16
|
+
name?: string;
|
|
17
|
+
/** The channel pattern the backend declared: `chat:{chatId}`. */
|
|
18
|
+
pattern: string;
|
|
19
|
+
/** It keeps what it sends: a join is sent what it keeps, and a dropped socket misses nothing. */
|
|
20
|
+
durable?: boolean;
|
|
21
|
+
/** Its server pipes a chat into it: the handle holds the chat's state (`handle.chat`). */
|
|
22
|
+
chat?: C;
|
|
23
|
+
/** The `{param}` names, in the pattern's order: a join takes exactly these. */
|
|
24
|
+
params: P;
|
|
25
|
+
/** The declared event names: what a handle listens to. */
|
|
26
|
+
events: readonly string[];
|
|
27
|
+
/** The declared message names: what a handle sends. */
|
|
28
|
+
messages: readonly string[];
|
|
29
|
+
send: S;
|
|
30
|
+
reply?: R;
|
|
31
|
+
event: E;
|
|
32
|
+
}
|
|
33
|
+
/** How a gateway is joined. */
|
|
34
|
+
export interface JoinOptions {
|
|
35
|
+
/** A durable gateway's: sent what it keeps first (true, the default), or only what comes after the join (false). */
|
|
36
|
+
history?: boolean;
|
|
37
|
+
}
|
|
38
|
+
/** What `on` returns: called, it stops that callback (`off` does the same). */
|
|
39
|
+
export type GatewaySubscription = () => void;
|
|
40
|
+
/** A live gateway. Hold it for as long as the view is on screen, and `leave` it when the view goes: an occupied gateway is one its backend is still running for. */
|
|
41
|
+
export interface GatewayHandle<E extends GatewayEvent, S, R = Record<keyof S, unknown>> {
|
|
42
|
+
/** The channel this handle is on: `chat:42`. */
|
|
43
|
+
readonly topic: string;
|
|
44
|
+
/** A durable gateway's number of the last event the handle was sent: what a dropped socket joins again after. */
|
|
45
|
+
readonly seq: number | undefined;
|
|
46
|
+
/** Every event the gateway declares, as a union to switch over. */
|
|
47
|
+
on(handler: (event: E) => void): GatewaySubscription;
|
|
48
|
+
/** One event by its name, its payload typed. */
|
|
49
|
+
on<K extends E['event']>(event: K, handler: (payload: Extract<E, {
|
|
50
|
+
event: K;
|
|
51
|
+
}>['payload']) => void): GatewaySubscription;
|
|
52
|
+
/** Stops one callback. */
|
|
53
|
+
off(subscription: GatewaySubscription): void;
|
|
54
|
+
/**
|
|
55
|
+
* Sends one declared message and waits for the gateway's backend to take
|
|
56
|
+
* it: resolves with its ack (what its @Subscribe returned), rejects with a
|
|
57
|
+
* GatewayError — its reason — when it did not.
|
|
58
|
+
*/
|
|
59
|
+
send<K extends keyof S & string>(message: K, payload: S[K]): Promise<K extends keyof R ? R[K] : unknown>;
|
|
60
|
+
/** Drops every callback of this handle and lets go of the gateway; the channel is left with its last handle. */
|
|
61
|
+
leave(): void;
|
|
62
|
+
}
|
|
63
|
+
/** A chat gateway's handle: the chat its server piped into the channel, as its state. */
|
|
64
|
+
export interface ChatGatewayHandle<E extends GatewayEvent, S, R = Record<keyof S, unknown>> extends GatewayHandle<E, S, R> {
|
|
65
|
+
/** The chat from its start (the channel keeps it), and each change as the platform writes it. */
|
|
66
|
+
readonly chat: GatewayChat;
|
|
67
|
+
}
|
|
68
|
+
/** What a join resolves with: a chat gateway's handle holds its chat. */
|
|
69
|
+
export type JoinedGateway<E extends GatewayEvent, S, R, C> = [C] extends [true] ? ChatGatewayHandle<E, S, R> : GatewayHandle<E, S, R>;
|
|
70
|
+
/**
|
|
71
|
+
* Why a gateway did not do what was asked. `reason` is the server's: for a join,
|
|
72
|
+
* `unauthorized` (the backend did not let the user in) or `unavailable` (it
|
|
73
|
+
* could not be asked: try again); for a message, the reason the backend gave,
|
|
74
|
+
* `forbidden` when it gave none or the user may only listen, `rate_limited`,
|
|
75
|
+
* `unavailable`. When no answer came it is `no reply` or `socket closed` —
|
|
76
|
+
* the message may have been taken — and `not joined` when nothing was sent:
|
|
77
|
+
* the handle left, its socket closed (a sign-out, another user's sign-in), or
|
|
78
|
+
* the socket dropped and is being opened again.
|
|
79
|
+
*/
|
|
80
|
+
export declare class GatewayError extends Error {
|
|
81
|
+
readonly reason: string;
|
|
82
|
+
constructor(message: string, reason: string);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Joins `gateway` on `socket`: resolves once the backend let the user in,
|
|
86
|
+
* rejects with a GatewayError when it did not. me is the signed-in user: a
|
|
87
|
+
* chat's turns and messages that are theirs.
|
|
88
|
+
*/
|
|
89
|
+
export declare function joinGateway<E extends GatewayEvent, S, R, P extends readonly string[], C extends boolean = false>(socket: RealtimeSocket, gateway: GatewayDescriptor<E, S, R, P, C>, params: Record<P[number], string>, options?: JoinOptions, me?: () => string | undefined): Promise<JoinedGateway<E, S, R, C>>;
|
package/types/web/src/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export { createClient, type ClientOptions, type PalbaseClient } from './client.js';
|
|
2
2
|
export type { Auth, CredentialsLike, SignInResult, User } from './auth.js';
|
|
3
|
-
export { localStore, memoryStore, SessionChangedError, type AuthEvent, type Session, type SessionStore } from './session.js';
|
|
4
|
-
export { Channel, RealtimeSocket, type PushReply } from './socket.js';
|
|
3
|
+
export { localStore, memoryStore, SessionChangedError, type AuthEvent, type RefreshMode, type Session, type SessionStore } from './session.js';
|
|
4
|
+
export { Channel, RealtimeSocket, type ChannelOptions, type PushReply } from './socket.js';
|
|
5
5
|
export { Analytics, type AnalyticsOptions } from './analytics.js';
|
|
6
|
-
export {
|
|
6
|
+
export type { AgentEvent, ChatEvent, ChatItem, ChatMessageView, ChatPart, ChatResponse, ChatState, GatewayChat, ToolEvent, TurnEvent } from './chat.js';
|
|
7
7
|
export { Purchases, type CustomerInfo, type CustomerInfoListener, type MergeGrant, type Offerings } from './purchases.js';
|
|
8
8
|
export type { Paywall, PaywallRenderOptions } from './paywall/placement.js';
|
|
9
9
|
export type { PaywallAttribute } from './paywall/attributes.js';
|
|
@@ -11,5 +11,5 @@ export type { PaywallPackage, PaywallView } from './paywall/render.js';
|
|
|
11
11
|
export { PalbaseError } from '../../internal/src/transport.js';
|
|
12
12
|
export { BackendError, isBackendError, type BackendErrorKind, type FieldError } from './backend-error.js';
|
|
13
13
|
export type { BackendBase, CallOptions, UploadOptions, UploadProgress } from './backends.js';
|
|
14
|
-
export {
|
|
14
|
+
export { GatewayError, type ChatGatewayHandle, type GatewayDescriptor, type GatewayEvent, type GatewayHandle, type GatewaySubscription, type JoinedGateway, type JoinOptions } from './gateways.js';
|
|
15
15
|
export type { RetryPolicy } from '../../internal/src/retry.js';
|
|
@@ -38,9 +38,19 @@ export declare function localStore(key: string): SessionStore;
|
|
|
38
38
|
export declare function subjectOf(accessToken: string): string;
|
|
39
39
|
/** A refusal of the refresh token itself (rotated away, revoked, expired): the session is over. */
|
|
40
40
|
export type IsRejected = (e: unknown) => boolean;
|
|
41
|
+
/**
|
|
42
|
+
* When the session's access token is renewed: `behind` the call while it
|
|
43
|
+
* still works (a browser: no call waits), `before` the call that finds it
|
|
44
|
+
* about to lapse (a server that writes the session where it keeps it — the
|
|
45
|
+
* response's cookies — before it answers), or `never` (a server that cannot
|
|
46
|
+
* write it: the renewed refresh token would be lost, and the next renewal
|
|
47
|
+
* with the old one ends the session; the request's middleware renews it).
|
|
48
|
+
*/
|
|
49
|
+
export type RefreshMode = 'behind' | 'before' | 'never';
|
|
41
50
|
export interface SessionManagerOptions {
|
|
42
51
|
now?: () => number;
|
|
43
52
|
lockName?: string;
|
|
53
|
+
refresh?: RefreshMode;
|
|
44
54
|
refreshTimeoutMs?: number;
|
|
45
55
|
}
|
|
46
56
|
export declare class SessionManager {
|
|
@@ -54,6 +64,7 @@ export declare class SessionManager {
|
|
|
54
64
|
private now;
|
|
55
65
|
private lockName;
|
|
56
66
|
private refreshTimeoutMs;
|
|
67
|
+
private mode;
|
|
57
68
|
constructor(store: SessionStore, refresher: (refreshToken: string) => Promise<TokenPair>, isRejected: IsRejected, opts?: SessionManagerOptions);
|
|
58
69
|
session(): Promise<Session | null>;
|
|
59
70
|
/** The session as it is now, without waiting (null before the store has loaded). */
|
|
@@ -12,6 +12,14 @@ export interface SocketOptions {
|
|
|
12
12
|
replyTimeoutMs?: number;
|
|
13
13
|
}
|
|
14
14
|
export type ChannelState = 'closed' | 'joining' | 'joined' | 'refused';
|
|
15
|
+
export interface ChannelOptions {
|
|
16
|
+
/**
|
|
17
|
+
* On a durable channel, the number to be sent its log after: what was missed
|
|
18
|
+
* since (0: all it keeps). Left out, the channel is heard from its join on.
|
|
19
|
+
* Either way it is joined again after the last number it was sent.
|
|
20
|
+
*/
|
|
21
|
+
after?: number;
|
|
22
|
+
}
|
|
15
23
|
/**
|
|
16
24
|
* What became of a push: the server's answer — `ok` with its response, or
|
|
17
25
|
* `error` with `{ reason }` — or, when none came, `timeout` (`no reply`: the
|
|
@@ -26,13 +34,20 @@ export declare class Channel {
|
|
|
26
34
|
state: ChannelState;
|
|
27
35
|
/** Why the server refused the last join, when it did. */
|
|
28
36
|
refusal?: Record<string, unknown>;
|
|
37
|
+
/**
|
|
38
|
+
* A durable channel's number: of the last broadcast it was sent (each carries
|
|
39
|
+
* its `seq`), or of the one its join started after. A socket that drops joins
|
|
40
|
+
* it again after it, and is sent what it missed in order, once. Undefined on
|
|
41
|
+
* a channel that keeps no log.
|
|
42
|
+
*/
|
|
43
|
+
logSeq?: number;
|
|
29
44
|
joinRef: string | null;
|
|
30
45
|
private listeners;
|
|
31
46
|
private closers;
|
|
32
47
|
private joinWaiters;
|
|
33
48
|
readonly name: string;
|
|
34
49
|
private socket;
|
|
35
|
-
constructor(name: string, socket: RealtimeSocket);
|
|
50
|
+
constructor(name: string, socket: RealtimeSocket, opts?: ChannelOptions);
|
|
36
51
|
get topic(): string;
|
|
37
52
|
/** Resolves once joined; rejects with the server's reason when refused. */
|
|
38
53
|
join(): Promise<void>;
|
|
@@ -69,7 +84,8 @@ export declare class RealtimeSocket {
|
|
|
69
84
|
reconnects: number;
|
|
70
85
|
private opts;
|
|
71
86
|
constructor(opts: SocketOptions);
|
|
72
|
-
channel
|
|
87
|
+
/** The channel by its name; opts are the first caller's (a channel already made keeps its own). */
|
|
88
|
+
channel(name: string, opts?: ChannelOptions): Channel;
|
|
73
89
|
/** Closes the socket; every channel is closed (the app joins again — as the next user, if one signs in). */
|
|
74
90
|
disconnect(): void;
|
|
75
91
|
/** A new token for every joined channel (the session was refreshed). */
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { User } from './auth.js';
|
|
2
|
+
import { type ClientOptions, type PalbaseClient } from './client.js';
|
|
3
|
+
import type { SessionStore } from './session.js';
|
|
4
|
+
/** A cookie's attributes, as Next.js's cookies().set and the cookie package name them. */
|
|
5
|
+
export interface CookieOptions {
|
|
6
|
+
path?: string;
|
|
7
|
+
domain?: string;
|
|
8
|
+
maxAge?: number;
|
|
9
|
+
expires?: Date;
|
|
10
|
+
sameSite?: 'lax' | 'strict' | 'none';
|
|
11
|
+
secure?: boolean;
|
|
12
|
+
httpOnly?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The request's cookies, and — where the server can write the response's — a
|
|
16
|
+
* way to write them. An answer that writes a session's cookies is one user's:
|
|
17
|
+
* setAll is given the headers that keep any cache between the server and the
|
|
18
|
+
* browser from keeping it and handing it to someone else — set them on the
|
|
19
|
+
* response with the cookies.
|
|
20
|
+
*/
|
|
21
|
+
export interface CookieMethods {
|
|
22
|
+
getAll(): {
|
|
23
|
+
name: string;
|
|
24
|
+
value: string;
|
|
25
|
+
}[] | Promise<{
|
|
26
|
+
name: string;
|
|
27
|
+
value: string;
|
|
28
|
+
}[]>;
|
|
29
|
+
setAll?(cookies: {
|
|
30
|
+
name: string;
|
|
31
|
+
value: string;
|
|
32
|
+
options: CookieOptions;
|
|
33
|
+
}[], headers: Record<string, string>): void | Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
/** What an answer that writes a session's cookies is sent with: kept by no cache. */
|
|
36
|
+
export declare const NO_STORE_HEADERS: Readonly<Record<string, string>>;
|
|
37
|
+
/**
|
|
38
|
+
* What the session's cookies are written with unless the app says: the whole
|
|
39
|
+
* site; sent when a link from elsewhere opens it (a sign-in link); over https
|
|
40
|
+
* alone (a page served on http — a developer's computer — says secure: false,
|
|
41
|
+
* and the browser's client says it of a page on http itself); kept as long as
|
|
42
|
+
* a browser keeps a cookie (400 days — the session itself ends when its
|
|
43
|
+
* refresh token does); readable by the page, as the browser client reads it.
|
|
44
|
+
*/
|
|
45
|
+
export declare const SESSION_COOKIE_OPTIONS: CookieOptions;
|
|
46
|
+
/** The session's cookie for the project the publishable key is of: pb-<ref>-session (with .0, .1, … when it is long). */
|
|
47
|
+
export declare function sessionCookieName(publishableKey: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* The session in cookies named `name` (one, or numbered parts): read from
|
|
50
|
+
* getAll on every load, written with setAll — or not at all where there is
|
|
51
|
+
* none to write with.
|
|
52
|
+
*/
|
|
53
|
+
export declare function cookieSessionStore(name: string, cookies: CookieMethods, options?: CookieOptions, shared?: boolean): SessionStore;
|
|
54
|
+
type SsrOptions = Omit<ClientOptions, 'storage'> & {
|
|
55
|
+
cookieOptions?: CookieOptions;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* A server's client for one request, its session in the request's cookies:
|
|
59
|
+
* it renews the session before a call that finds it about to lapse when it
|
|
60
|
+
* can write the response's cookies (setAll), and never when it cannot.
|
|
61
|
+
*/
|
|
62
|
+
export declare function createServerClient(opts: SsrOptions & {
|
|
63
|
+
cookies: CookieMethods;
|
|
64
|
+
}): PalbaseClient;
|
|
65
|
+
/** The page's cookies (document.cookie). */
|
|
66
|
+
export declare function documentCookies(): CookieMethods;
|
|
67
|
+
/**
|
|
68
|
+
* The browser's client, its session in the page's cookies — where the
|
|
69
|
+
* server's pages read it. Renewed behind the call, as any browser client's,
|
|
70
|
+
* one tab at a time.
|
|
71
|
+
*/
|
|
72
|
+
export declare function createBrowserClient(opts: SsrOptions): PalbaseClient;
|
|
73
|
+
/**
|
|
74
|
+
* Who is signed in, as auth says — a server's middleware calls it on the way
|
|
75
|
+
* in, with a client that writes the response's cookies: the session is
|
|
76
|
+
* renewed first when it has little left (a renewal that could not be made
|
|
77
|
+
* keeps it while its token works), then auth is asked whose its token is.
|
|
78
|
+
* Null when no one is signed in, the session is over, or auth does not take
|
|
79
|
+
* the token: a cookie the browser could have written is never taken at its
|
|
80
|
+
* word. Asking writes nothing back: only a renewal writes the session, so an
|
|
81
|
+
* answer never puts back the session its request carried over one the
|
|
82
|
+
* browser renewed meanwhile (whose old refresh token, used again later, would
|
|
83
|
+
* end the session).
|
|
84
|
+
*/
|
|
85
|
+
export declare function keepSession(pb: PalbaseClient): Promise<User | null>;
|
|
86
|
+
export {};
|
package/dist/chunks/FNUO6DSY.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
/*! palbase 0.5.2 — Palbase SDK License (see LICENSE) */
|
|
2
|
-
import{AsyncLocalStorage as v}from"node:async_hooks";function x(n,e){return new Proxy(e,{get(s,t,i){if(c.getStore()?.services===void 0)return Reflect.get(s,t,i);let o=R(n,t,s),r=o[t];return typeof r=="function"?r.bind(o):r}})}function R(n,e,s){let t=c.getStore()?.services;if(t===void 0)return s;let i=t[n];if(i!==void 0)return i;if(n==="Log"||typeof e=="symbol"||e==="then")return s;throw new Error(`${n}.${String(e)} was read, but this test did not provide ${n}. Pass it: withServices({ ${n}: \u2026 }, () => \u2026)`)}var A=Symbol.for("palbase.backend.requestScope"),c=globalThis[A]??=new v,b;function I(n){b=n}var N=new Proxy({},{get(n,e){if(!b)throw new Error(`Palbase.${String(e)} is reached before the app is served (serve() binds it)`);return b[e]}}),C=new Proxy({},{get(n,e){let s=c.getStore(),t=s?.database;if(!t)throw new Error(s?.services?`Database.${String(e)} was read, and this test gave no Database: withServices({ Database: fake.raw }, \u2026)`:s?`Database.${String(e)}: this app declares no database \u2014 PalbaseFactory.create(\u2026, { db: { schemas } })`:`Database.${String(e)} is reached outside a request: it is the request's transaction, reached from a handler, a service it calls or an @On`);let i=t[e];return typeof i=="function"?i.bind(t):i}});function g(n,e,s){let t={time:new Date().toISOString(),level:n,msg:e},i=c.getStore();if(i&&(t.request_id=i.requestId),s)for(let[r,a]of Object.entries(s))t[r]=a instanceof Error?{name:a.name,message:a.message,stack:a.stack}:a;let o=O(t);n==="error"||n==="warn"?process.stderr.write(`${o}
|
|
3
|
-
`):process.stdout.write(`${o}
|
|
4
|
-
`)}function O(n){try{return JSON.stringify(n)}catch{let e=new WeakSet;try{return JSON.stringify(n,(s,t)=>{if(typeof t=="bigint")return t.toString();if(typeof t=="object"&&t!==null){if(e.has(t))return"[circular]";e.add(t)}return t})}catch{return JSON.stringify({time:n.time,level:n.level,msg:n.msg,request_id:n.request_id,unwritable:"a field of this line could not be written"})}}}var m=x("Log",{debug:(n,e)=>g("debug",n,e),info:(n,e)=>g("info",n,e),warn:(n,e)=>g("warn",n,e),error:(n,e)=>g("error",n,e)});var T=512,k=8,L=64,E=/^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/,h={"i-klingon":"tlh","en-gb-oed":"en-GB-oxendict","sgn-be-fr":"sfb","zh-cmn-hans":"cmn-Hans","zh-yue":"yue","hy-arevela":"hy-arevela"};function P(n){let e=n.indexOf("-");return e>0?n.slice(0,e):n}function _(n){let e=n.split("-"),s=(e[0]??"").toLowerCase();return s==="mo"&&e.length===1?"ro-MD":s==="tl"?(e[0]="fil",e.join("-")):s==="sh"?(e[0]="sr",e.length>1&&/^[A-Za-z]{4}$/.test(e[1]??"")||e.splice(1,0,"Latn"),e.join("-")):n}function q(n){let e=n.trim().replaceAll("_","-");if(e===""||e==="*"||e.length>L)return;let s=e.toLowerCase(),t=Object.hasOwn(h,s)?h[s]:void 0;if(t===void 0){try{t=Intl.getCanonicalLocales(_(e))[0]}catch{return}if(t===void 0)return}let i=P(t);if(!(i===""||i==="und"||i==="mul"))return t}function D(n){let e=n.split("-"),s=e.findIndex((r,a)=>a>0&&r.length===1),t=s>0?e.slice(0,s):e,i=[],o=r=>{i.includes(r)||i.push(r)};for(let r=t.length;r>1||r===t.length;r--)o(t.slice(0,r).join("-"));if(!t.slice(1).some(r=>/^[A-Za-z]{4}$/.test(r)))try{let r=new Intl.Locale(t.join("-")).maximize().script;r&&o(`${t[0]}-${r}`)}catch{}return o(t[0]),i}function G(n,e){let s=[],t=i=>{i!==""&&!s.includes(i)&&s.push(i)};if(n!==null&&n.length<=T){let i=[];for(let o of n.split(",")){let r=o.trim();if(r==="")continue;let a=1,l=r.indexOf(";");if(l>=0){let y=r.slice(l+1);r=r.slice(0,l).trim();for(let f of y.split(";")){let p=f.indexOf("=");if(p<0||f.slice(0,p).trim().toLowerCase()!=="q")continue;let w=f.slice(p+1).trim(),d=E.test(w)?Number(w):Number.NaN;a=Number.isFinite(d)&&d>=0&&d<=1?d:0}}a>0&&i.push({tag:r,q:a,at:i.length})}i.sort((o,r)=>r.q-o.q||o.at-r.at);for(let{tag:o}of i.slice(0,k)){let r=q(o);if(r!==void 0)for(let a of D(r))t(a)}}return e!==void 0&&e!==""&&t(e),s}function $(n,e,s){let t=n.strings??{},i=Object.hasOwn(t,e)?t[e]:null;for(let o of s){if(o===n.source)break;let r=i!=null&&Object.hasOwn(i,o)?i[o]:void 0;if(typeof r=="string"&&r!=="")return{text:r,locale:o}}return{text:e,locale:n.source}}var j=/\{\{\s*([A-Za-z_][A-Za-z0-9_]*)\s*\}\}/g;function S(n,e){return n.replace(j,(s,t,i,o)=>{if(o[i-1]==="{"||o[i+s.length]==="}")return s;let r=e!==void 0&&Object.hasOwn(e,t)?e[t]:void 0;return r==null?"":String(r)})}var u;function K(n){u=n===void 0?void 0:{root:n,said:!1}}function Z(n,e){let s=c.getStore(),t=s?.strings;if(t===void 0)return u&&!u.said&&s?.services===void 0&&(u.said=!0,m.warn(`[palbase] t(): the app has no palbase/strings (looked in ${u.root}) \u2014 every sentence is said as it is written. \`npx palbase strings\` starts the table; an image takes it with COPY palbase ./palbase`)),S(n,e);let{text:i,locale:o}=$(t,n,s?.locales??[t.source]),r=s?.usedLocales;return r!==void 0&&!r.includes(o)&&r.push(o),S(i,e)}export{x as a,R as b,c,I as d,N as e,C as f,m as g,G as h,K as i,Z as j};
|
package/dist/chunks/JHQDWDV3.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/*! palbase 0.5.2 — Palbase SDK License (see LICENSE) */
|
|
2
|
-
import{d as O}from"./5G3URQAW.js";import{a as E,b as T,e as _}from"./HLYQRT7O.js";var a=class extends Error{kind;code;status;requestId;fields;retryAfter;data;constructor(n,t){super(t.message,t.cause===void 0?void 0:{cause:t.cause}),this.name="BackendError",this.kind=n,this.code=t.code,this.status=t.status??0,this.requestId=t.requestId,this.fields=t.fields,this.retryAfter=t.retryAfter,this.data=t.data}};function D(e){return e instanceof a||typeof e=="object"&&e!==null&&e.name==="BackendError"&&typeof e.kind=="string"}function $(e){let n=e.body,t={code:e.code,message:e.message,status:e.status,requestId:e.requestId??se(n,"request_id"),data:b(n,"data"),cause:e};if(e.code==="network_error")return new a("network",t);if(e.status===401)return new a("unauthorized",t);if(e.status===429)return new a("rateLimited",{...t,retryAfter:oe(n)??e.retryAfter});let r=re(n);return e.status===400&&r?new a("validation",{...t,fields:r}):new a("server",t)}function P(e){return e instanceof T||e instanceof Error&&e.name==="PalbaseError"}function j(e){return Array.isArray(e)&&e.length>0&&e.every(n=>typeof n=="object"&&n!==null&&typeof n.field=="string"&&typeof n.message=="string")}function re(e){let n=b(b(e,"data"),"fields");if(j(n))return n;let t=b(e,"fields");return j(t)?t:void 0}function oe(e){return N(e,"retry_after")??N(b(e,"data"),"retryAfter")}function b(e,n){if(typeof e=="object"&&e!==null)return e[n]}function N(e,n){let t=b(e,n);return typeof t=="number"?t:void 0}function se(e,n){let t=b(e,n);return typeof t=="string"?t:void 0}var ie=/^[A-Za-z_$][A-Za-z0-9_$]*$/,ae=Object.freeze(["adoptSession","analytics","appContext","appVersion","auth","callOnSignOut","cancelCallOnSignOut","configuration","consent","currentSession","flags","installation","module","moduleDirectory","notify","onSessionChange","onSignOut","preferences","realtime","scope","send","socket","storage","storedUserId","telemetry","transport","version","palbe","data","stores","purchases","messaging","notifications","perf","debug","equals","hashCode","toString","self","Type","init","deinit","subscript","then","constructor","__proto__"]),ce=new Set(ae),de=new Set(["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf","__proto__","__defineGetter__","__defineSetter__","__lookupGetter__","__lookupSetter__"]);function S(e){return e==="then"||e==="toJSON"||de.has(e)}function A(e){return e==="call"||e==="join"||S(e)}function C(e){return typeof e=="string"&&ie.test(e)&&!ce.has(e)&&!S(e)}function B(e){return typeof e=="string"&&/^[a-z][a-z0-9-]{0,62}$/.test(e)}function I(e){_(e)}function J(e){return _(e).origin}var R=class extends Error{reason;constructor(n,t){super(n),this.name="RoomError",this.reason=t}},q=new WeakMap;async function U(e,n,t){let{pattern:r,events:o,messages:s}=pe(n),i=ue(r,t),c=q.get(e);c||q.set(e,c=new Map);let p=c;p.set(i,(p.get(i)??0)+1);let u=e.channel(i),l=()=>{let d=(p.get(i)??1)-1;d>0?p.set(i,d):(p.delete(i),u.leave())};try{await u.join()}catch{let d=u.state==="refused"?K(u.refusal,"unavailable"):"socket closed";throw l(),new R(`room ${JSON.stringify(i)} was not joined: ${d}`,d)}let m=!1,w=new Set,k=()=>{if(!m){m=!0,h();for(let d of[...w])d();l()}},h=u.onClosed(k),y=d=>{if(m)return()=>{};let v=u.on("broadcast",f=>{typeof f.event=="string"&&o.has(f.event)&&d(f.event,E(f.payload))}),g=()=>{w.delete(g),v()};return w.add(g),g};return{topic:i,on(d,v){if(typeof d=="function")return y((g,f)=>d({event:g,payload:f}));if(!o.has(d))throw new TypeError(`room ${JSON.stringify(r)} declares no event ${JSON.stringify(String(d))}`);if(typeof v!="function")throw new TypeError(`room ${JSON.stringify(r)}: on(${JSON.stringify(d)}, \u2026) takes the function the event is handed to`);return y((g,f)=>{g===d&&v(f)})},off(d){w.has(d)&&d()},async send(d,v){if(!s.has(d))throw new TypeError(`room ${JSON.stringify(r)} declares no message ${JSON.stringify(String(d))}`);let g=m?{status:"error",response:{reason:"not joined"}}:await u.push("broadcast",{type:"broadcast",event:d,payload:v});if(g.status==="ok")return;let f=K(g.response,"unavailable");throw new R(`room ${JSON.stringify(i)} did not take ${JSON.stringify(d)}: ${f}`,f)},leave:k}}function pe(e){let n=typeof e=="object"&&e!==null?e:{},t=r=>Array.isArray(r)&&r.every(o=>typeof o=="string");if(typeof n.pattern!="string"||n.pattern===""||!t(n.events)||!t(n.messages))throw new TypeError("join takes a room of the backend's generated module: its pattern, its events and its messages");return{pattern:n.pattern,events:new Set(n.events),messages:new Set(n.messages)}}function ue(e,n){let t=typeof n=="object"&&n!==null?n:{};return e.split(":").map(r=>{if(!(r.startsWith("{")&&r.endsWith("}")&&r.length>2))return r;let o=r.slice(1,-1),s=Object.hasOwn(t,o)?t[o]:void 0;if(typeof s!="string"||s==="")throw new TypeError(`room ${JSON.stringify(e)} needs a value for ${JSON.stringify(o)}`);if(s.includes(":"))throw new TypeError(`room ${JSON.stringify(e)}: the value of ${JSON.stringify(o)} is one segment of the channel's name and cannot hold ":"`);return s}).join(":")}function K(e,n){let t=e?.reason;return typeof t=="string"&&t!==""?t:n}var x=class{pending="";dataLines=[];eventName;consume(n){this.pending+=n.replace(/\r\n/g,`
|
|
3
|
-
`);let t=[],r=this.pending.indexOf(`
|
|
4
|
-
`);for(;r!==-1;){let o=this.pending.slice(0,r);this.pending=this.pending.slice(r+1);let s=o.endsWith("\r")?o.slice(0,-1):o;if(s==="")this.dataLines.length>0&&t.push({event:this.eventName,payload:this.dataLines.join(`
|
|
5
|
-
`)}),this.dataLines=[],this.eventName=void 0;else if(!s.startsWith(":")){if(s.startsWith("data:")){let i=s.slice(5);this.dataLines.push(i.startsWith(" ")?i.slice(1):i)}else if(s.startsWith("event:")){let i=s.slice(6);this.eventName=i.startsWith(" ")?i.slice(1):i}}r=this.pending.indexOf(`
|
|
6
|
-
`)}return t}};async function*M(e,n){let t=e.getReader(),r=new TextDecoder,o=new x;try{for(;;){let{done:s,value:i}=await t.read();if(s)break;for(let c of o.consume(r.decode(i,{stream:!0}))){if(c.event==="error")throw new a("network",{code:"stream_failed",message:`stream failed: ${c.payload}`});let p;try{p=JSON.parse(c.payload)}catch{throw new a("decode",{code:"invalid_frame",message:`stream frame is not valid JSON: ${c.payload.slice(0,120)}`})}yield E(p)}}}finally{n.abort();try{await t.cancel()}catch{}}}var le={},W=new WeakMap;function Ke(e,n,t,r,o){W.set(e,{project:n,machine:t,storage:r,socket:o})}var L=new Map,F=new WeakMap;function Ue(e,n,t,r,o){if(!C(n))throw new a("validation",{code:"reserved_namespace",message:`Cannot register backend ${JSON.stringify(String(n))}: a backend's name is an identifier the client does not keep.`});let s=J(e);if(!B(t))throw new TypeError(`${JSON.stringify(String(t))} is not a machine's name: a lowercase letter, then lowercase letters, digits and -`);I(r),H(o);for(let i of Object.keys(o))if(A(i))throw z(i);(L.get(n)??fe(n)).set(s,{machine:t,url:r,tree:o})}function fe(e){let n=new Map;return L.set(e,n),Object.defineProperty(le,e,{configurable:!0,get(){return me(this,e,n)}}),n}function me(e,n,t){let r=W.get(e);if(!r)return;let o=t.get(r.project);if(!o)throw new TypeError(`pb.${n} is the backend of ${[...t.keys()].join(" and ")}: this client is ${r.project}'s, and its user's session never goes to another project's machine`);let s=F.get(e);s||F.set(e,s=new Map);let i=s.get(n);if(i?.registration===o)return i.ns;let c={machine:()=>r.machine(o.url),storage:r.storage,name:o.machine},p=Object.assign({call:(u,l,m)=>ve(c.machine,u,l,m),join:(u,l)=>U(r.socket,u,l)},V(o.tree,c));return s.set(n,{registration:o,ns:p}),p}function z(e){return new a("validation",{code:"reserved_namespace",message:`Cannot register endpoint namespace ${JSON.stringify(e)}: the name is reserved.`})}function G(e){return typeof e.path=="string"&&typeof e.method=="string"}function ge(e,n){if(e.pathParams!==void 0){if(!Array.isArray(e.pathParams)||!e.pathParams.every(t=>typeof t=="string"))throw new a("validation",{code:"invalid_namespace_tree",message:`Descriptor '${n}': pathParams must be an array of strings.`});for(let t of e.pathParams)if(!e.path.includes(`{${t}}`))throw new a("validation",{code:"invalid_namespace_tree",message:`Descriptor '${n}': pathParams entry '${t}' has no '{${t}}' placeholder in the path.`})}if(e.sse!==void 0&&typeof e.sse!="boolean")throw new a("validation",{code:"invalid_namespace_tree",message:`Descriptor '${n}': sse must be a boolean.`});if(e.idempotent!==void 0&&typeof e.idempotent!="boolean")throw new a("validation",{code:"invalid_namespace_tree",message:`Descriptor '${n}': idempotent must be a boolean.`});if(e.upload!==void 0&&typeof e.upload!="boolean")throw new a("validation",{code:"invalid_namespace_tree",message:`Descriptor '${n}': upload must be a boolean.`});if(e.upload===!0&&(e.method!=="POST"||e.sse===!0))throw new a("validation",{code:"invalid_namespace_tree",message:`Descriptor '${n}': an upload endpoint is a POST, and no stream.`});if(e.sse===!0&&e.input==="query")throw new a("validation",{code:"invalid_namespace_tree",message:`Descriptor '${n}': an sse endpoint cannot take query input.`});if(e.input!==void 0&&e.input!=="body"&&e.input!=="query"&&e.input!=="none")throw new a("validation",{code:"invalid_namespace_tree",message:`Descriptor '${n}': input must be 'body', 'query' or 'none'.`});if(e.errors!==void 0){for(let[t,r]of Object.entries(e.errors))if(typeof r!="function")throw new a("validation",{code:"invalid_namespace_tree",message:`Descriptor '${n}': errors['${t}'] must be a function.`})}}function H(e){if(typeof e!="object"||e===null)throw new a("validation",{code:"invalid_namespace_tree",message:"Namespace tree nodes must be plain objects."});let n=Object.getPrototypeOf(e);if(n!==Object.prototype&&n!==null)throw new a("validation",{code:"invalid_namespace_tree",message:"Namespace tree nodes must be plain objects."});for(let[t,r]of Object.entries(e)){if(S(t))throw z(t);typeof r=="object"&&r!==null&&G(r)?(r.method=r.method.toUpperCase(),ge(r,r.path)):H(r)}}function V(e,n){if(G(e))return e.upload===!0?async(...r)=>be(n,e,r):async(...r)=>Z(n.machine(),e,r);let t={};for(let[r,o]of Object.entries(e))t[r]=V(o,n);return t}function Q(e){if(e==null)return"";let n=Object.entries(e).filter(([,r])=>r!=null).sort(([r],[o])=>r<o?-1:r>o?1:0);return n.length===0?"":`?${n.map(([r,o])=>{if(typeof o!="string"&&typeof o!="number"&&typeof o!="boolean")throw new a("validation",{code:"invalid_query_value",message:`Query parameter '${r}' must be a string, number, or boolean.`});return`${encodeURIComponent(r)}=${encodeURIComponent(String(o))}`}).join("&")}`}function he(e,n,t){let r=String(t);if(r===""||r==="."||r==="..")throw new a("validation",{code:"invalid_path_parameter",message:`${e.path}: path parameter '${n}' cannot be ${r===""?"empty":JSON.stringify(r)}`});return encodeURIComponent(r)}function Y(e,n){let t=e.pathParams??[],r=e.path;for(let o=0;o<t.length;o++){let s=n[o];if(typeof s!="string"&&typeof s!="number")throw new a("validation",{code:"missing_path_param",message:`${e.path}: path parameter '${t[o]}' must be a string or number`});r=r.replace(`{${t[o]}}`,he(e,t[o],s))}return r}var ye=new Set(["POST","PUT","PATCH","DELETE"]);async function Z(e,n,t){let r=n.pathParams??[],o=Y(n,t);if(n.input==="none"&&t.length>r.length+1)throw new a("validation",{code:"unexpected_argument",message:`${n.path}: endpoint takes no input \u2014 pass only path params and options`});let s=n.input==="none"?void 0:t[r.length],i=n.input==="none"?r.length:r.length+1,c=t[i],p;if(n.input==="query")o+=Q(s);else if(n.input!=="none")if(n.method==="GET"){if(s!==void 0)throw new a("validation",{code:"unsupported_get_input",message:`${n.path}: GET endpoints take no body input`})}else p=s;let u={...c?.headers};ye.has(n.method)&&!Object.keys(u).some(l=>l.toLowerCase()==="idempotency-key")&&(u["Idempotency-Key"]=O());try{return n.sse===!0?await Re(e,n,o,p,u,c?.signal):await Se(e,n,o,p,u,c?.signal)}catch(l){throw X(n,l)}}function X(e,n){return e.errors&&D(n)&&Object.hasOwn(e.errors,n.code)?e.errors[n.code](n):n}var we=[["ApiKeyAuth","userJWT"],["ApiKeyAuth"]];async function be(e,n,t){let r=n.pathParams??[],o=Y(n,t),s=n.input==="none"?r.length:r.length+1;if(t.length>s+2)throw new a("validation",{code:"unexpected_argument",message:`${n.path}: an upload takes its path params, ${n.input==="none"?"":"its input, "}the file and options`});let i=n.input==="none"?void 0:t[r.length],c=t[s],p=t[s+1];if(!(c instanceof Blob))throw new a("validation",{code:"invalid_file",message:`${n.path}: the file is a Blob (a File is one)`});let u=`/storage/upload/${e.name}/${encodeURIComponent(o.slice(1))}`;n.input==="query"&&(u+=Q(i));let l=ke(n.input==="query"?void 0:i,c),m=l.body.size,w=0,k=h=>{w=h;try{p?.onProgress?.({loaded:h,total:m})}catch{}};p?.onProgress&&k(0);try{let h;try{let y={op:`Upload ${n.path}`,method:"POST",path:u,auth:we,answers:ee,body:{kind:"raw",contentType:l.type,value:l.body},signal:p?.signal,...p?.onProgress?{onUploadProgress:d=>k(d)}:{}};h=(await e.storage.send(y)).data}catch(y){throw P(y)?$(y):y}return p?.onProgress&&w<m&&k(m),await te(n,h,p?.signal)}catch(h){throw X(n,h)}}function ke(e,n){let t=`Palbase-${O()}`,r=c=>c.replaceAll('"',"_").replace(/[\r\n]/g,""),o=typeof n.name=="string"?n.name:"blob",s=(c,p)=>`--${t}\r
|
|
7
|
-
Content-Disposition: form-data; ${c}\r
|
|
8
|
-
Content-Type: ${p}\r
|
|
9
|
-
\r
|
|
10
|
-
`,i=[];return e!==void 0&&i.push(s('name="body"',"application/json"),JSON.stringify(e),`\r
|
|
11
|
-
`),i.push(s(`name="file"; filename="${r(o)}"`,r(n.type)||"application/octet-stream"),n,`\r
|
|
12
|
-
--${t}--\r
|
|
13
|
-
`),{body:new Blob(i),type:`multipart/form-data; boundary=${t}`}}async function ve(e,n,t,r){if(typeof n!="string"||n===""||n==="/")throw new a("validation",{code:"invalid_endpoint_name",message:'Endpoint name must be a non-empty path like "todos/create"'});let o=n.startsWith("/")?n:`/${n}`;return Z(e(),{method:"POST",path:o},[t,r])}var ee=Object.fromEntries(Array.from({length:100},(e,n)=>[200+n,"raw"])),Ee=[["userJWT"],[]];async function ne(e,n,t,r,o,s){let i={op:`${n.method} ${n.path}`,method:n.method,path:t,auth:Ee,answers:ee,headers:o,...r===void 0?{}:{body:{kind:"json",contentType:"application/json",value:r}},idempotent:n.idempotent===!0,signal:s};try{return(await e.send(i)).data}catch(c){throw P(c)?$(c):c}}async function Se(e,n,t,r,o,s){return te(n,await ne(e,n,t,r,o,s),s)}async function te(e,n,t){let r=n.headers.get("x-request-id")??void 0,o;try{o=await n.text()}catch(s){throw t?.aborted?s:new a("network",{code:"network_error",message:`${e.method} ${e.path}: the answer did not arrive whole`,status:n.status,requestId:r,cause:s})}if(o!=="")try{return E(JSON.parse(o))}catch(s){throw new a("decode",{code:"invalid_json",message:`${e.method} ${e.path}: the answer is not JSON`,status:n.status,requestId:r,cause:s})}}async function Re(e,n,t,r,o,s){let i=new AbortController;s&&(s.aborted?i.abort():s.addEventListener("abort",()=>i.abort(),{once:!0}));let c=await ne(e,n,t,r,{accept:"text/event-stream",...o},i.signal);if(!c.body)throw new a("network",{code:"empty_stream",message:"the server answered a streaming route with no body",status:c.status});return M(c.body,i)}export{a,D as b,ae as c,C as d,R as e,le as f,Ke as g,Ue as h};
|