experimental-a2 0.9.0 → 0.11.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 +53 -0
- package/dist/actor-D_54lz_1.d.ts +310 -0
- package/dist/actor-D_54lz_1.d.ts.map +1 -0
- package/dist/actor-client.d.ts +13 -4
- package/dist/actor-client.d.ts.map +1 -1
- package/dist/actor-client.js +63 -7
- package/dist/actor-client.js.map +1 -1
- package/dist/actor-react.d.ts +5 -4
- package/dist/actor-react.d.ts.map +1 -1
- package/dist/actor-react.js +16 -2
- package/dist/actor-react.js.map +1 -1
- package/dist/actor.d.ts +2 -176
- package/dist/actor.js +13 -2
- package/dist/actor.js.map +1 -1
- package/dist/ai-server.d.ts +1 -1
- package/dist/ai-server.js +2 -2
- package/dist/ai.d.ts +1 -1
- package/dist/ai.js +1 -1
- package/dist/client-Bf6uSEAk.js +1342 -0
- package/dist/client-Bf6uSEAk.js.map +1 -0
- package/dist/client-P_NNNRM-.d.ts +243 -0
- package/dist/client-P_NNNRM-.d.ts.map +1 -0
- package/dist/client.d.ts +2 -202
- package/dist/client.js +2 -1026
- package/dist/errors-DCk6ch5n.js.map +1 -1
- package/dist/errors-DvhSXnxk.d.ts +28 -0
- package/dist/errors-DvhSXnxk.d.ts.map +1 -0
- package/dist/index.d.ts +3 -35
- package/dist/{internal-DRXJ56EI.js → internal-Dq2qYxou.js} +2 -2
- package/dist/{internal-DRXJ56EI.js.map → internal-Dq2qYxou.js.map} +1 -1
- package/dist/platform-B4TnJtWu.js +34 -0
- package/dist/platform-B4TnJtWu.js.map +1 -0
- package/dist/react.d.ts +3 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +2 -1
- package/dist/react.js.map +1 -1
- package/dist/scheduler-qstash.d.ts +2 -2
- package/dist/scheduler-qstash.js +3 -2
- package/dist/scheduler-qstash.js.map +1 -1
- package/dist/scheduler-vercel.d.ts +2 -2
- package/dist/scheduler-vercel.js +2 -2
- package/dist/{server-CBET-jSz.js → server-Dkz2a84E.js} +295 -133
- package/dist/server-Dkz2a84E.js.map +1 -0
- package/dist/{server-CKY3_lbw.d.ts → server-DwPrMqHB.d.ts} +4 -2
- package/dist/server-DwPrMqHB.d.ts.map +1 -0
- package/dist/server.d.ts +2 -2
- package/dist/server.js +1 -1
- package/dist/{store-DGHeBtIQ.d.ts → store-DtDOWLSn.d.ts} +4 -5
- package/dist/{store-DGHeBtIQ.d.ts.map → store-DtDOWLSn.d.ts.map} +1 -1
- package/dist/store-N8PXxDAS.js.map +1 -1
- package/dist/store-memory.d.ts +1 -1
- package/dist/store-memory.js +1 -1
- package/dist/{store-polling-6DW7F1DT.js → store-polling-CmxUbV93.js} +56 -7
- package/dist/store-polling-CmxUbV93.js.map +1 -0
- package/dist/store-postgres.d.ts +6 -4
- package/dist/store-postgres.d.ts.map +1 -1
- package/dist/store-postgres.js +701 -53
- package/dist/store-postgres.js.map +1 -1
- package/dist/store-presence-polling-C7-XZyW9.js +94 -0
- package/dist/store-presence-polling-C7-XZyW9.js.map +1 -0
- package/dist/store-redis-http.d.ts +2 -2
- package/dist/store-redis-http.d.ts.map +1 -1
- package/dist/store-redis-http.js +184 -38
- package/dist/store-redis-http.js.map +1 -1
- package/dist/{store-redis-core-z-ykbyMg.js → store-redis-notify-BUCyXOn0.js} +491 -27
- package/dist/store-redis-notify-BUCyXOn0.js.map +1 -0
- package/dist/store-redis.d.ts +5 -13
- package/dist/store-redis.d.ts.map +1 -1
- package/dist/store-redis.js +27 -271
- package/dist/store-redis.js.map +1 -1
- package/dist/store-sqlite.d.ts +1 -1
- package/dist/store-sqlite.js +1 -1
- package/dist/{wire--yji6mO3.js → wire-BO5wWCb1.js} +18 -16
- package/dist/wire-BO5wWCb1.js.map +1 -0
- package/docs/actors/04-routes.mdx +40 -8
- package/docs/guides/03-react.mdx +52 -10
- package/docs/guides/05-production.mdx +54 -5
- package/docs/guides/09-presence.mdx +12 -7
- package/docs/guides/10-transports.mdx +85 -22
- package/docs/reference/01-api.mdx +90 -28
- package/docs/reference/02-errors.mdx +45 -11
- package/examples/playground/package.json +1 -1
- package/package.json +1 -1
- package/src/actor-client.ts +114 -14
- package/src/actor-react.ts +18 -3
- package/src/actor.ts +16 -1
- package/src/client-errors.ts +51 -0
- package/src/client.ts +577 -175
- package/src/errors.ts +4 -9
- package/src/index.ts +1 -1
- package/src/internal.ts +1 -1
- package/src/postgres-notification-scope.ts +134 -0
- package/src/postgres-notifications.ts +244 -0
- package/src/postgres-pool.ts +65 -0
- package/src/postgres-resources.ts +185 -0
- package/src/presence-recovery.ts +120 -0
- package/src/react.ts +3 -0
- package/src/redis-http-subscriptions.ts +199 -0
- package/src/server-fetch.ts +51 -23
- package/src/server.ts +146 -19
- package/src/session-socket.ts +241 -88
- package/src/sse.ts +17 -0
- package/src/store-polling.ts +32 -12
- package/src/store-postgres.ts +292 -75
- package/src/store-presence-polling.ts +125 -0
- package/src/store-redis-core.ts +37 -30
- package/src/store-redis-http.ts +51 -45
- package/src/store-redis-notify.ts +464 -0
- package/src/store-redis.ts +9 -364
- package/src/store.ts +3 -4
- package/src/stream-activity.ts +32 -0
- package/src/wire.ts +39 -15
- package/dist/actor-shared-BACubf4x.d.ts +0 -136
- package/dist/actor-shared-BACubf4x.d.ts.map +0 -1
- package/dist/actor.d.ts.map +0 -1
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/server-CBET-jSz.js.map +0 -1
- package/dist/server-CKY3_lbw.d.ts.map +0 -1
- package/dist/store-polling-6DW7F1DT.js.map +0 -1
- package/dist/store-redis-core-z-ykbyMg.js.map +0 -1
- package/dist/wire--yji6mO3.js.map +0 -1
package/src/actor-react.ts
CHANGED
|
@@ -41,6 +41,7 @@ import type { A2Client, Connection } from './client.ts'
|
|
|
41
41
|
import type { ContractEvent, EventDefs, PresenceDefs } from './contract.ts'
|
|
42
42
|
import type { Reducer } from './reducer.ts'
|
|
43
43
|
import { useSession } from './react.ts'
|
|
44
|
+
import { useMemo } from 'react'
|
|
44
45
|
|
|
45
46
|
/** The server-to-client handoff: `await def.actor(id).state()`. */
|
|
46
47
|
export type ActorSnapshot<S> = { state: S; index: number }
|
|
@@ -66,13 +67,14 @@ type PresenceOf<D extends AnyActorDefinition> = D extends {
|
|
|
66
67
|
: never
|
|
67
68
|
|
|
68
69
|
export type UseActorResult<D extends AnyActorDefinition, View> = {
|
|
69
|
-
/** The
|
|
70
|
+
/** The live view, advanced by call answers, refreshes, and stream commits. */
|
|
70
71
|
state: View
|
|
71
|
-
/** The
|
|
72
|
+
/** The latest adopted state index. */
|
|
72
73
|
index: number
|
|
73
74
|
connection: Connection
|
|
74
75
|
/** Typed calls over POST — the response is the answer. */
|
|
75
76
|
call: ActorClientCall<D, View>
|
|
77
|
+
refresh: () => Promise<ActorSnapshot<View>>
|
|
76
78
|
/** The state-commit feed this browser has observed. */
|
|
77
79
|
events: ContractEvent<EventDefs>[]
|
|
78
80
|
/**
|
|
@@ -128,12 +130,25 @@ export function useActor<D extends AnyActorDefinition, View = ActorStateOf<D>>(
|
|
|
128
130
|
? {}
|
|
129
131
|
: { participant: options.participant }),
|
|
130
132
|
})
|
|
131
|
-
const { call } =
|
|
133
|
+
const { call, state: refresh } = useMemo(
|
|
134
|
+
() =>
|
|
135
|
+
createActorClient<D, View>({
|
|
136
|
+
api,
|
|
137
|
+
onSnapshot: ({ state, index }) => {
|
|
138
|
+
client.session(options.id, {
|
|
139
|
+
initialState: state,
|
|
140
|
+
initialIndex: index,
|
|
141
|
+
})
|
|
142
|
+
},
|
|
143
|
+
}),
|
|
144
|
+
[api, client, options.id],
|
|
145
|
+
)
|
|
132
146
|
return {
|
|
133
147
|
state: session.state as View,
|
|
134
148
|
index: session.index,
|
|
135
149
|
connection: session.connection,
|
|
136
150
|
call,
|
|
151
|
+
refresh,
|
|
137
152
|
events: session.events,
|
|
138
153
|
presence: session.presence as ActorPresenceMap<PresenceOf<D>>,
|
|
139
154
|
setPresence: session.setPresence as (
|
package/src/actor.ts
CHANGED
|
@@ -169,9 +169,10 @@ export type ActorOptions<D extends ActorProtocol> = {
|
|
|
169
169
|
/**
|
|
170
170
|
* One HTTP operation `handle.fetch` is about to serve — the actor
|
|
171
171
|
* mirror of core's `A2Operation`. `authorize` sees it before any
|
|
172
|
-
* write or subscription; returning `false` answers 403.
|
|
172
|
+
* read, write, or subscription; returning `false` answers 403.
|
|
173
173
|
*/
|
|
174
174
|
export type ActorOperation =
|
|
175
|
+
| { readonly type: 'state'; readonly id: string }
|
|
175
176
|
| {
|
|
176
177
|
readonly type: 'stream'
|
|
177
178
|
readonly id: string
|
|
@@ -736,6 +737,19 @@ export function actor<D extends ActorProtocol>(
|
|
|
736
737
|
|
|
737
738
|
if (request.method === 'GET') {
|
|
738
739
|
const url = new URL(request.url)
|
|
740
|
+
if (url.searchParams.has('snapshot')) {
|
|
741
|
+
if (!(await authorized({ type: 'state', id }))) return forbidden()
|
|
742
|
+
const result = await readState()
|
|
743
|
+
return Response.json(
|
|
744
|
+
{
|
|
745
|
+
state: fetchOptions?.view
|
|
746
|
+
? applyView(fetchOptions.view, result.state)
|
|
747
|
+
: result.state,
|
|
748
|
+
index: result.index,
|
|
749
|
+
},
|
|
750
|
+
{ headers: { 'cache-control': 'private, no-store' } },
|
|
751
|
+
)
|
|
752
|
+
}
|
|
739
753
|
const raw = Number(url.searchParams.get('index'))
|
|
740
754
|
const startAfter = Number.isSafeInteger(raw) && raw >= 0 ? raw : 0
|
|
741
755
|
if (!(await authorized({ type: 'stream', id, startAfter }))) {
|
|
@@ -851,6 +865,7 @@ export function actor<D extends ActorProtocol>(
|
|
|
851
865
|
index: result.index,
|
|
852
866
|
}
|
|
853
867
|
: result,
|
|
868
|
+
{ headers: { 'cache-control': 'private, no-store' } },
|
|
854
869
|
)
|
|
855
870
|
} catch (error) {
|
|
856
871
|
if (error instanceof ActorRefusedError) {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { A2Error, type A2ErrorCode } from './errors.ts'
|
|
2
|
+
|
|
3
|
+
export type A2ClientErrorOptions = {
|
|
4
|
+
details?: unknown
|
|
5
|
+
cause?: unknown
|
|
6
|
+
status?: number
|
|
7
|
+
closeCode?: number
|
|
8
|
+
closeReason?: string
|
|
9
|
+
phase?: 'stream' | 'subscribe'
|
|
10
|
+
timeoutMs?: number
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class A2ClientError extends A2Error {
|
|
14
|
+
readonly status: number | undefined
|
|
15
|
+
readonly closeCode: number | undefined
|
|
16
|
+
readonly closeReason: string | undefined
|
|
17
|
+
readonly phase: 'stream' | 'subscribe' | undefined
|
|
18
|
+
readonly timeoutMs: number | undefined
|
|
19
|
+
|
|
20
|
+
constructor(
|
|
21
|
+
code: A2ErrorCode,
|
|
22
|
+
message: string,
|
|
23
|
+
options?: A2ClientErrorOptions,
|
|
24
|
+
) {
|
|
25
|
+
super(code, message, options)
|
|
26
|
+
this.name = 'A2ClientError'
|
|
27
|
+
this.status = options?.status
|
|
28
|
+
this.closeCode = options?.closeCode
|
|
29
|
+
this.closeReason = options?.closeReason
|
|
30
|
+
this.phase = options?.phase
|
|
31
|
+
this.timeoutMs = options?.timeoutMs
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function asClientError(
|
|
36
|
+
error: unknown,
|
|
37
|
+
options?: { code?: A2ErrorCode },
|
|
38
|
+
): A2ClientError {
|
|
39
|
+
if (error instanceof A2ClientError) return error
|
|
40
|
+
if (error instanceof A2Error) {
|
|
41
|
+
return new A2ClientError(error.code, error.message, {
|
|
42
|
+
details: error.details,
|
|
43
|
+
cause: error,
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
return new A2ClientError(
|
|
47
|
+
options?.code ?? 'UNKNOWN',
|
|
48
|
+
error instanceof Error ? error.message : 'client operation failed',
|
|
49
|
+
{ cause: error },
|
|
50
|
+
)
|
|
51
|
+
}
|