experimental-a2 0.5.0 → 0.6.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/CHANGELOG.md +60 -0
- package/dist/{ai-CFNeCrRl.d.ts → ai-D_PGS-JR.d.ts} +2 -2
- package/dist/{ai-CFNeCrRl.d.ts.map → ai-D_PGS-JR.d.ts.map} +1 -1
- package/dist/ai-server.d.ts +2 -2
- package/dist/ai-server.js +1 -1
- package/dist/ai.d.ts +1 -1
- package/dist/{client-D7mvIXrF.d.ts → client-CdMqi7mC.d.ts} +23 -12
- package/dist/client-CdMqi7mC.d.ts.map +1 -0
- package/dist/{client-BKlyLiOU.js → client-Dj5d3SP_.js} +37 -19
- package/dist/client-Dj5d3SP_.js.map +1 -0
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/http.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/otel.d.ts +1 -1
- package/dist/react.d.ts +41 -7
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +74 -35
- package/dist/react.js.map +1 -1
- package/dist/scheduler-qstash.d.ts +1 -1
- package/dist/scheduler-qstash.js +1 -1
- package/dist/scheduler-vercel.d.ts +1 -1
- package/dist/scheduler-vercel.js +1 -1
- package/dist/{server-DUF9pjsx.d.ts → server-DpvjhdoE.d.ts} +2 -2
- package/dist/{server-DUF9pjsx.d.ts.map → server-DpvjhdoE.d.ts.map} +1 -1
- package/dist/{server-C72KOw51.js → server-Duw6MVlB.js} +13 -7
- package/dist/server-Duw6MVlB.js.map +1 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +1 -1
- package/dist/{telemetry-BjYHTfh2.d.ts → telemetry-CpeclqB2.d.ts} +3 -3
- package/dist/{telemetry-BjYHTfh2.d.ts.map → telemetry-CpeclqB2.d.ts.map} +1 -1
- package/docs/guides/03-react.mdx +98 -1
- package/docs/guides/09-presence.mdx +5 -2
- package/docs/reference/01-api.mdx +45 -4
- package/package.json +1 -1
- package/src/client.ts +69 -33
- package/src/react.ts +118 -44
- package/src/server.ts +2 -2
- package/src/telemetry.ts +17 -10
- package/dist/client-BKlyLiOU.js.map +0 -1
- package/dist/client-D7mvIXrF.d.ts.map +0 -1
- package/dist/server-C72KOw51.js.map +0 -1
package/dist/react.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { t as createClient } from "./client-
|
|
2
|
+
import { t as createClient } from "./client-Dj5d3SP_.js";
|
|
3
3
|
import { createContext, createElement, useContext, useEffect, useMemo, useSyncExternalStore } from "react";
|
|
4
4
|
//#region src/react.ts
|
|
5
5
|
/**
|
|
@@ -13,10 +13,15 @@ import { createContext, createElement, useContext, useEffect, useMemo, useSyncEx
|
|
|
13
13
|
* renders resolve the same live session. Everything is typed by the
|
|
14
14
|
* reducer value — no type arguments, and nothing here ever touches the
|
|
15
15
|
* machine module.
|
|
16
|
+
*
|
|
17
|
+
* The standalone `useSession(client, sessionId, options?)` is the
|
|
18
|
+
* provider-less primitive for client-first apps: identity-mapped
|
|
19
|
+
* handles, one leased stream per session, and an app-owned hydration
|
|
20
|
+
* input — the hook holds the stream until the app hands it a
|
|
21
|
+
* `{ state, index }` fold.
|
|
16
22
|
*/
|
|
17
23
|
function createReact(options) {
|
|
18
24
|
const Context = createContext(null);
|
|
19
|
-
const providerMounts = /* @__PURE__ */ new WeakMap();
|
|
20
25
|
const resolveSession = "client" in options ? (sessionId, _api, initialState, initialIndex, initialEvents, participant) => options.client.session(sessionId, {
|
|
21
26
|
initialState,
|
|
22
27
|
initialIndex,
|
|
@@ -53,48 +58,82 @@ function createReact(options) {
|
|
|
53
58
|
initialEvents,
|
|
54
59
|
participant
|
|
55
60
|
]);
|
|
56
|
-
|
|
57
|
-
const mounts = providerMounts.get(client) ?? 0;
|
|
58
|
-
providerMounts.set(client, mounts + 1);
|
|
59
|
-
if (mounts === 0) client.connect();
|
|
60
|
-
return () => {
|
|
61
|
-
const remaining = (providerMounts.get(client) ?? 1) - 1;
|
|
62
|
-
if (remaining === 0) {
|
|
63
|
-
providerMounts.delete(client);
|
|
64
|
-
client.close();
|
|
65
|
-
} else providerMounts.set(client, remaining);
|
|
66
|
-
};
|
|
67
|
-
}, [client]);
|
|
61
|
+
useSessionLifecycle(client, true);
|
|
68
62
|
return createElement(Context.Provider, { value: client }, props.children);
|
|
69
63
|
}
|
|
70
|
-
function
|
|
64
|
+
function useBoundSession() {
|
|
71
65
|
const client = useContext(Context);
|
|
72
66
|
if (!client) throw new Error("useSession must be rendered inside its matching SessionProvider");
|
|
73
|
-
|
|
74
|
-
return useMemo(() => {
|
|
75
|
-
const { setPresence } = client;
|
|
76
|
-
const { presence } = snapshot;
|
|
77
|
-
return {
|
|
78
|
-
state: snapshot.state,
|
|
79
|
-
events: snapshot.events,
|
|
80
|
-
index: snapshot.index,
|
|
81
|
-
connection: snapshot.connection,
|
|
82
|
-
push: client.push,
|
|
83
|
-
loadHistory: client.loadHistory,
|
|
84
|
-
history: snapshot.history,
|
|
85
|
-
...setPresence && presence ? {
|
|
86
|
-
presence,
|
|
87
|
-
setPresence
|
|
88
|
-
} : {}
|
|
89
|
-
};
|
|
90
|
-
}, [snapshot, client]);
|
|
67
|
+
return useSessionResult(client);
|
|
91
68
|
}
|
|
92
69
|
return {
|
|
93
70
|
SessionProvider,
|
|
94
|
-
useSession
|
|
71
|
+
useSession: useBoundSession
|
|
95
72
|
};
|
|
96
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Hold a stream lease while mounted and `live` — the client refcounts
|
|
76
|
+
* leases per handle, so however many providers and hooks mount one
|
|
77
|
+
* session, the first connects and the last release closes
|
|
78
|
+
* (StrictMode-safe: the lease is retaken on remount). A standalone
|
|
79
|
+
* hook without a `hydrate` value passes `live: false` and holds the
|
|
80
|
+
* stream — connecting an unhydrated session would replay the whole
|
|
81
|
+
* log, and the library never picks the expensive path silently.
|
|
82
|
+
*/
|
|
83
|
+
function useSessionLifecycle(session, live) {
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
if (!live) return;
|
|
86
|
+
return session.connect();
|
|
87
|
+
}, [session, live]);
|
|
88
|
+
}
|
|
89
|
+
function useSessionResult(session) {
|
|
90
|
+
const snapshot = useSyncExternalStore(session.subscribe, session.getSnapshot, session.getSnapshot);
|
|
91
|
+
return useMemo(() => {
|
|
92
|
+
const { setPresence } = session;
|
|
93
|
+
const { presence } = snapshot;
|
|
94
|
+
return {
|
|
95
|
+
state: snapshot.state,
|
|
96
|
+
events: snapshot.events,
|
|
97
|
+
index: snapshot.index,
|
|
98
|
+
connection: snapshot.connection,
|
|
99
|
+
push: session.push,
|
|
100
|
+
loadHistory: session.loadHistory,
|
|
101
|
+
history: snapshot.history,
|
|
102
|
+
...setPresence && presence ? {
|
|
103
|
+
presence,
|
|
104
|
+
setPresence
|
|
105
|
+
} : {}
|
|
106
|
+
};
|
|
107
|
+
}, [snapshot, session]);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* The standalone, provider-less hook — for apps whose components reach
|
|
111
|
+
* sessions ad hoc (a sidebar of channel sessions, a user session read
|
|
112
|
+
* from a menu). Takes the shared client and a session id; the handle
|
|
113
|
+
* is identity-mapped, so every hook and provider mounting the same
|
|
114
|
+
* session shares one runtime and one leased stream. Hydration is
|
|
115
|
+
* app-owned: pass `hydrate` when your fetch lands; until then the
|
|
116
|
+
* stream is held, and your data layer's loading state is the pending
|
|
117
|
+
* state.
|
|
118
|
+
*/
|
|
119
|
+
function useSession(client, sessionId, options) {
|
|
120
|
+
const { participant, hydrate } = options ?? {};
|
|
121
|
+
const session = useMemo(() => client.session(sessionId, {
|
|
122
|
+
...hydrate === void 0 ? {} : {
|
|
123
|
+
initialState: hydrate.state,
|
|
124
|
+
initialIndex: hydrate.index
|
|
125
|
+
},
|
|
126
|
+
...participant === void 0 ? {} : { participant }
|
|
127
|
+
}), [
|
|
128
|
+
client,
|
|
129
|
+
sessionId,
|
|
130
|
+
hydrate,
|
|
131
|
+
participant
|
|
132
|
+
]);
|
|
133
|
+
useSessionLifecycle(session, hydrate !== void 0);
|
|
134
|
+
return useSessionResult(session);
|
|
135
|
+
}
|
|
97
136
|
//#endregion
|
|
98
|
-
export { createReact };
|
|
137
|
+
export { createReact, useSession };
|
|
99
138
|
|
|
100
139
|
//# sourceMappingURL=react.js.map
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.js","names":[],"sources":["../src/react.ts"],"sourcesContent":["'use client'\n/**\n * experimental-a2/react — React bindings over experimental-a2/client.\n *\n * `createReact({ client })` is a factory (like createContext): call it\n * once in a `'use client'` module with a shared A2 client and export the\n * bound pair. Server components import `SessionProvider` from that module\n * as a client reference; client components import `useSession` from the\n * same file. The shared client also makes imperative pushes and provider\n * renders resolve the same live session. Everything is typed by the\n * reducer value — no type arguments, and nothing here ever touches the\n * machine module.\n */\n\nimport {\n createContext,\n createElement,\n useContext,\n useEffect,\n useMemo,\n useSyncExternalStore,\n type ReactElement,\n type ReactNode,\n} from 'react'\nimport {\n createClient,\n type A2Client,\n type Connection,\n type HistoryState,\n type LoadHistoryOptions,\n type PushResult,\n type SessionClient,\n type SessionClientPresence,\n type SessionSnapshot,\n} from './client.ts'\nimport type {\n AppendInput,\n ContractEvent,\n EventDefs,\n PresenceDefs,\n PresenceMap,\n PresencePatch,\n WithPresence,\n} from './contract.ts'\nimport type { Reducer } from './reducer.ts'\n\nexport type SessionProviderProps<D extends EventDefs, S> = {\n /** Which session to subscribe to. */\n sessionId: string\n /** Base path of the route exposing GET (stream) and POST (push). */\n api: string\n /** The server-rendered fold — the first paint, no client JS needed. */\n initialState: S\n /** The fold's frontier — the stream resumes exactly there. */\n initialIndex: number\n /** Server-rendered event history through `initialIndex`. */\n initialEvents?: ContractEvent<D>[]\n /**\n * This client's presence identity — required to call `setPresence`.\n * Caller-supplied (a user id, a tab nonce, a guest name): A2 does\n * not invent an identity story.\n */\n participant?: string\n children?: ReactNode\n}\n\nexport type BoundSessionProviderProps<D extends EventDefs, S> = Omit<\n SessionProviderProps<D, S>,\n 'api'\n>\n\n/**\n * The presence members of the hook result — intersected in via\n * `WithPresence`, so they exist exactly when the contract declares\n * presence fields (the reducer is the client's typed handle on it).\n */\nexport type UseSessionPresence<P extends PresenceDefs> = {\n /** The replicated presence map, this client included (local echo). */\n presence: PresenceMap<P>\n /**\n * Fire-and-forget: validated locally, echoed into the map\n * immediately, coalesced on the wire to a fixed cadence (a leading\n * send immediately, then at most one merged send per interval;\n * later values win per field), stamped with the frontier at send\n * time as `seen`. Requires the provider's `participant`.\n */\n setPresence: (values: PresencePatch<P>['values']) => void\n}\n\nexport type UseSessionResult<\n D extends EventDefs,\n S,\n P extends PresenceDefs = Record<never, never>,\n> = WithPresence<P, UseSessionPresence<P>> & {\n /** The live view, folded through the shared reducer. */\n state: S\n /** The raw event feed — observed, seeded, or backscrolled. */\n events: ContractEvent<D>[]\n /** The stream frontier — `lastSeenIndex` for cancellation. */\n index: number\n /**\n * The connection, as a discriminated union — `error` exists only\n * while disconnected; \"reconnecting…\" is\n * `status === 'connecting' && reconnects > 0`.\n */\n connection: Connection\n /**\n * Typed optimistic append. Awaiting it gives the server ack;\n * `.confirmed` resolves when the live stream has delivered the batch\n * back. Rejects with the server's A2Error codes.\n */\n push: (...events: AppendInput<D>[]) => PushResult<D>\n /**\n * Backscroll: fetch a bounded slice of older events into `events`.\n * Defaults page backward 50 at a time from the oldest loaded event.\n * Display data only — `state` and the optimistic overlay never move.\n */\n loadHistory: (options?: LoadHistoryOptions) => Promise<ContractEvent<D>[]>\n /** Backscroll progress: `complete` means the feed reaches index 1. */\n history: HistoryState\n}\n\nexport type A2React<\n D extends EventDefs,\n S,\n P extends PresenceDefs = Record<never, never>,\n> = {\n SessionProvider: (props: SessionProviderProps<D, S>) => ReactElement\n useSession: () => UseSessionResult<D, S, P>\n}\n\nexport type BoundA2React<\n D extends EventDefs,\n S,\n P extends PresenceDefs = Record<never, never>,\n> = {\n SessionProvider: (props: BoundSessionProviderProps<D, S>) => ReactElement\n useSession: () => UseSessionResult<D, S, P>\n}\n\nexport function createReact<\n D extends EventDefs,\n S,\n P extends PresenceDefs = Record<never, never>,\n>(options: { client: A2Client<D, S, P> }): BoundA2React<D, S, P>\nexport function createReact<\n D extends EventDefs,\n S,\n P extends PresenceDefs = Record<never, never>,\n>(options: { reducer: Reducer<D, S, P> }): A2React<D, S, P>\nexport function createReact<\n D extends EventDefs,\n S,\n P extends PresenceDefs = Record<never, never>,\n>(\n options: { client: A2Client<D, S, P> } | { reducer: Reducer<D, S, P> },\n): BoundA2React<D, S, P> | A2React<D, S, P> {\n const Context = createContext<SessionClient<D, S, P> | null>(null)\n const providerMounts = new WeakMap<SessionClient<D, S, P> & object, number>()\n const resolveSession: (\n sessionId: string,\n api: string | undefined,\n initialState: S,\n initialIndex: number,\n initialEvents: ContractEvent<D>[] | undefined,\n participant: string | undefined,\n ) => SessionClient<D, S, P> =\n 'client' in options\n ? (\n sessionId,\n _api,\n initialState,\n initialIndex,\n initialEvents,\n participant,\n ) =>\n options.client.session(sessionId, {\n initialState,\n initialIndex,\n ...(initialEvents === undefined ? {} : { initialEvents }),\n ...(participant === undefined ? {} : { participant }),\n })\n : (() => {\n const clients = new Map<string, A2Client<D, S, P>>()\n return (\n sessionId: string,\n api: string | undefined,\n initialState: S,\n initialIndex: number,\n initialEvents: ContractEvent<D>[] | undefined,\n participant: string | undefined,\n ) => {\n if (api === undefined) {\n throw new TypeError(\n 'SessionProvider requires api when createReact binds a reducer',\n )\n }\n let client = clients.get(api)\n if (!client) {\n client = createClient({ reducer: options.reducer, api })\n clients.set(api, client)\n }\n return client.session(sessionId, {\n initialState,\n initialIndex,\n ...(initialEvents === undefined ? {} : { initialEvents }),\n ...(participant === undefined ? {} : { participant }),\n })\n }\n })()\n\n function SessionProvider(\n props: SessionProviderProps<D, S> | BoundSessionProviderProps<D, S>,\n ): ReactElement {\n const {\n sessionId,\n initialState,\n initialIndex,\n initialEvents,\n participant,\n } = props\n const api = 'api' in props ? props.api : undefined\n const client = useMemo(\n () =>\n resolveSession(\n sessionId,\n api,\n initialState,\n initialIndex,\n initialEvents,\n participant,\n ),\n [sessionId, api, initialState, initialIndex, initialEvents, participant],\n )\n useEffect(() => {\n const mounts = providerMounts.get(client) ?? 0\n providerMounts.set(client, mounts + 1)\n if (mounts === 0) client.connect()\n return () => {\n const remaining = (providerMounts.get(client) ?? 1) - 1\n if (remaining === 0) {\n providerMounts.delete(client)\n client.close()\n } else {\n providerMounts.set(client, remaining)\n }\n }\n }, [client])\n return createElement(Context.Provider, { value: client }, props.children)\n }\n\n function useSession(): UseSessionResult<D, S, P> {\n const client = useContext(Context)\n if (!client) {\n throw new Error(\n 'useSession must be rendered inside its matching SessionProvider',\n )\n }\n const snapshot: SessionSnapshot<D, S, P> = useSyncExternalStore(\n client.subscribe,\n client.getSnapshot,\n client.getSnapshot,\n )\n return useMemo(() => {\n // Runtime mirror of the WithPresence surface: the client attaches\n // setPresence (and the snapshot carries presence) exactly when the\n // reducer declares presence fields — no runtime-inert members.\n const { setPresence } = client as Partial<SessionClientPresence<P>>\n const { presence } = snapshot as Partial<{ presence: PresenceMap<P> }>\n return {\n state: snapshot.state,\n events: snapshot.events,\n index: snapshot.index,\n connection: snapshot.connection,\n push: client.push,\n loadHistory: client.loadHistory,\n history: snapshot.history,\n ...(setPresence && presence ? { presence, setPresence } : {}),\n } as UseSessionResult<D, S, P>\n }, [snapshot, client])\n }\n\n return { SessionProvider, useSession }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAsJA,SAAgB,YAKd,SAC0C;CAC1C,MAAM,UAAU,cAA6C,IAAI;CACjE,MAAM,iCAAiB,IAAI,QAAiD;CAC5E,MAAM,iBAQJ,YAAY,WAEN,WACA,MACA,cACA,cACA,eACA,gBAEA,QAAQ,OAAO,QAAQ,WAAW;EAChC;EACA;EACA,GAAI,kBAAkB,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc;EACvD,GAAI,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY;CACrD,CAAC,WACI;EACL,MAAM,0BAAU,IAAI,IAA+B;EACnD,QACE,WACA,KACA,cACA,cACA,eACA,gBACG;GACH,IAAI,QAAQ,KAAA,GACV,MAAM,IAAI,UACR,+DACF;GAEF,IAAI,SAAS,QAAQ,IAAI,GAAG;GAC5B,IAAI,CAAC,QAAQ;IACX,SAAS,aAAa;KAAE,SAAS,QAAQ;KAAS;IAAI,CAAC;IACvD,QAAQ,IAAI,KAAK,MAAM;GACzB;GACA,OAAO,OAAO,QAAQ,WAAW;IAC/B;IACA;IACA,GAAI,kBAAkB,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc;IACvD,GAAI,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY;GACrD,CAAC;EACH;CACF,EAAA,CAAG;CAET,SAAS,gBACP,OACc;EACd,MAAM,EACJ,WACA,cACA,cACA,eACA,gBACE;EACJ,MAAM,MAAM,SAAS,QAAQ,MAAM,MAAM,KAAA;EACzC,MAAM,SAAS,cAEX,eACE,WACA,KACA,cACA,cACA,eACA,WACF,GACF;GAAC;GAAW;GAAK;GAAc;GAAc;GAAe;EAAW,CACzE;EACA,gBAAgB;GACd,MAAM,SAAS,eAAe,IAAI,MAAM,KAAK;GAC7C,eAAe,IAAI,QAAQ,SAAS,CAAC;GACrC,IAAI,WAAW,GAAG,OAAO,QAAQ;GACjC,aAAa;IACX,MAAM,aAAa,eAAe,IAAI,MAAM,KAAK,KAAK;IACtD,IAAI,cAAc,GAAG;KACnB,eAAe,OAAO,MAAM;KAC5B,OAAO,MAAM;IACf,OACE,eAAe,IAAI,QAAQ,SAAS;GAExC;EACF,GAAG,CAAC,MAAM,CAAC;EACX,OAAO,cAAc,QAAQ,UAAU,EAAE,OAAO,OAAO,GAAG,MAAM,QAAQ;CAC1E;CAEA,SAAS,aAAwC;EAC/C,MAAM,SAAS,WAAW,OAAO;EACjC,IAAI,CAAC,QACH,MAAM,IAAI,MACR,iEACF;EAEF,MAAM,WAAqC,qBACzC,OAAO,WACP,OAAO,aACP,OAAO,WACT;EACA,OAAO,cAAc;GAInB,MAAM,EAAE,gBAAgB;GACxB,MAAM,EAAE,aAAa;GACrB,OAAO;IACL,OAAO,SAAS;IAChB,QAAQ,SAAS;IACjB,OAAO,SAAS;IAChB,YAAY,SAAS;IACrB,MAAM,OAAO;IACb,aAAa,OAAO;IACpB,SAAS,SAAS;IAClB,GAAI,eAAe,WAAW;KAAE;KAAU;IAAY,IAAI,CAAC;GAC7D;EACF,GAAG,CAAC,UAAU,MAAM,CAAC;CACvB;CAEA,OAAO;EAAE;EAAiB;CAAW;AACvC"}
|
|
1
|
+
{"version":3,"file":"react.js","names":[],"sources":["../src/react.ts"],"sourcesContent":["'use client'\n/**\n * experimental-a2/react — React bindings over experimental-a2/client.\n *\n * `createReact({ client })` is a factory (like createContext): call it\n * once in a `'use client'` module with a shared A2 client and export the\n * bound pair. Server components import `SessionProvider` from that module\n * as a client reference; client components import `useSession` from the\n * same file. The shared client also makes imperative pushes and provider\n * renders resolve the same live session. Everything is typed by the\n * reducer value — no type arguments, and nothing here ever touches the\n * machine module.\n *\n * The standalone `useSession(client, sessionId, options?)` is the\n * provider-less primitive for client-first apps: identity-mapped\n * handles, one leased stream per session, and an app-owned hydration\n * input — the hook holds the stream until the app hands it a\n * `{ state, index }` fold.\n */\n\nimport {\n createContext,\n createElement,\n useContext,\n useEffect,\n useMemo,\n useSyncExternalStore,\n type ReactElement,\n type ReactNode,\n} from 'react'\nimport {\n createClient,\n type A2Client,\n type Connection,\n type HistoryState,\n type LoadHistoryOptions,\n type PushResult,\n type SessionClient,\n type SessionClientPresence,\n type SessionSnapshot,\n} from './client.ts'\nimport type {\n AppendInput,\n ContractEvent,\n EventDefs,\n PresenceDefs,\n PresenceMap,\n PresencePatch,\n WithPresence,\n} from './contract.ts'\nimport type { Reducer } from './reducer.ts'\n\nexport type UseSessionOptions<S> = {\n /** Overrides the client's `participant` for this session — for apps\n * whose identity is only known at mount time. Bound once per\n * session handle. */\n participant?: string\n /**\n * The server fold this session mounts from: the `{ state, index }`\n * pair `session.state(reducer)` returns, fetched by the app through\n * its own route. Atomic on purpose — the fold and its frontier\n * travel together or not at all. While `undefined` (the app's fetch\n * has not landed), the hook holds the stream; when the value\n * arrives, the session hydrates through the ordinary re-hydration\n * seam and the stream connects at that frontier. To fold from the log's start\n * deliberately, hand the fold's true starting point:\n * `{ state: reducer.initialState, index: 0 }` — state at index 0 is\n * the reducer's seed by definition, so the explicit replay needs no\n * special vocabulary. There is no pending/ready echo on the result:\n * whether the fold has been handed over is this option — the\n * caller's own input — so the data layer's loading state IS the\n * pending state.\n */\n hydrate?: { state: S; index: number } | undefined\n}\n\nexport type SessionProviderProps<D extends EventDefs, S> = {\n /** Which session to subscribe to. */\n sessionId: string\n /** Base path of the route exposing GET (stream) and POST (push). */\n api: string\n /** The server-rendered fold — the first paint, no client JS needed. */\n initialState: S\n /** The fold's frontier — the stream resumes exactly there. */\n initialIndex: number\n /** Server-rendered event history through `initialIndex`. */\n initialEvents?: ContractEvent<D>[]\n /** Overrides the client's `participant` for this session — for apps\n * whose identity is only known at mount time. */\n participant?: string\n children?: ReactNode\n}\n\nexport type BoundSessionProviderProps<D extends EventDefs, S> = Omit<\n SessionProviderProps<D, S>,\n 'api'\n>\n\n/**\n * The presence members of the hook result — intersected in via\n * `WithPresence`, so they exist exactly when the contract declares\n * presence fields (the reducer is the client's typed handle on it).\n */\nexport type UseSessionPresence<P extends PresenceDefs> = {\n /** The replicated presence map, this client included (local echo). */\n presence: PresenceMap<P>\n /**\n * Fire-and-forget: validated locally, echoed into the map\n * immediately, coalesced on the wire to a fixed cadence (a leading\n * send immediately, then at most one merged send per interval;\n * later values win per field), stamped with the frontier at send\n * time as `seen`. Requires the provider's `participant`.\n */\n setPresence: (values: PresencePatch<P>['values']) => void\n}\n\nexport type UseSessionResult<\n D extends EventDefs,\n S,\n P extends PresenceDefs = Record<never, never>,\n> = WithPresence<P, UseSessionPresence<P>> & {\n /** The live view, folded through the shared reducer. */\n state: S\n /** The raw event feed — observed, seeded, or backscrolled. */\n events: ContractEvent<D>[]\n /** The stream frontier — `lastSeenIndex` for cancellation. */\n index: number\n /**\n * The connection, as a discriminated union — `error` exists only\n * while disconnected; \"reconnecting…\" is\n * `status === 'connecting' && reconnects > 0`.\n */\n connection: Connection\n /**\n * Typed optimistic append. Awaiting it gives the server ack;\n * `.confirmed` resolves when the live stream has delivered the batch\n * back. Rejects with the server's A2Error codes.\n */\n push: (...events: AppendInput<D>[]) => PushResult<D>\n /**\n * Backscroll: fetch a bounded slice of older events into `events`.\n * Defaults page backward 50 at a time from the oldest loaded event.\n * Display data only — `state` and the optimistic overlay never move.\n */\n loadHistory: (options?: LoadHistoryOptions) => Promise<ContractEvent<D>[]>\n /** Backscroll progress: `complete` means the feed reaches index 1. */\n history: HistoryState\n}\n\nexport type A2React<\n D extends EventDefs,\n S,\n P extends PresenceDefs = Record<never, never>,\n> = {\n SessionProvider: (props: SessionProviderProps<D, S>) => ReactElement\n useSession: () => UseSessionResult<D, S, P>\n}\n\nexport type BoundA2React<\n D extends EventDefs,\n S,\n P extends PresenceDefs = Record<never, never>,\n> = {\n SessionProvider: (props: BoundSessionProviderProps<D, S>) => ReactElement\n useSession: () => UseSessionResult<D, S, P>\n}\n\nexport function createReact<\n D extends EventDefs,\n S,\n P extends PresenceDefs = Record<never, never>,\n>(options: { client: A2Client<D, S, P> }): BoundA2React<D, S, P>\nexport function createReact<\n D extends EventDefs,\n S,\n P extends PresenceDefs = Record<never, never>,\n>(options: { reducer: Reducer<D, S, P> }): A2React<D, S, P>\nexport function createReact<\n D extends EventDefs,\n S,\n P extends PresenceDefs = Record<never, never>,\n>(\n options: { client: A2Client<D, S, P> } | { reducer: Reducer<D, S, P> },\n): BoundA2React<D, S, P> | A2React<D, S, P> {\n const Context = createContext<SessionClient<D, S, P> | null>(null)\n const resolveSession: (\n sessionId: string,\n api: string | undefined,\n initialState: S,\n initialIndex: number,\n initialEvents: ContractEvent<D>[] | undefined,\n participant: string | undefined,\n ) => SessionClient<D, S, P> =\n 'client' in options\n ? (\n sessionId,\n _api,\n initialState,\n initialIndex,\n initialEvents,\n participant,\n ) =>\n options.client.session(sessionId, {\n initialState,\n initialIndex,\n ...(initialEvents === undefined ? {} : { initialEvents }),\n ...(participant === undefined ? {} : { participant }),\n })\n : (() => {\n const clients = new Map<string, A2Client<D, S, P>>()\n return (\n sessionId: string,\n api: string | undefined,\n initialState: S,\n initialIndex: number,\n initialEvents: ContractEvent<D>[] | undefined,\n participant: string | undefined,\n ) => {\n if (api === undefined) {\n throw new TypeError(\n 'SessionProvider requires api when createReact binds a reducer',\n )\n }\n let client = clients.get(api)\n if (!client) {\n client = createClient({ reducer: options.reducer, api })\n clients.set(api, client)\n }\n return client.session(sessionId, {\n initialState,\n initialIndex,\n ...(initialEvents === undefined ? {} : { initialEvents }),\n ...(participant === undefined ? {} : { participant }),\n })\n }\n })()\n\n function SessionProvider(\n props: SessionProviderProps<D, S> | BoundSessionProviderProps<D, S>,\n ): ReactElement {\n const {\n sessionId,\n initialState,\n initialIndex,\n initialEvents,\n participant,\n } = props\n const api = 'api' in props ? props.api : undefined\n const client = useMemo(\n () =>\n resolveSession(\n sessionId,\n api,\n initialState,\n initialIndex,\n initialEvents,\n participant,\n ),\n [sessionId, api, initialState, initialIndex, initialEvents, participant],\n )\n useSessionLifecycle(client, true)\n return createElement(Context.Provider, { value: client }, props.children)\n }\n\n function useBoundSession(): UseSessionResult<D, S, P> {\n const client = useContext(Context)\n if (!client) {\n throw new Error(\n 'useSession must be rendered inside its matching SessionProvider',\n )\n }\n return useSessionResult(client)\n }\n\n return { SessionProvider, useSession: useBoundSession }\n}\n\n// ── the shared session lifecycle ───────────────────────────────\n\n/**\n * Hold a stream lease while mounted and `live` — the client refcounts\n * leases per handle, so however many providers and hooks mount one\n * session, the first connects and the last release closes\n * (StrictMode-safe: the lease is retaken on remount). A standalone\n * hook without a `hydrate` value passes `live: false` and holds the\n * stream — connecting an unhydrated session would replay the whole\n * log, and the library never picks the expensive path silently.\n */\nfunction useSessionLifecycle<D extends EventDefs, S, P extends PresenceDefs>(\n session: SessionClient<D, S, P>,\n live: boolean,\n): void {\n useEffect(() => {\n if (!live) return\n return session.connect()\n }, [session, live])\n}\n\nfunction useSessionResult<D extends EventDefs, S, P extends PresenceDefs>(\n session: SessionClient<D, S, P>,\n): UseSessionResult<D, S, P> {\n const snapshot: SessionSnapshot<D, S, P> = useSyncExternalStore(\n session.subscribe,\n session.getSnapshot,\n session.getSnapshot,\n )\n return useMemo(() => {\n // Runtime mirror of the WithPresence surface: the client attaches\n // setPresence (and the snapshot carries presence) exactly when the\n // reducer declares presence fields — no runtime-inert members.\n const { setPresence } = session as Partial<SessionClientPresence<P>>\n const { presence } = snapshot as Partial<{ presence: PresenceMap<P> }>\n return {\n state: snapshot.state,\n events: snapshot.events,\n index: snapshot.index,\n connection: snapshot.connection,\n push: session.push,\n loadHistory: session.loadHistory,\n history: snapshot.history,\n ...(setPresence && presence ? { presence, setPresence } : {}),\n } as UseSessionResult<D, S, P>\n }, [snapshot, session])\n}\n\n/**\n * The standalone, provider-less hook — for apps whose components reach\n * sessions ad hoc (a sidebar of channel sessions, a user session read\n * from a menu). Takes the shared client and a session id; the handle\n * is identity-mapped, so every hook and provider mounting the same\n * session shares one runtime and one leased stream. Hydration is\n * app-owned: pass `hydrate` when your fetch lands; until then the\n * stream is held, and your data layer's loading state is the pending\n * state.\n */\nexport function useSession<\n D extends EventDefs,\n S,\n P extends PresenceDefs = Record<never, never>,\n>(\n client: A2Client<D, S, P>,\n sessionId: string,\n options?: UseSessionOptions<S>,\n): UseSessionResult<D, S, P> {\n const { participant, hydrate } = options ?? {}\n const session = useMemo(\n () =>\n client.session(sessionId, {\n ...(hydrate === undefined\n ? {}\n : { initialState: hydrate.state, initialIndex: hydrate.index }),\n ...(participant === undefined ? {} : { participant }),\n }),\n [client, sessionId, hydrate, participant],\n )\n useSessionLifecycle(session, hydrate !== undefined)\n return useSessionResult(session)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAiLA,SAAgB,YAKd,SAC0C;CAC1C,MAAM,UAAU,cAA6C,IAAI;CACjE,MAAM,iBAQJ,YAAY,WAEN,WACA,MACA,cACA,cACA,eACA,gBAEA,QAAQ,OAAO,QAAQ,WAAW;EAChC;EACA;EACA,GAAI,kBAAkB,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc;EACvD,GAAI,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY;CACrD,CAAC,WACI;EACL,MAAM,0BAAU,IAAI,IAA+B;EACnD,QACE,WACA,KACA,cACA,cACA,eACA,gBACG;GACH,IAAI,QAAQ,KAAA,GACV,MAAM,IAAI,UACR,+DACF;GAEF,IAAI,SAAS,QAAQ,IAAI,GAAG;GAC5B,IAAI,CAAC,QAAQ;IACX,SAAS,aAAa;KAAE,SAAS,QAAQ;KAAS;IAAI,CAAC;IACvD,QAAQ,IAAI,KAAK,MAAM;GACzB;GACA,OAAO,OAAO,QAAQ,WAAW;IAC/B;IACA;IACA,GAAI,kBAAkB,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc;IACvD,GAAI,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY;GACrD,CAAC;EACH;CACF,EAAA,CAAG;CAET,SAAS,gBACP,OACc;EACd,MAAM,EACJ,WACA,cACA,cACA,eACA,gBACE;EACJ,MAAM,MAAM,SAAS,QAAQ,MAAM,MAAM,KAAA;EACzC,MAAM,SAAS,cAEX,eACE,WACA,KACA,cACA,cACA,eACA,WACF,GACF;GAAC;GAAW;GAAK;GAAc;GAAc;GAAe;EAAW,CACzE;EACA,oBAAoB,QAAQ,IAAI;EAChC,OAAO,cAAc,QAAQ,UAAU,EAAE,OAAO,OAAO,GAAG,MAAM,QAAQ;CAC1E;CAEA,SAAS,kBAA6C;EACpD,MAAM,SAAS,WAAW,OAAO;EACjC,IAAI,CAAC,QACH,MAAM,IAAI,MACR,iEACF;EAEF,OAAO,iBAAiB,MAAM;CAChC;CAEA,OAAO;EAAE;EAAiB,YAAY;CAAgB;AACxD;;;;;;;;;;AAaA,SAAS,oBACP,SACA,MACM;CACN,gBAAgB;EACd,IAAI,CAAC,MAAM;EACX,OAAO,QAAQ,QAAQ;CACzB,GAAG,CAAC,SAAS,IAAI,CAAC;AACpB;AAEA,SAAS,iBACP,SAC2B;CAC3B,MAAM,WAAqC,qBACzC,QAAQ,WACR,QAAQ,aACR,QAAQ,WACV;CACA,OAAO,cAAc;EAInB,MAAM,EAAE,gBAAgB;EACxB,MAAM,EAAE,aAAa;EACrB,OAAO;GACL,OAAO,SAAS;GAChB,QAAQ,SAAS;GACjB,OAAO,SAAS;GAChB,YAAY,SAAS;GACrB,MAAM,QAAQ;GACd,aAAa,QAAQ;GACrB,SAAS,SAAS;GAClB,GAAI,eAAe,WAAW;IAAE;IAAU;GAAY,IAAI,CAAC;EAC7D;CACF,GAAG,CAAC,UAAU,OAAO,CAAC;AACxB;;;;;;;;;;;AAYA,SAAgB,WAKd,QACA,WACA,SAC2B;CAC3B,MAAM,EAAE,aAAa,YAAY,WAAW,CAAC;CAC7C,MAAM,UAAU,cAEZ,OAAO,QAAQ,WAAW;EACxB,GAAI,YAAY,KAAA,IACZ,CAAC,IACD;GAAE,cAAc,QAAQ;GAAO,cAAc,QAAQ;EAAM;EAC/D,GAAI,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY;CACrD,CAAC,GACH;EAAC;EAAQ;EAAW;EAAS;CAAW,CAC1C;CACA,oBAAoB,SAAS,YAAY,KAAA,CAAS;CAClD,OAAO,iBAAiB,OAAO;AACjC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as Clock } from "./store-DysUkTH3.js";
|
|
2
|
-
import { D as SchedulerTask, t as A2Scheduler } from "./server-
|
|
2
|
+
import { D as SchedulerTask, t as A2Scheduler } from "./server-DpvjhdoE.js";
|
|
3
3
|
//#region src/scheduler-qstash.d.ts
|
|
4
4
|
type QStashStoreOutage = {
|
|
5
5
|
version: 1;
|
package/dist/scheduler-qstash.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as A2Error } from "./errors-BQuJpe82.js";
|
|
2
2
|
import { f as classifySchedulerSendFailure, t as DRAIN_TIMINGS, u as assertSchedulerTargets, v as serverInternals } from "./internal-DstsI6Re.js";
|
|
3
|
-
import { n as deliverSchedulerAppend } from "./server-
|
|
3
|
+
import { n as deliverSchedulerAppend } from "./server-Duw6MVlB.js";
|
|
4
4
|
import { n as platformVercelOidcToken } from "./platform-B4TnJtWu.js";
|
|
5
5
|
import { t as retryableLazy } from "./retryable-lazy-DZWmHpii.js";
|
|
6
6
|
import { n as SYSTEM_CLOCK } from "./store-N8PXxDAS.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as Clock } from "./store-DysUkTH3.js";
|
|
2
|
-
import { D as SchedulerTask, t as A2Scheduler } from "./server-
|
|
2
|
+
import { D as SchedulerTask, t as A2Scheduler } from "./server-DpvjhdoE.js";
|
|
3
3
|
//#region src/scheduler-vercel.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* The "not settled yet" signal for a stalled handler — an expected state,
|
package/dist/scheduler-vercel.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { f as classifySchedulerSendFailure, t as DRAIN_TIMINGS, u as assertSchedulerTargets, v as serverInternals } from "./internal-DstsI6Re.js";
|
|
2
|
-
import { n as deliverSchedulerAppend } from "./server-
|
|
2
|
+
import { n as deliverSchedulerAppend } from "./server-Duw6MVlB.js";
|
|
3
3
|
import { t as retryableLazy } from "./retryable-lazy-DZWmHpii.js";
|
|
4
4
|
import { n as SYSTEM_CLOCK } from "./store-N8PXxDAS.js";
|
|
5
5
|
import { t as normalizeSchedulerTask } from "./scheduler-task-BpzhPnRS.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as EventDefs, c as PresencePatch, d as WithPresence, l as PresenceSnapshot, n as Contract, o as PresenceDefs, p as Reducer, r as ContractEvent, s as PresenceMap, t as AppendInput } from "./contract-jIfaR085.js";
|
|
2
2
|
import { t as A2Store } from "./store-DysUkTH3.js";
|
|
3
|
-
import { i as A2Telemetry } from "./telemetry-
|
|
3
|
+
import { i as A2Telemetry } from "./telemetry-CpeclqB2.js";
|
|
4
4
|
//#region src/scheduler-task.d.ts
|
|
5
5
|
/** One event carried by a delayed append task. */
|
|
6
6
|
type ScheduledEvent = {
|
|
@@ -258,4 +258,4 @@ type ServerOptions<D extends EventDefs, P extends PresenceDefs = Record<never, n
|
|
|
258
258
|
declare function createServer<D extends EventDefs, P extends PresenceDefs = Record<never, never>>(options: ServerOptions<D, P>): A2Server<D, P>;
|
|
259
259
|
//#endregion
|
|
260
260
|
export { deliverSchedulerAppend as C, SchedulerTask as D, SchedulerDrainTask as E, createServer as S, SchedulerAppendTask as T, Session as _, Handler as a, SessionPresence as b, HandlerEntry as c, PushValidationContext as d, PushedEvent as f, ServerOptions as g, ScheduleTiming as h, DrainableServer as i, Lane as l, ScheduleDelay as m, A2Server as n, HandlerAppend as o, PushedPresence as p, AbortSpec as r, HandlerContext as s, A2Scheduler as t, LaneContext as u, SessionAppend as v, ScheduledEvent as w, SessionSchedule as x, SessionDispatch as y };
|
|
261
|
-
//# sourceMappingURL=server-
|
|
261
|
+
//# sourceMappingURL=server-DpvjhdoE.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-
|
|
1
|
+
{"version":3,"file":"server-DpvjhdoE.d.ts","names":[],"sources":["../src/scheduler-task.ts","../src/server.ts"],"mappings":"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"}
|
|
@@ -66,12 +66,18 @@ async function deterministicScheduledEventId(scheduleId, itemOrdinal) {
|
|
|
66
66
|
}
|
|
67
67
|
//#endregion
|
|
68
68
|
//#region src/telemetry.ts
|
|
69
|
-
|
|
69
|
+
/**
|
|
70
|
+
* The default when no telemetry is configured. Spans cost nothing, but
|
|
71
|
+
* `recordError` prints: it only ever receives errors a2 swallows by
|
|
72
|
+
* design, so without a configured sink the console is the one place
|
|
73
|
+
* they can surface. Passing `telemetry` replaces this sink wholesale.
|
|
74
|
+
*/
|
|
75
|
+
const CONSOLE_TELEMETRY = { span: (name, attributes, fn) => fn({
|
|
70
76
|
setAttribute: () => {},
|
|
71
|
-
recordError: () => {
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
recordError: (error) => {
|
|
78
|
+
console.error(`[a2] error in ${name}`, attributes, error);
|
|
79
|
+
}
|
|
80
|
+
}) };
|
|
75
81
|
//#endregion
|
|
76
82
|
//#region src/server.ts
|
|
77
83
|
/**
|
|
@@ -230,7 +236,7 @@ function createServer(options) {
|
|
|
230
236
|
};
|
|
231
237
|
}
|
|
232
238
|
const resolveStore = retryableLazy(makeStore).get;
|
|
233
|
-
const telemetry = options.telemetry ??
|
|
239
|
+
const telemetry = options.telemetry ?? CONSOLE_TELEMETRY;
|
|
234
240
|
const scheduler = options.scheduler;
|
|
235
241
|
const handlers = /* @__PURE__ */ new Map();
|
|
236
242
|
for (const [type, entry] of Object.entries(options.handlers ?? {})) {
|
|
@@ -1454,4 +1460,4 @@ function cloneInitial(initial) {
|
|
|
1454
1460
|
//#endregion
|
|
1455
1461
|
export { deliverSchedulerAppend as n, createServer as t };
|
|
1456
1462
|
|
|
1457
|
-
//# sourceMappingURL=server-
|
|
1463
|
+
//# sourceMappingURL=server-Duw6MVlB.js.map
|