@livestore/sync-cf 0.4.0-dev.9 → 0.5.0-dev.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/README.md +7 -8
- package/dist/.tsbuildinfo +1 -1
- package/dist/cf-worker/do/durable-object.d.ts +1 -1
- package/dist/cf-worker/do/durable-object.d.ts.map +1 -1
- package/dist/cf-worker/do/durable-object.js +36 -18
- package/dist/cf-worker/do/durable-object.js.map +1 -1
- package/dist/cf-worker/do/layer.d.ts +24 -20
- package/dist/cf-worker/do/layer.d.ts.map +1 -1
- package/dist/cf-worker/do/layer.js +57 -24
- package/dist/cf-worker/do/layer.js.map +1 -1
- package/dist/cf-worker/do/pull.d.ts +8 -3
- package/dist/cf-worker/do/pull.d.ts.map +1 -1
- package/dist/cf-worker/do/pull.js +26 -21
- package/dist/cf-worker/do/pull.js.map +1 -1
- package/dist/cf-worker/do/push.d.ts +20 -6
- package/dist/cf-worker/do/push.d.ts.map +1 -1
- package/dist/cf-worker/do/push.js +84 -56
- package/dist/cf-worker/do/push.js.map +1 -1
- package/dist/cf-worker/do/push.test.d.ts +2 -0
- package/dist/cf-worker/do/push.test.d.ts.map +1 -0
- package/dist/cf-worker/do/push.test.js +30 -0
- package/dist/cf-worker/do/push.test.js.map +1 -0
- package/dist/cf-worker/do/sqlite.d.ts +49 -52
- package/dist/cf-worker/do/sqlite.d.ts.map +1 -1
- package/dist/cf-worker/do/sqlite.js +14 -5
- package/dist/cf-worker/do/sqlite.js.map +1 -1
- package/dist/cf-worker/do/sync-storage.d.ts +15 -9
- package/dist/cf-worker/do/sync-storage.d.ts.map +1 -1
- package/dist/cf-worker/do/sync-storage.js +111 -25
- package/dist/cf-worker/do/sync-storage.js.map +1 -1
- package/dist/cf-worker/do/transport/do-rpc-server.d.ts +2 -2
- package/dist/cf-worker/do/transport/do-rpc-server.d.ts.map +1 -1
- package/dist/cf-worker/do/transport/do-rpc-server.js +31 -23
- package/dist/cf-worker/do/transport/do-rpc-server.js.map +1 -1
- package/dist/cf-worker/do/transport/http-rpc-server.d.ts +5 -3
- package/dist/cf-worker/do/transport/http-rpc-server.d.ts.map +1 -1
- package/dist/cf-worker/do/transport/http-rpc-server.js +28 -19
- package/dist/cf-worker/do/transport/http-rpc-server.js.map +1 -1
- package/dist/cf-worker/do/transport/ws-rpc-server.d.ts +3 -2
- package/dist/cf-worker/do/transport/ws-rpc-server.d.ts.map +1 -1
- package/dist/cf-worker/do/transport/ws-rpc-server.js +32 -10
- package/dist/cf-worker/do/transport/ws-rpc-server.js.map +1 -1
- package/dist/cf-worker/shared.d.ts +124 -34
- package/dist/cf-worker/shared.d.ts.map +1 -1
- package/dist/cf-worker/shared.js +52 -17
- package/dist/cf-worker/shared.js.map +1 -1
- package/dist/cf-worker/worker.d.ts +47 -39
- package/dist/cf-worker/worker.d.ts.map +1 -1
- package/dist/cf-worker/worker.js +54 -35
- package/dist/cf-worker/worker.js.map +1 -1
- package/dist/client/transport/do-rpc-client.d.ts +13 -4
- package/dist/client/transport/do-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/do-rpc-client.js +74 -28
- package/dist/client/transport/do-rpc-client.js.map +1 -1
- package/dist/client/transport/http-rpc-client.d.ts +3 -3
- package/dist/client/transport/http-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/http-rpc-client.js +51 -22
- package/dist/client/transport/http-rpc-client.js.map +1 -1
- package/dist/client/transport/ws-rpc-client.d.ts +4 -3
- package/dist/client/transport/ws-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/ws-rpc-client.js +40 -22
- package/dist/client/transport/ws-rpc-client.js.map +1 -1
- package/dist/common/constants.d.ts +7 -0
- package/dist/common/constants.d.ts.map +1 -0
- package/dist/common/constants.js +17 -0
- package/dist/common/constants.js.map +1 -0
- package/dist/common/do-rpc-schema.d.ts +42 -43
- package/dist/common/do-rpc-schema.d.ts.map +1 -1
- package/dist/common/do-rpc-schema.js +5 -5
- package/dist/common/do-rpc-schema.js.map +1 -1
- package/dist/common/http-rpc-schema.d.ts +37 -38
- package/dist/common/http-rpc-schema.d.ts.map +1 -1
- package/dist/common/http-rpc-schema.js +7 -7
- package/dist/common/http-rpc-schema.js.map +1 -1
- package/dist/common/mod.d.ts +5 -3
- package/dist/common/mod.d.ts.map +1 -1
- package/dist/common/mod.js +4 -2
- package/dist/common/mod.js.map +1 -1
- package/dist/common/sync-message-types.d.ts +113 -130
- package/dist/common/sync-message-types.d.ts.map +1 -1
- package/dist/common/sync-message-types.js +29 -17
- package/dist/common/sync-message-types.js.map +1 -1
- package/dist/common/ws-rpc-schema.d.ts +34 -35
- package/dist/common/ws-rpc-schema.d.ts.map +1 -1
- package/dist/common/ws-rpc-schema.js +5 -5
- package/dist/common/ws-rpc-schema.js.map +1 -1
- package/package.json +57 -15
- package/src/cf-worker/do/durable-object.ts +59 -41
- package/src/cf-worker/do/layer.ts +153 -88
- package/src/cf-worker/do/pull.ts +48 -31
- package/src/cf-worker/do/push.test.ts +40 -0
- package/src/cf-worker/do/push.ts +163 -125
- package/src/cf-worker/do/sqlite.ts +15 -5
- package/src/cf-worker/do/sync-storage.ts +171 -38
- package/src/cf-worker/do/transport/do-rpc-server.ts +40 -40
- package/src/cf-worker/do/transport/http-rpc-server.ts +37 -20
- package/src/cf-worker/do/transport/ws-rpc-server.ts +44 -16
- package/src/cf-worker/shared.ts +152 -36
- package/src/cf-worker/worker.ts +110 -58
- package/src/client/transport/do-rpc-client.ts +106 -40
- package/src/client/transport/http-rpc-client.ts +74 -38
- package/src/client/transport/ws-rpc-client.ts +55 -29
- package/src/common/constants.ts +18 -0
- package/src/common/do-rpc-schema.ts +6 -5
- package/src/common/http-rpc-schema.ts +8 -7
- package/src/common/mod.ts +4 -3
- package/src/common/sync-message-types.ts +19 -19
- package/src/common/ws-rpc-schema.ts +6 -5
- package/dist/cf-worker/do/ws-chunking.d.ts +0 -22
- package/dist/cf-worker/do/ws-chunking.d.ts.map +0 -1
- package/dist/cf-worker/do/ws-chunking.js +0 -49
- package/dist/cf-worker/do/ws-chunking.js.map +0 -1
- package/src/cf-worker/do/ws-chunking.ts +0 -76
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BackendIdMismatchError, ServerAheadError, UnknownError } from '@livestore/common'
|
|
2
2
|
import { Rpc, RpcGroup, Schema } from '@livestore/utils/effect'
|
|
3
|
+
|
|
3
4
|
import * as SyncMessage from './sync-message-types.ts'
|
|
4
5
|
|
|
5
6
|
const commonPayloadFields = {
|
|
6
7
|
/**
|
|
7
|
-
* While the storeId is already implied by the
|
|
8
|
+
* While the storeId is already implied by the Durable Object, we still need the explicit storeId
|
|
8
9
|
* since a DO doesn't know its own id.name value. 🫠
|
|
9
10
|
* https://community.cloudflare.com/t/how-can-i-get-the-name-of-a-durable-object-from-itself/505961/8
|
|
10
11
|
*/
|
|
11
12
|
storeId: Schema.String,
|
|
12
13
|
/** Needed for various reasons (e.g. auth) */
|
|
13
|
-
payload: Schema.optional(Schema.
|
|
14
|
+
payload: Schema.optional(Schema.Json),
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export class SyncDoRpc extends RpcGroup.make(
|
|
@@ -34,7 +35,7 @@ export class SyncDoRpc extends RpcGroup.make(
|
|
|
34
35
|
rpcRequestId: Schema.String,
|
|
35
36
|
...SyncMessage.PullResponse.fields,
|
|
36
37
|
}),
|
|
37
|
-
error:
|
|
38
|
+
error: Schema.Union([UnknownError, BackendIdMismatchError]),
|
|
38
39
|
stream: true,
|
|
39
40
|
}),
|
|
40
41
|
Rpc.make('SyncDoRpc.Push', {
|
|
@@ -43,7 +44,7 @@ export class SyncDoRpc extends RpcGroup.make(
|
|
|
43
44
|
...commonPayloadFields,
|
|
44
45
|
},
|
|
45
46
|
success: SyncMessage.PushAck,
|
|
46
|
-
error:
|
|
47
|
+
error: Schema.Union([UnknownError, ServerAheadError, BackendIdMismatchError]),
|
|
47
48
|
}),
|
|
48
49
|
Rpc.make('SyncDoRpc.Ping', {
|
|
49
50
|
payload: {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BackendIdMismatchError, ServerAheadError, UnknownError } from '@livestore/common'
|
|
2
2
|
import { Rpc, RpcGroup, Schema } from '@livestore/utils/effect'
|
|
3
|
+
|
|
3
4
|
import * as SyncMessage from './sync-message-types.ts'
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -13,28 +14,28 @@ export class SyncHttpRpc extends RpcGroup.make(
|
|
|
13
14
|
Rpc.make('SyncHttpRpc.Pull', {
|
|
14
15
|
payload: Schema.Struct({
|
|
15
16
|
storeId: Schema.String,
|
|
16
|
-
payload: Schema.optional(Schema.
|
|
17
|
+
payload: Schema.optional(Schema.Json),
|
|
17
18
|
...SyncMessage.PullRequest.fields,
|
|
18
19
|
}),
|
|
19
20
|
success: SyncMessage.PullResponse,
|
|
20
|
-
error:
|
|
21
|
+
error: Schema.Union([UnknownError, BackendIdMismatchError]),
|
|
21
22
|
stream: true,
|
|
22
23
|
}),
|
|
23
24
|
Rpc.make('SyncHttpRpc.Push', {
|
|
24
25
|
payload: Schema.Struct({
|
|
25
26
|
storeId: Schema.String,
|
|
26
|
-
payload: Schema.optional(Schema.
|
|
27
|
+
payload: Schema.optional(Schema.Json),
|
|
27
28
|
...SyncMessage.PushRequest.fields,
|
|
28
29
|
}),
|
|
29
30
|
success: SyncMessage.PushAck,
|
|
30
|
-
error:
|
|
31
|
+
error: Schema.Union([UnknownError, ServerAheadError, BackendIdMismatchError]),
|
|
31
32
|
}),
|
|
32
33
|
Rpc.make('SyncHttpRpc.Ping', {
|
|
33
34
|
payload: Schema.Struct({
|
|
34
35
|
storeId: Schema.String,
|
|
35
|
-
payload: Schema.optional(Schema.
|
|
36
|
+
payload: Schema.optional(Schema.Json),
|
|
36
37
|
}),
|
|
37
38
|
success: SyncMessage.Pong,
|
|
38
|
-
error:
|
|
39
|
+
error: UnknownError,
|
|
39
40
|
}),
|
|
40
41
|
) {}
|
package/src/common/mod.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
export { OversizeChunkItemError, splitArrayBySize } from '@livestore/common/sync'
|
|
1
2
|
import { Schema } from '@livestore/utils/effect'
|
|
2
3
|
|
|
3
4
|
export type { CfTypes } from '@livestore/common-cf'
|
|
4
|
-
|
|
5
|
+
export * from './constants.ts'
|
|
5
6
|
export { SyncHttpRpc } from './http-rpc-schema.ts'
|
|
6
7
|
export * as SyncMessage from './sync-message-types.ts'
|
|
7
8
|
|
|
8
9
|
export const SearchParamsSchema = Schema.Struct({
|
|
9
10
|
storeId: Schema.String,
|
|
10
|
-
payload: Schema.
|
|
11
|
+
payload: Schema.optional(Schema.StringFromUriComponent.pipe(Schema.decodeTo(Schema.fromJsonString(Schema.Json)))),
|
|
11
12
|
// NOTE `do-rpc` is handled differently
|
|
12
|
-
transport: Schema.
|
|
13
|
+
transport: Schema.Literals(['http', 'ws']),
|
|
13
14
|
})
|
|
14
15
|
|
|
15
16
|
export type SearchParams = typeof SearchParamsSchema.Type
|
|
@@ -11,7 +11,7 @@ import { Schema } from '@livestore/utils/effect'
|
|
|
11
11
|
export const SyncMetadata = Schema.TaggedStruct('SyncMessage.SyncMetadata', {
|
|
12
12
|
/** ISO date format */
|
|
13
13
|
createdAt: Schema.String,
|
|
14
|
-
}).
|
|
14
|
+
}).annotate({ title: '@livestore/sync-cf:SyncMetadata' })
|
|
15
15
|
|
|
16
16
|
export type SyncMetadata = typeof SyncMetadata.Type
|
|
17
17
|
|
|
@@ -20,23 +20,23 @@ export const PullRequest = Schema.Struct({
|
|
|
20
20
|
cursor: Schema.Option(
|
|
21
21
|
Schema.Struct({
|
|
22
22
|
backendId: BackendId,
|
|
23
|
-
eventSequenceNumber: EventSequenceNumber.
|
|
23
|
+
eventSequenceNumber: EventSequenceNumber.Global.Schema,
|
|
24
24
|
}),
|
|
25
25
|
),
|
|
26
|
-
}).
|
|
26
|
+
}).annotate({ title: '@livestore/sync-cf:PullRequest' })
|
|
27
27
|
|
|
28
28
|
export type PullRequest = typeof PullRequest.Type
|
|
29
29
|
|
|
30
30
|
export const PullResponse = Schema.Struct({
|
|
31
31
|
batch: Schema.Array(
|
|
32
32
|
Schema.Struct({
|
|
33
|
-
eventEncoded: LiveStoreEvent.
|
|
33
|
+
eventEncoded: LiveStoreEvent.Global.Encoded,
|
|
34
34
|
metadata: Schema.Option(SyncMetadata),
|
|
35
35
|
}),
|
|
36
36
|
),
|
|
37
37
|
pageInfo: SyncBackend.PullResPageInfo,
|
|
38
38
|
backendId: BackendId,
|
|
39
|
-
}).
|
|
39
|
+
}).annotate({ title: '@livestore/sync-cf:PullResponse' })
|
|
40
40
|
|
|
41
41
|
export const emptyPullResponse = (backendId: string) =>
|
|
42
42
|
PullResponse.make({
|
|
@@ -48,34 +48,34 @@ export const emptyPullResponse = (backendId: string) =>
|
|
|
48
48
|
export type PullResponse = typeof PullResponse.Type
|
|
49
49
|
|
|
50
50
|
export const PushRequest = Schema.Struct({
|
|
51
|
-
batch: Schema.Array(LiveStoreEvent.
|
|
51
|
+
batch: Schema.Array(LiveStoreEvent.Global.Encoded),
|
|
52
52
|
backendId: Schema.Option(BackendId),
|
|
53
|
-
}).
|
|
53
|
+
}).annotate({ title: '@livestore/sync-cf:PushRequest' })
|
|
54
54
|
|
|
55
55
|
export type PushRequest = typeof PushRequest.Type
|
|
56
56
|
|
|
57
|
-
export const PushAck = Schema.Struct({}).
|
|
57
|
+
export const PushAck = Schema.Struct({}).annotate({
|
|
58
58
|
title: '@livestore/sync-cf:PushAck',
|
|
59
59
|
})
|
|
60
60
|
|
|
61
61
|
export type PushAck = typeof PushAck.Type
|
|
62
62
|
|
|
63
|
-
export const Ping = Schema.TaggedStruct('SyncMessage.Ping', {}).
|
|
63
|
+
export const Ping = Schema.TaggedStruct('SyncMessage.Ping', {}).annotate({ title: '@livestore/sync-cf:Ping' })
|
|
64
64
|
|
|
65
65
|
export type Ping = typeof Ping.Type
|
|
66
66
|
|
|
67
|
-
export const Pong = Schema.TaggedStruct('SyncMessage.Pong', {}).
|
|
67
|
+
export const Pong = Schema.TaggedStruct('SyncMessage.Pong', {}).annotate({ title: '@livestore/sync-cf:Pong' })
|
|
68
68
|
|
|
69
69
|
export type Pong = typeof Pong.Type
|
|
70
70
|
|
|
71
71
|
// Admin operations
|
|
72
72
|
export const AdminResetRoomRequest = Schema.TaggedStruct('SyncMessage.AdminResetRoomRequest', {
|
|
73
73
|
adminSecret: Schema.String,
|
|
74
|
-
}).
|
|
74
|
+
}).annotate({ title: '@livestore/sync-cf:AdminResetRoomRequest' })
|
|
75
75
|
|
|
76
76
|
export type AdminResetRoomRequest = typeof AdminResetRoomRequest.Type
|
|
77
77
|
|
|
78
|
-
export const AdminResetRoomResponse = Schema.TaggedStruct('SyncMessage.AdminResetRoomResponse', {}).
|
|
78
|
+
export const AdminResetRoomResponse = Schema.TaggedStruct('SyncMessage.AdminResetRoomResponse', {}).annotate({
|
|
79
79
|
title: '@livestore/sync-cf:AdminResetRoomResponse',
|
|
80
80
|
})
|
|
81
81
|
|
|
@@ -83,7 +83,7 @@ export type AdminResetRoomResponse = typeof AdminResetRoomResponse.Type
|
|
|
83
83
|
|
|
84
84
|
export const AdminInfoRequest = Schema.TaggedStruct('SyncMessage.AdminInfoRequest', {
|
|
85
85
|
adminSecret: Schema.String,
|
|
86
|
-
}).
|
|
86
|
+
}).annotate({ title: '@livestore/sync-cf:AdminInfoRequest' })
|
|
87
87
|
|
|
88
88
|
export type AdminInfoRequest = typeof AdminInfoRequest.Type
|
|
89
89
|
|
|
@@ -91,27 +91,27 @@ export const AdminInfoResponse = Schema.TaggedStruct('SyncMessage.AdminInfoRespo
|
|
|
91
91
|
info: Schema.Struct({
|
|
92
92
|
durableObjectId: Schema.String,
|
|
93
93
|
}),
|
|
94
|
-
}).
|
|
94
|
+
}).annotate({ title: '@livestore/sync-cf:AdminInfoResponse' })
|
|
95
95
|
|
|
96
96
|
export type AdminInfoResponse = typeof AdminInfoResponse.Type
|
|
97
97
|
|
|
98
|
-
export const BackendToClientMessage = Schema.Union(
|
|
98
|
+
export const BackendToClientMessage = Schema.Union([
|
|
99
99
|
PullResponse,
|
|
100
100
|
PushAck,
|
|
101
101
|
Pong,
|
|
102
102
|
AdminResetRoomResponse,
|
|
103
103
|
AdminInfoResponse,
|
|
104
|
-
)
|
|
104
|
+
])
|
|
105
105
|
export type BackendToClientMessage = typeof BackendToClientMessage.Type
|
|
106
106
|
|
|
107
|
-
export const ClientToBackendMessage = Schema.Union(
|
|
107
|
+
export const ClientToBackendMessage = Schema.Union([
|
|
108
108
|
PullRequest,
|
|
109
109
|
PushRequest,
|
|
110
110
|
Ping,
|
|
111
111
|
AdminResetRoomRequest,
|
|
112
112
|
AdminInfoRequest,
|
|
113
|
-
)
|
|
113
|
+
])
|
|
114
114
|
export type ClientToBackendMessage = typeof ClientToBackendMessage.Type
|
|
115
115
|
|
|
116
|
-
export const Message = Schema.Union(BackendToClientMessage, ClientToBackendMessage)
|
|
116
|
+
export const Message = Schema.Union([BackendToClientMessage, ClientToBackendMessage])
|
|
117
117
|
export type Message = typeof Message.Type
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BackendIdMismatchError, ServerAheadError, UnknownError } from '@livestore/common'
|
|
2
2
|
import { Rpc, RpcGroup, Schema } from '@livestore/utils/effect'
|
|
3
|
+
|
|
3
4
|
import * as SyncMessage from './sync-message-types.ts'
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -13,23 +14,23 @@ export class SyncWsRpc extends RpcGroup.make(
|
|
|
13
14
|
Rpc.make('SyncWsRpc.Pull', {
|
|
14
15
|
payload: Schema.Struct({
|
|
15
16
|
storeId: Schema.String,
|
|
16
|
-
payload: Schema.optional(Schema.
|
|
17
|
+
payload: Schema.optional(Schema.Json),
|
|
17
18
|
/** Whether to keep the pull stream alive and wait for more events */
|
|
18
19
|
live: Schema.Boolean,
|
|
19
20
|
...SyncMessage.PullRequest.fields,
|
|
20
21
|
}),
|
|
21
22
|
success: SyncMessage.PullResponse,
|
|
22
|
-
error:
|
|
23
|
+
error: Schema.Union([UnknownError, BackendIdMismatchError]),
|
|
23
24
|
stream: true,
|
|
24
25
|
}),
|
|
25
26
|
Rpc.make('SyncWsRpc.Push', {
|
|
26
27
|
payload: Schema.Struct({
|
|
27
28
|
storeId: Schema.String,
|
|
28
|
-
payload: Schema.optional(Schema.
|
|
29
|
+
payload: Schema.optional(Schema.Json),
|
|
29
30
|
...SyncMessage.PushRequest.fields,
|
|
30
31
|
}),
|
|
31
32
|
success: SyncMessage.PushAck,
|
|
32
|
-
error:
|
|
33
|
+
error: Schema.Union([UnknownError, ServerAheadError, BackendIdMismatchError]),
|
|
33
34
|
}),
|
|
34
35
|
// Ping <> Pong is handled by DO WS auto-response
|
|
35
36
|
// TODO add admin RPCs
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { Chunk } from '@livestore/utils/effect';
|
|
2
|
-
/**
|
|
3
|
-
* Configuration describing how to break a chunk into smaller payload-safe chunks.
|
|
4
|
-
*/
|
|
5
|
-
export interface ChunkingOptions<A> {
|
|
6
|
-
/** Maximum number of items that may appear in any emitted chunk. */
|
|
7
|
-
readonly maxItems: number;
|
|
8
|
-
/** Maximum encoded byte size allowed for any emitted chunk. */
|
|
9
|
-
readonly maxBytes: number;
|
|
10
|
-
/**
|
|
11
|
-
* Callback that produces a JSON-serialisable structure whose byte size should
|
|
12
|
-
* fit within {@link maxBytes}. This lets callers control framing overhead.
|
|
13
|
-
*/
|
|
14
|
-
readonly encode: (items: ReadonlyArray<A>) => unknown;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Derives a function that splits an input chunk into sub-chunks confined by
|
|
18
|
-
* both item count and encoded byte size limits. Designed for transports with
|
|
19
|
-
* strict frame caps (e.g. Cloudflare hibernated WebSockets).
|
|
20
|
-
*/
|
|
21
|
-
export declare const splitChunkBySize: <A>(options: ChunkingOptions<A>) => (chunk: Chunk.Chunk<A>) => Chunk.Chunk<Chunk.Chunk<A>>;
|
|
22
|
-
//# sourceMappingURL=ws-chunking.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ws-chunking.d.ts","sourceRoot":"","sources":["../../../src/cf-worker/do/ws-chunking.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AAI/C;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,OAAO,CAAA;CACtD;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAC1B,CAAC,EAAE,SAAS,eAAe,CAAC,CAAC,CAAC,MAC9B,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAiDlD,CAAA"}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { Chunk } from '@livestore/utils/effect';
|
|
2
|
-
const textEncoder = new TextEncoder();
|
|
3
|
-
/**
|
|
4
|
-
* Derives a function that splits an input chunk into sub-chunks confined by
|
|
5
|
-
* both item count and encoded byte size limits. Designed for transports with
|
|
6
|
-
* strict frame caps (e.g. Cloudflare hibernated WebSockets).
|
|
7
|
-
*/
|
|
8
|
-
export const splitChunkBySize = (options) => (chunk) => {
|
|
9
|
-
const maxItems = Math.max(1, options.maxItems);
|
|
10
|
-
const maxBytes = Math.max(1, options.maxBytes);
|
|
11
|
-
const encode = options.encode;
|
|
12
|
-
const measure = (items) => {
|
|
13
|
-
const encoded = encode(items);
|
|
14
|
-
return textEncoder.encode(JSON.stringify(encoded)).byteLength;
|
|
15
|
-
};
|
|
16
|
-
const items = Chunk.toReadonlyArray(chunk);
|
|
17
|
-
if (items.length === 0) {
|
|
18
|
-
return Chunk.fromIterable([]);
|
|
19
|
-
}
|
|
20
|
-
const result = [];
|
|
21
|
-
let current = [];
|
|
22
|
-
const flushCurrent = () => {
|
|
23
|
-
if (current.length > 0) {
|
|
24
|
-
result.push(Chunk.fromIterable(current));
|
|
25
|
-
current = [];
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
for (const item of items) {
|
|
29
|
-
current.push(item);
|
|
30
|
-
const exceedsLimit = current.length > maxItems || measure(current) > maxBytes;
|
|
31
|
-
if (exceedsLimit) {
|
|
32
|
-
// remove the item we just added and emit the previous chunk if it exists
|
|
33
|
-
const last = current.pop();
|
|
34
|
-
flushCurrent();
|
|
35
|
-
if (last !== undefined) {
|
|
36
|
-
current = [last];
|
|
37
|
-
const singleItemTooLarge = measure(current) > maxBytes;
|
|
38
|
-
if (singleItemTooLarge || current.length > maxItems) {
|
|
39
|
-
// Emit the oversized item on its own; downstream can decide how to handle it.
|
|
40
|
-
result.push(Chunk.of(last));
|
|
41
|
-
current = [];
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
flushCurrent();
|
|
47
|
-
return Chunk.fromIterable(result);
|
|
48
|
-
};
|
|
49
|
-
//# sourceMappingURL=ws-chunking.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ws-chunking.js","sourceRoot":"","sources":["../../../src/cf-worker/do/ws-chunking.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AAE/C,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAA;AAiBrC;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAC3B,CAAI,OAA2B,EAAE,EAAE,CACnC,CAAC,KAAqB,EAA+B,EAAE;IACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC9C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;IAE7B,MAAM,OAAO,GAAG,CAAC,KAAuB,EAAE,EAAE;QAC1C,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;QAC7B,OAAO,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAA;IAC/D,CAAC,CAAA;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAA;IAC1C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC,YAAY,CAAiB,EAAE,CAAC,CAAA;IAC/C,CAAC;IAED,MAAM,MAAM,GAA0B,EAAE,CAAA;IACxC,IAAI,OAAO,GAAa,EAAE,CAAA;IAE1B,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAA;YACxC,OAAO,GAAG,EAAE,CAAA;QACd,CAAC;IACH,CAAC,CAAA;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClB,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,GAAG,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAA;QAE7E,IAAI,YAAY,EAAE,CAAC;YACjB,yEAAyE;YACzE,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAG,CAAA;YAC3B,YAAY,EAAE,CAAA;YAEd,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,OAAO,GAAG,CAAC,IAAI,CAAC,CAAA;gBAChB,MAAM,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAA;gBACtD,IAAI,kBAAkB,IAAI,OAAO,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;oBACpD,8EAA8E;oBAC9E,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;oBAC3B,OAAO,GAAG,EAAE,CAAA;gBACd,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,YAAY,EAAE,CAAA;IAEd,OAAO,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAA;AACnC,CAAC,CAAA"}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { Chunk } from '@livestore/utils/effect'
|
|
2
|
-
|
|
3
|
-
const textEncoder = new TextEncoder()
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Configuration describing how to break a chunk into smaller payload-safe chunks.
|
|
7
|
-
*/
|
|
8
|
-
export interface ChunkingOptions<A> {
|
|
9
|
-
/** Maximum number of items that may appear in any emitted chunk. */
|
|
10
|
-
readonly maxItems: number
|
|
11
|
-
/** Maximum encoded byte size allowed for any emitted chunk. */
|
|
12
|
-
readonly maxBytes: number
|
|
13
|
-
/**
|
|
14
|
-
* Callback that produces a JSON-serialisable structure whose byte size should
|
|
15
|
-
* fit within {@link maxBytes}. This lets callers control framing overhead.
|
|
16
|
-
*/
|
|
17
|
-
readonly encode: (items: ReadonlyArray<A>) => unknown
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Derives a function that splits an input chunk into sub-chunks confined by
|
|
22
|
-
* both item count and encoded byte size limits. Designed for transports with
|
|
23
|
-
* strict frame caps (e.g. Cloudflare hibernated WebSockets).
|
|
24
|
-
*/
|
|
25
|
-
export const splitChunkBySize =
|
|
26
|
-
<A>(options: ChunkingOptions<A>) =>
|
|
27
|
-
(chunk: Chunk.Chunk<A>): Chunk.Chunk<Chunk.Chunk<A>> => {
|
|
28
|
-
const maxItems = Math.max(1, options.maxItems)
|
|
29
|
-
const maxBytes = Math.max(1, options.maxBytes)
|
|
30
|
-
const encode = options.encode
|
|
31
|
-
|
|
32
|
-
const measure = (items: ReadonlyArray<A>) => {
|
|
33
|
-
const encoded = encode(items)
|
|
34
|
-
return textEncoder.encode(JSON.stringify(encoded)).byteLength
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const items = Chunk.toReadonlyArray(chunk)
|
|
38
|
-
if (items.length === 0) {
|
|
39
|
-
return Chunk.fromIterable<Chunk.Chunk<A>>([])
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const result: Array<Chunk.Chunk<A>> = []
|
|
43
|
-
let current: Array<A> = []
|
|
44
|
-
|
|
45
|
-
const flushCurrent = () => {
|
|
46
|
-
if (current.length > 0) {
|
|
47
|
-
result.push(Chunk.fromIterable(current))
|
|
48
|
-
current = []
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
for (const item of items) {
|
|
53
|
-
current.push(item)
|
|
54
|
-
const exceedsLimit = current.length > maxItems || measure(current) > maxBytes
|
|
55
|
-
|
|
56
|
-
if (exceedsLimit) {
|
|
57
|
-
// remove the item we just added and emit the previous chunk if it exists
|
|
58
|
-
const last = current.pop()!
|
|
59
|
-
flushCurrent()
|
|
60
|
-
|
|
61
|
-
if (last !== undefined) {
|
|
62
|
-
current = [last]
|
|
63
|
-
const singleItemTooLarge = measure(current) > maxBytes
|
|
64
|
-
if (singleItemTooLarge || current.length > maxItems) {
|
|
65
|
-
// Emit the oversized item on its own; downstream can decide how to handle it.
|
|
66
|
-
result.push(Chunk.of(last))
|
|
67
|
-
current = []
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
flushCurrent()
|
|
74
|
-
|
|
75
|
-
return Chunk.fromIterable(result)
|
|
76
|
-
}
|