experimental-a2 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/CHANGELOG.md +169 -0
  2. package/dist/ai-B4YhEnfw.d.ts +333 -0
  3. package/dist/ai-server.d.ts +48 -9
  4. package/dist/ai-server.js +121 -49
  5. package/dist/ai.d.ts +2 -303
  6. package/dist/ai.js +231 -86
  7. package/dist/cli-B3VuxoDe.js +597 -0
  8. package/dist/cli-bin.d.ts +1 -0
  9. package/dist/cli-bin.js +5 -0
  10. package/dist/cli.d.ts +19 -0
  11. package/dist/cli.js +2 -0
  12. package/dist/client-BrfDXQ8A.d.ts +155 -0
  13. package/dist/client-Bt4tAKi9.js +798 -0
  14. package/dist/client.d.ts +2 -90
  15. package/dist/client.js +1 -409
  16. package/dist/{contract-CG_adnu_.js → contract-48bUMgcL.js} +10 -2
  17. package/dist/{contract-C_3dIIEU.d.ts → contract-jIfaR085.d.ts} +62 -8
  18. package/dist/devtools-J_jZ2vQf.d.ts +151 -0
  19. package/dist/devtools-kJJaORn-.js +338 -0
  20. package/dist/devtools-server.browser.js +1 -1
  21. package/dist/devtools-server.d.ts +2 -2
  22. package/dist/devtools-server.js +224 -43
  23. package/dist/devtools.d.ts +2 -0
  24. package/dist/devtools.js +2 -0
  25. package/dist/{errors-BJRMd-h6.js → errors-BQuJpe82.js} +4 -4
  26. package/dist/{errors-xL_JTXsY.d.ts → errors-W6nwJ-fm.d.ts} +1 -1
  27. package/dist/http.d.ts +71 -13
  28. package/dist/http.js +302 -41
  29. package/dist/{idempotent-replay-BMyHrP0L.js → idempotent-replay-DuqEkYA7.js} +2 -2
  30. package/dist/index.d.ts +5 -5
  31. package/dist/index.js +2 -2
  32. package/dist/{inspection-E7qbD0Xj.js → inspection-DaxB5jM2.js} +2 -1
  33. package/dist/internal-aEotMzu_.js +209 -0
  34. package/dist/otel.d.ts +1 -1
  35. package/dist/platform-B4TnJtWu.js +32 -0
  36. package/dist/react.d.ts +37 -14
  37. package/dist/react.js +26 -15
  38. package/dist/scheduler-qstash.d.ts +78 -0
  39. package/dist/scheduler-qstash.js +499 -0
  40. package/dist/scheduler-task-BpzhPnRS.js +54 -0
  41. package/dist/{recovery-vercel.d.ts → scheduler-vercel.d.ts} +17 -24
  42. package/dist/scheduler-vercel.js +226 -0
  43. package/dist/server-CcNnFnoW.js +1405 -0
  44. package/dist/server-YtPq7hjw.d.ts +260 -0
  45. package/dist/server.d.ts +4 -155
  46. package/dist/server.js +2 -2
  47. package/dist/{log-ldf5g8Cx.d.ts → store-C3sNAaBT.d.ts} +111 -35
  48. package/dist/{log-yJbXUf72.js → store-N8PXxDAS.js} +1 -1
  49. package/dist/store-codec-DTG0Ftek.js +8 -0
  50. package/dist/store-memory.d.ts +11 -0
  51. package/dist/{log-memory.js → store-memory.js} +127 -24
  52. package/dist/{log-polling-6COoN60V.js → store-polling-DgrrAE3d.js} +7 -6
  53. package/dist/{log-postgres.d.ts → store-postgres.d.ts} +6 -6
  54. package/dist/{log-postgres.js → store-postgres.js} +158 -24
  55. package/dist/{log-redis.js → store-redis-core-DWqx3F47.js} +294 -156
  56. package/dist/store-redis-http.d.ts +21 -0
  57. package/dist/store-redis-http.js +70 -0
  58. package/dist/store-redis.d.ts +37 -0
  59. package/dist/store-redis.js +298 -0
  60. package/dist/{log-sqlite.d.ts → store-sqlite.d.ts} +6 -6
  61. package/dist/{log-sqlite.js → store-sqlite.js} +116 -22
  62. package/dist/{telemetry-Cso0qyHQ.d.ts → telemetry-BjYHTfh2.d.ts} +1 -1
  63. package/dist/testing.browser.d.ts +1 -0
  64. package/dist/testing.browser.js +4 -0
  65. package/dist/testing.d.ts +31 -0
  66. package/dist/testing.js +101 -0
  67. package/dist/wire-DCUZBUlT.js +222 -0
  68. package/docs/01-quickstart.mdx +4 -5
  69. package/docs/concepts/01-contracts.mdx +21 -17
  70. package/docs/concepts/02-handlers.mdx +7 -7
  71. package/docs/concepts/03-durability.mdx +26 -29
  72. package/docs/concepts/04-state.mdx +18 -21
  73. package/docs/guides/01-timers.mdx +154 -54
  74. package/docs/guides/02-cancellation.mdx +30 -4
  75. package/docs/guides/03-react.mdx +20 -21
  76. package/docs/guides/04-local-first.mdx +1 -1
  77. package/docs/guides/05-production.mdx +321 -60
  78. package/docs/guides/06-ai-agents.mdx +249 -49
  79. package/docs/guides/07-devtools.mdx +137 -12
  80. package/docs/guides/08-application-data.mdx +1 -1
  81. package/docs/guides/09-presence.mdx +284 -0
  82. package/docs/guides/10-transports.mdx +131 -0
  83. package/docs/index.mdx +22 -46
  84. package/docs/reference/01-api.mdx +751 -102
  85. package/docs/reference/02-errors.mdx +10 -5
  86. package/package.json +23 -6
  87. package/dist/internal-D6wNxTck.js +0 -36
  88. package/dist/log-memory.d.ts +0 -11
  89. package/dist/log-redis.d.ts +0 -31
  90. package/dist/recovery-vercel.js +0 -119
  91. package/dist/server-DJgD2YWP.js +0 -877
  92. package/dist/wire-BVsgR8o9.js +0 -62
@@ -0,0 +1,32 @@
1
+ //#region src/platform.ts
2
+ const SYMBOL_FOR_REQ_CONTEXT = Symbol.for("@vercel/request-context");
3
+ function requestContext() {
4
+ try {
5
+ return Reflect.get(globalThis, SYMBOL_FOR_REQ_CONTEXT)?.get?.() ?? {};
6
+ } catch {
7
+ return {};
8
+ }
9
+ }
10
+ /** The current invocation's Vercel deployment identity, when available. */
11
+ function platformVercelOidcToken() {
12
+ try {
13
+ const token = requestContext().headers?.["x-vercel-oidc-token"];
14
+ return typeof token === "string" && token.length > 0 ? token : null;
15
+ } catch {
16
+ return null;
17
+ }
18
+ }
19
+ function platformWaitUntil(promise) {
20
+ try {
21
+ requestContext().waitUntil?.(promise);
22
+ } catch {}
23
+ }
24
+ /** The invocation's termination time in epoch ms, or null if unknowable. */
25
+ function invocationDeadlineMs() {
26
+ const deadline = requestContext().deadline;
27
+ if (deadline === void 0 || deadline === null) return null;
28
+ const ms = new Date(deadline).getTime();
29
+ return Number.isNaN(ms) ? null : ms;
30
+ }
31
+ //#endregion
32
+ export { platformVercelOidcToken as n, platformWaitUntil as r, invocationDeadlineMs as t };
package/dist/react.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as EventDefs, c as Reducer, r as ContractEvent, t as AppendInput } from "./contract-C_3dIIEU.js";
2
- import { A2Client, Connection, PushResult } from "./client.js";
1
+ import { a as EventDefs, c as PresencePatch, d as WithPresence, o as PresenceDefs, p as Reducer, r as ContractEvent, s as PresenceMap, t as AppendInput } from "./contract-jIfaR085.js";
2
+ import { a as Connection, c as PushResult, t as A2Client } from "./client-BrfDXQ8A.js";
3
3
  import { ReactElement, ReactNode } from "react";
4
4
  //#region src/react.d.ts
5
5
  type SessionProviderProps<D extends EventDefs, S> = {
@@ -13,10 +13,33 @@ type SessionProviderProps<D extends EventDefs, S> = {
13
13
  initialIndex: number;
14
14
  /** Server-rendered event history through `initialIndex`. */
15
15
  initialEvents?: ContractEvent<D>[];
16
+ /**
17
+ * This client's presence identity — required to call `setPresence`.
18
+ * Caller-supplied (a user id, a tab nonce, a guest name): A2 does
19
+ * not invent an identity story.
20
+ */
21
+ participant?: string;
16
22
  children?: ReactNode;
17
23
  };
18
24
  type BoundSessionProviderProps<D extends EventDefs, S> = Omit<SessionProviderProps<D, S>, "api">;
19
- type UseSessionResult<D extends EventDefs, S> = {
25
+ /**
26
+ * The presence members of the hook result — intersected in via
27
+ * `WithPresence`, so they exist exactly when the contract declares
28
+ * presence fields (the reducer is the client's typed handle on it).
29
+ */
30
+ type UseSessionPresence<P extends PresenceDefs> = {
31
+ /** The replicated presence map, this client included (local echo). */
32
+ presence: PresenceMap<P>;
33
+ /**
34
+ * Fire-and-forget: validated locally, echoed into the map
35
+ * immediately, coalesced on the wire to a fixed cadence (a leading
36
+ * send immediately, then at most one merged send per interval;
37
+ * later values win per field), stamped with the frontier at send
38
+ * time as `seen`. Requires the provider's `participant`.
39
+ */
40
+ setPresence: (values: PresencePatch<P>["values"]) => void;
41
+ };
42
+ type UseSessionResult<D extends EventDefs, S, P extends PresenceDefs = Record<never, never>> = WithPresence<P, UseSessionPresence<P>> & {
20
43
  /** The live view, folded through the shared reducer. */
21
44
  state: S;
22
45
  /** The raw observed feed `state` is folded from. */
@@ -36,19 +59,19 @@ type UseSessionResult<D extends EventDefs, S> = {
36
59
  */
37
60
  push: (...events: AppendInput<D>[]) => PushResult<D>;
38
61
  };
39
- type A2React<D extends EventDefs, S> = {
62
+ type A2React<D extends EventDefs, S, P extends PresenceDefs = Record<never, never>> = {
40
63
  SessionProvider: (props: SessionProviderProps<D, S>) => ReactElement;
41
- useSession: () => UseSessionResult<D, S>;
64
+ useSession: () => UseSessionResult<D, S, P>;
42
65
  };
43
- type BoundA2React<D extends EventDefs, S> = {
66
+ type BoundA2React<D extends EventDefs, S, P extends PresenceDefs = Record<never, never>> = {
44
67
  SessionProvider: (props: BoundSessionProviderProps<D, S>) => ReactElement;
45
- useSession: () => UseSessionResult<D, S>;
68
+ useSession: () => UseSessionResult<D, S, P>;
46
69
  };
47
- declare function createReact<D extends EventDefs, S>(options: {
48
- client: A2Client<D, S>;
49
- }): BoundA2React<D, S>;
50
- declare function createReact<D extends EventDefs, S>(options: {
51
- reducer: Reducer<D, S>;
52
- }): A2React<D, S>;
70
+ declare function createReact<D extends EventDefs, S, P extends PresenceDefs = Record<never, never>>(options: {
71
+ client: A2Client<D, S, P>;
72
+ }): BoundA2React<D, S, P>;
73
+ declare function createReact<D extends EventDefs, S, P extends PresenceDefs = Record<never, never>>(options: {
74
+ reducer: Reducer<D, S, P>;
75
+ }): A2React<D, S, P>;
53
76
  //#endregion
54
- export { A2React, BoundA2React, BoundSessionProviderProps, SessionProviderProps, UseSessionResult, createReact };
77
+ export { A2React, BoundA2React, BoundSessionProviderProps, SessionProviderProps, UseSessionPresence, UseSessionResult, createReact };
package/dist/react.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { createClient } from "./client.js";
2
+ import { t as createClient } from "./client-Bt4tAKi9.js";
3
3
  import { createContext, createElement, useContext, useEffect, useMemo, useSyncExternalStore } from "react";
4
4
  //#region src/react.ts
5
5
  /**
@@ -17,13 +17,14 @@ import { createContext, createElement, useContext, useEffect, useMemo, useSyncEx
17
17
  function createReact(options) {
18
18
  const Context = createContext(null);
19
19
  const providerMounts = /* @__PURE__ */ new WeakMap();
20
- const resolveSession = "client" in options ? (sessionId, _api, initialState, initialIndex, initialEvents) => options.client.session(sessionId, {
20
+ const resolveSession = "client" in options ? (sessionId, _api, initialState, initialIndex, initialEvents, participant) => options.client.session(sessionId, {
21
21
  initialState,
22
22
  initialIndex,
23
- ...initialEvents === void 0 ? {} : { initialEvents }
23
+ ...initialEvents === void 0 ? {} : { initialEvents },
24
+ ...participant === void 0 ? {} : { participant }
24
25
  }) : (() => {
25
26
  const clients = /* @__PURE__ */ new Map();
26
- return (sessionId, api, initialState, initialIndex, initialEvents) => {
27
+ return (sessionId, api, initialState, initialIndex, initialEvents, participant) => {
27
28
  if (api === void 0) throw new TypeError("SessionProvider requires api when createReact binds a reducer");
28
29
  let client = clients.get(api);
29
30
  if (!client) {
@@ -36,19 +37,21 @@ function createReact(options) {
36
37
  return client.session(sessionId, {
37
38
  initialState,
38
39
  initialIndex,
39
- ...initialEvents === void 0 ? {} : { initialEvents }
40
+ ...initialEvents === void 0 ? {} : { initialEvents },
41
+ ...participant === void 0 ? {} : { participant }
40
42
  });
41
43
  };
42
44
  })();
43
45
  function SessionProvider(props) {
44
- const { sessionId, initialState, initialIndex, initialEvents } = props;
46
+ const { sessionId, initialState, initialIndex, initialEvents, participant } = props;
45
47
  const api = "api" in props ? props.api : void 0;
46
- const client = useMemo(() => resolveSession(sessionId, api, initialState, initialIndex, initialEvents), [
48
+ const client = useMemo(() => resolveSession(sessionId, api, initialState, initialIndex, initialEvents, participant), [
47
49
  sessionId,
48
50
  api,
49
51
  initialState,
50
52
  initialIndex,
51
- initialEvents
53
+ initialEvents,
54
+ participant
52
55
  ]);
53
56
  useEffect(() => {
54
57
  const mounts = providerMounts.get(client) ?? 0;
@@ -68,13 +71,21 @@ function createReact(options) {
68
71
  const client = useContext(Context);
69
72
  if (!client) throw new Error("useSession must be rendered inside its matching SessionProvider");
70
73
  const snapshot = useSyncExternalStore(client.subscribe, client.getSnapshot, client.getSnapshot);
71
- return useMemo(() => ({
72
- state: snapshot.state,
73
- events: snapshot.events,
74
- index: snapshot.index,
75
- connection: snapshot.connection,
76
- push: client.push
77
- }), [snapshot, client]);
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
+ ...setPresence && presence ? {
84
+ presence,
85
+ setPresence
86
+ } : {}
87
+ };
88
+ }, [snapshot, client]);
78
89
  }
79
90
  return {
80
91
  SessionProvider,
@@ -0,0 +1,78 @@
1
+ import { i as Clock } from "./store-C3sNAaBT.js";
2
+ import { D as SchedulerTask, t as A2Scheduler } from "./server-YtPq7hjw.js";
3
+ //#region src/scheduler-qstash.d.ts
4
+ type QStashStoreOutage = {
5
+ version: 1;
6
+ /** Zero is the first successor created for a store outage. */
7
+ generation: number;
8
+ /** The first failing drain task's due time. Append identity lives on the task. */
9
+ rootDueAt?: number;
10
+ };
11
+ type QStashMessage = SchedulerTask & {
12
+ /** Provider-private state authenticated as part of QStash's signed body. */
13
+ _a2QStash?: QStashStoreOutage;
14
+ };
15
+ type QStashPublishRequest = {
16
+ url: string;
17
+ body: QStashMessage;
18
+ /** Headers the transport must deliver to the callback. */
19
+ headers?: Readonly<Record<string, string>>;
20
+ /** Header names the transport must redact from provider dashboard/API views. */
21
+ redact?: {
22
+ header: readonly string[];
23
+ };
24
+ /** Whole-second Unix timestamp. Omitted for an immediate delivery. */
25
+ notBefore?: number;
26
+ deduplicationId: string;
27
+ /** Delivery retries after the initial attempt. */
28
+ retries?: number;
29
+ };
30
+ /** The request shape passed to an injected `@upstash/qstash` client. */
31
+ type QStashClientPublishRequest = Omit<QStashPublishRequest, "headers" | "redact"> & {
32
+ headers?: Record<string, string>;
33
+ redact?: {
34
+ header: string[];
35
+ };
36
+ };
37
+ /** The outbound part of `@upstash/qstash` used by the built-in transport. */
38
+ type QStashPublishingClient = {
39
+ publishJSON(request: QStashClientPublishRequest): Promise<unknown>;
40
+ };
41
+ type QStashVerifyRequest = {
42
+ signature: string;
43
+ /** The untouched request body covered by the signature. */
44
+ body: string;
45
+ /** Exact destination URL, checked against the signature subject. */
46
+ url: string;
47
+ upstashRegion?: string;
48
+ };
49
+ /** The small part of `@upstash/qstash` this adapter needs. */
50
+ type QStashTransport = {
51
+ publish(request: QStashPublishRequest): Promise<unknown>;
52
+ verify(request: QStashVerifyRequest): Promise<boolean>;
53
+ };
54
+ type QStashSchedulerOptions = {
55
+ /** Exact URL mounted with `schedulerHandler(...)`. Inferred in local dev and on Vercel. */
56
+ url?: string;
57
+ /** QStash API token. Default: `QSTASH_TOKEN`. */
58
+ token?: string;
59
+ /** QStash signing key. Default: `QSTASH_CURRENT_SIGNING_KEY`. */
60
+ currentSigningKey?: string;
61
+ /** Next QStash signing key. Default: `QSTASH_NEXT_SIGNING_KEY`. */
62
+ nextSigningKey?: string;
63
+ /** Delivery retries after the initial attempt. Default: provider default. */
64
+ retries?: number;
65
+ /** Maximum callback body and outbound task with outage headroom. Default 1 MiB. */
66
+ maxBodyBytes?: number;
67
+ /** Static callback headers. QStash receives them; A2 requests dashboard/API redaction. */
68
+ headers?: Readonly<Record<string, string>>;
69
+ /** Injectable publishing client. The built-in receiver still verifies callbacks. */
70
+ client?: QStashPublishingClient;
71
+ /** Injectable transport (tests). Default: `@upstash/qstash`. */
72
+ transport?: QStashTransport;
73
+ /** Injectable clock for due-time calculations (tests). */
74
+ clock?: Clock;
75
+ };
76
+ declare function qstash(options?: QStashSchedulerOptions): A2Scheduler;
77
+ //#endregion
78
+ export { QStashClientPublishRequest, QStashPublishRequest, QStashPublishingClient, QStashSchedulerOptions, QStashTransport, QStashVerifyRequest, qstash };