@livestore/sync-s2 0.4.0-dev.21 → 0.4.0-dev.23

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.
@@ -677,7 +677,7 @@ export const make = (
677
677
  )
678
678
  const withResponse: <A, E>(
679
679
  f: (response: HttpClientResponse.HttpClientResponse) => Effect.Effect<A, E>,
680
- ) => (request: HttpClientRequest.HttpClientRequest) => Effect.Effect<any, any> = options.transformClient
680
+ ) => (request: HttpClientRequest.HttpClientRequest) => Effect.Effect<any, any> = options.transformClient !== undefined
681
681
  ? (f) => (request) =>
682
682
  Effect.flatMap(
683
683
  Effect.flatMap(options.transformClient!(httpClient), (client) => client.execute(request)),
@@ -697,6 +697,7 @@ export const make = (
697
697
  return {
698
698
  httpClient,
699
699
  listAccessTokens: (options) =>
700
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
700
701
  HttpClientRequest.get(`/access-tokens`).pipe(
701
702
  HttpClientRequest.setUrlParams({
702
703
  prefix: options?.prefix as any,
@@ -713,6 +714,7 @@ export const make = (
713
714
  ),
714
715
  ),
715
716
  issueAccessToken: (options) =>
717
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
716
718
  HttpClientRequest.post(`/access-tokens`).pipe(
717
719
  HttpClientRequest.bodyUnsafeJson(options),
718
720
  withResponse(
@@ -726,6 +728,7 @@ export const make = (
726
728
  ),
727
729
  ),
728
730
  revokeAccessToken: (id) =>
731
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
729
732
  HttpClientRequest.del(`/access-tokens/${id}`).pipe(
730
733
  withResponse(
731
734
  HttpClientResponse.matchStatus({
@@ -737,6 +740,7 @@ export const make = (
737
740
  ),
738
741
  ),
739
742
  listBasins: (options) =>
743
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
740
744
  HttpClientRequest.get(`/basins`).pipe(
741
745
  HttpClientRequest.setUrlParams({
742
746
  prefix: options?.prefix as any,
@@ -753,6 +757,7 @@ export const make = (
753
757
  ),
754
758
  ),
755
759
  createBasin: (options) =>
760
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
756
761
  HttpClientRequest.post(`/basins`).pipe(
757
762
  HttpClientRequest.bodyUnsafeJson(options),
758
763
  withResponse(
@@ -768,6 +773,7 @@ export const make = (
768
773
  ),
769
774
  ),
770
775
  getBasinConfig: (basin) =>
776
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
771
777
  HttpClientRequest.get(`/basins/${basin}`).pipe(
772
778
  withResponse(
773
779
  HttpClientResponse.matchStatus({
@@ -780,6 +786,7 @@ export const make = (
780
786
  ),
781
787
  ),
782
788
  createOrReconfigureBasin: (basin, options) =>
789
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
783
790
  HttpClientRequest.put(`/basins/${basin}`).pipe(
784
791
  HttpClientRequest.setHeaders({ 's2-request-token': options.params?.['s2-request-token'] ?? undefined }),
785
792
  HttpClientRequest.bodyUnsafeJson(options.payload),
@@ -794,6 +801,7 @@ export const make = (
794
801
  ),
795
802
  ),
796
803
  deleteBasin: (basin) =>
804
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
797
805
  HttpClientRequest.del(`/basins/${basin}`).pipe(
798
806
  withResponse(
799
807
  HttpClientResponse.matchStatus({
@@ -807,6 +815,7 @@ export const make = (
807
815
  ),
808
816
  ),
809
817
  reconfigureBasin: (basin, options) =>
818
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
810
819
  HttpClientRequest.patch(`/basins/${basin}`).pipe(
811
820
  HttpClientRequest.bodyUnsafeJson(options),
812
821
  withResponse(
@@ -820,6 +829,7 @@ export const make = (
820
829
  ),
821
830
  ),
822
831
  accountMetrics: (options) =>
832
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
823
833
  HttpClientRequest.get(`/metrics`).pipe(
824
834
  HttpClientRequest.setUrlParams({
825
835
  set: options?.set as any,
@@ -837,6 +847,7 @@ export const make = (
837
847
  ),
838
848
  ),
839
849
  basinMetrics: (basin, options) =>
850
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
840
851
  HttpClientRequest.get(`/metrics/${basin}`).pipe(
841
852
  HttpClientRequest.setUrlParams({
842
853
  set: options?.set as any,
@@ -854,6 +865,7 @@ export const make = (
854
865
  ),
855
866
  ),
856
867
  streamMetrics: (basin, stream, options) =>
868
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
857
869
  HttpClientRequest.get(`/metrics/${basin}/${stream}`).pipe(
858
870
  HttpClientRequest.setUrlParams({
859
871
  set: options?.set as any,
@@ -871,6 +883,7 @@ export const make = (
871
883
  ),
872
884
  ),
873
885
  listStreams: (options) =>
886
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
874
887
  HttpClientRequest.get(`/streams`).pipe(
875
888
  HttpClientRequest.setUrlParams({
876
889
  prefix: options?.prefix as any,
@@ -888,6 +901,7 @@ export const make = (
888
901
  ),
889
902
  ),
890
903
  createStream: (options) =>
904
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
891
905
  HttpClientRequest.post(`/streams`).pipe(
892
906
  HttpClientRequest.bodyUnsafeJson(options),
893
907
  withResponse(
@@ -902,6 +916,7 @@ export const make = (
902
916
  ),
903
917
  ),
904
918
  getStreamConfig: (stream) =>
919
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
905
920
  HttpClientRequest.get(`/streams/${stream}`).pipe(
906
921
  withResponse(
907
922
  HttpClientResponse.matchStatus({
@@ -915,6 +930,7 @@ export const make = (
915
930
  ),
916
931
  ),
917
932
  createOrReconfigureStream: (stream, options) =>
933
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
918
934
  HttpClientRequest.put(`/streams/${stream}`).pipe(
919
935
  HttpClientRequest.setHeaders({ 's2-request-token': options.params?.['s2-request-token'] ?? undefined }),
920
936
  HttpClientRequest.bodyUnsafeJson(options.payload),
@@ -931,6 +947,7 @@ export const make = (
931
947
  ),
932
948
  ),
933
949
  deleteStream: (stream) =>
950
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
934
951
  HttpClientRequest.del(`/streams/${stream}`).pipe(
935
952
  withResponse(
936
953
  HttpClientResponse.matchStatus({
@@ -943,6 +960,7 @@ export const make = (
943
960
  ),
944
961
  ),
945
962
  reconfigureStream: (stream, options) =>
963
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
946
964
  HttpClientRequest.patch(`/streams/${stream}`).pipe(
947
965
  HttpClientRequest.bodyUnsafeJson(options),
948
966
  withResponse(
@@ -957,6 +975,7 @@ export const make = (
957
975
  ),
958
976
  ),
959
977
  read: (stream, options) =>
978
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
960
979
  HttpClientRequest.get(`/streams/${stream}/records`).pipe(
961
980
  HttpClientRequest.setUrlParams({
962
981
  seq_num: options?.seq_num as any,
@@ -982,6 +1001,7 @@ export const make = (
982
1001
  ),
983
1002
  ),
984
1003
  append: (stream, options) =>
1004
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
985
1005
  HttpClientRequest.post(`/streams/${stream}/records`).pipe(
986
1006
  HttpClientRequest.setHeaders({ 's2-format': options.params?.['s2-format'] ?? undefined }),
987
1007
  HttpClientRequest.bodyUnsafeJson(options.payload),
@@ -999,6 +1019,7 @@ export const make = (
999
1019
  ),
1000
1020
  ),
1001
1021
  checkTail: (stream) =>
1022
+ // @effect-diagnostics-next-line anyUnknownInErrorContext:off
1002
1023
  HttpClientRequest.get(`/streams/${stream}/records/tail`).pipe(
1003
1024
  withResponse(
1004
1025
  HttpClientResponse.matchStatus({
@@ -1021,13 +1042,13 @@ export interface Client {
1021
1042
  * List access tokens.
1022
1043
  */
1023
1044
  readonly listAccessTokens: (
1024
- options?: typeof ListAccessTokensParams.Encoded | undefined,
1045
+ options?: typeof ListAccessTokensParams.Encoded ,
1025
1046
  ) => Effect.Effect<
1026
1047
  typeof ListAccessTokensResponse.Type,
1027
1048
  | HttpClientError.HttpClientError
1028
1049
  | ParseResult.ParseError
1029
1050
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1030
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1051
+
1031
1052
  >
1032
1053
  /**
1033
1054
  * Issue a new access token.
@@ -1039,8 +1060,8 @@ export interface Client {
1039
1060
  | HttpClientError.HttpClientError
1040
1061
  | ParseResult.ParseError
1041
1062
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1042
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1043
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1063
+
1064
+
1044
1065
  >
1045
1066
  /**
1046
1067
  * Revoke an access token.
@@ -1052,19 +1073,19 @@ export interface Client {
1052
1073
  | HttpClientError.HttpClientError
1053
1074
  | ParseResult.ParseError
1054
1075
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1055
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1076
+
1056
1077
  >
1057
1078
  /**
1058
1079
  * List basins.
1059
1080
  */
1060
1081
  readonly listBasins: (
1061
- options?: typeof ListBasinsParams.Encoded | undefined,
1082
+ options?: typeof ListBasinsParams.Encoded ,
1062
1083
  ) => Effect.Effect<
1063
1084
  typeof ListBasinsResponse.Type,
1064
1085
  | HttpClientError.HttpClientError
1065
1086
  | ParseResult.ParseError
1066
1087
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1067
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1088
+
1068
1089
  >
1069
1090
  /**
1070
1091
  * Create a basin.
@@ -1072,13 +1093,13 @@ export interface Client {
1072
1093
  readonly createBasin: (
1073
1094
  options: typeof CreateBasinRequest.Encoded,
1074
1095
  ) => Effect.Effect<
1075
- typeof BasinInfo.Type | typeof BasinInfo.Type,
1096
+ typeof BasinInfo.Type ,
1076
1097
  | HttpClientError.HttpClientError
1077
1098
  | ParseResult.ParseError
1078
1099
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1079
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1080
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1081
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1100
+
1101
+
1102
+
1082
1103
  >
1083
1104
  /**
1084
1105
  * Get basin configuration.
@@ -1090,8 +1111,8 @@ export interface Client {
1090
1111
  | HttpClientError.HttpClientError
1091
1112
  | ParseResult.ParseError
1092
1113
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1093
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1094
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1114
+
1115
+
1095
1116
  >
1096
1117
  /**
1097
1118
  * Create or reconfigure a basin.
@@ -1103,7 +1124,7 @@ export interface Client {
1103
1124
  readonly payload: typeof CreateOrReconfigureBasinRequest.Encoded
1104
1125
  },
1105
1126
  ) => Effect.Effect<
1106
- typeof BasinInfo.Type | typeof BasinInfo.Type,
1127
+ typeof BasinInfo.Type ,
1107
1128
  HttpClientError.HttpClientError | ParseResult.ParseError | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1108
1129
  >
1109
1130
  /**
@@ -1116,9 +1137,9 @@ export interface Client {
1116
1137
  | HttpClientError.HttpClientError
1117
1138
  | ParseResult.ParseError
1118
1139
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1119
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1120
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1121
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1140
+
1141
+
1142
+
1122
1143
  >
1123
1144
  /**
1124
1145
  * Reconfigure a basin.
@@ -1131,8 +1152,8 @@ export interface Client {
1131
1152
  | HttpClientError.HttpClientError
1132
1153
  | ParseResult.ParseError
1133
1154
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1134
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1135
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1155
+
1156
+
1136
1157
  >
1137
1158
  /**
1138
1159
  * Account-level metrics.
@@ -1144,7 +1165,7 @@ export interface Client {
1144
1165
  | HttpClientError.HttpClientError
1145
1166
  | ParseResult.ParseError
1146
1167
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1147
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1168
+
1148
1169
  >
1149
1170
  /**
1150
1171
  * Basin-level metrics.
@@ -1157,7 +1178,7 @@ export interface Client {
1157
1178
  | HttpClientError.HttpClientError
1158
1179
  | ParseResult.ParseError
1159
1180
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1160
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1181
+
1161
1182
  >
1162
1183
  /**
1163
1184
  * Stream-level metrics.
@@ -1171,20 +1192,20 @@ export interface Client {
1171
1192
  | HttpClientError.HttpClientError
1172
1193
  | ParseResult.ParseError
1173
1194
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1174
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1195
+
1175
1196
  >
1176
1197
  /**
1177
1198
  * List streams.
1178
1199
  */
1179
1200
  readonly listStreams: (
1180
- options?: typeof ListStreamsParams.Encoded | undefined,
1201
+ options?: typeof ListStreamsParams.Encoded ,
1181
1202
  ) => Effect.Effect<
1182
1203
  typeof ListStreamsResponse.Type,
1183
1204
  | HttpClientError.HttpClientError
1184
1205
  | ParseResult.ParseError
1185
1206
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1186
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1187
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1207
+
1208
+
1188
1209
  >
1189
1210
  /**
1190
1211
  * Create a stream.
@@ -1196,9 +1217,9 @@ export interface Client {
1196
1217
  | HttpClientError.HttpClientError
1197
1218
  | ParseResult.ParseError
1198
1219
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1199
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1200
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1201
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1220
+
1221
+
1222
+
1202
1223
  >
1203
1224
  /**
1204
1225
  * Get stream configuration.
@@ -1210,9 +1231,9 @@ export interface Client {
1210
1231
  | HttpClientError.HttpClientError
1211
1232
  | ParseResult.ParseError
1212
1233
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1213
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1214
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1215
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1234
+
1235
+
1236
+
1216
1237
  >
1217
1238
  /**
1218
1239
  * Create or reconfigure a stream.
@@ -1228,9 +1249,9 @@ export interface Client {
1228
1249
  | HttpClientError.HttpClientError
1229
1250
  | ParseResult.ParseError
1230
1251
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1231
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1232
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1233
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1252
+
1253
+
1254
+
1234
1255
  >
1235
1256
  /**
1236
1257
  * Delete a stream.
@@ -1242,8 +1263,8 @@ export interface Client {
1242
1263
  | HttpClientError.HttpClientError
1243
1264
  | ParseResult.ParseError
1244
1265
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1245
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1246
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1266
+
1267
+
1247
1268
  >
1248
1269
  /**
1249
1270
  * Reconfigure a stream.
@@ -1256,26 +1277,26 @@ export interface Client {
1256
1277
  | HttpClientError.HttpClientError
1257
1278
  | ParseResult.ParseError
1258
1279
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1259
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1260
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1261
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1280
+
1281
+
1282
+
1262
1283
  >
1263
1284
  /**
1264
1285
  * Read records.
1265
1286
  */
1266
1287
  readonly read: (
1267
1288
  stream: string,
1268
- options?: typeof ReadParams.Encoded | undefined,
1289
+ options?: typeof ReadParams.Encoded ,
1269
1290
  ) => Effect.Effect<
1270
1291
  typeof ReadBatch.Type,
1271
1292
  | HttpClientError.HttpClientError
1272
1293
  | ParseResult.ParseError
1273
1294
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1274
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1275
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1276
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1295
+
1296
+
1297
+
1277
1298
  | ClientError<'TailResponse', typeof TailResponse.Type>
1278
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1299
+
1279
1300
  >
1280
1301
  /**
1281
1302
  * Append records.
@@ -1291,11 +1312,11 @@ export interface Client {
1291
1312
  | HttpClientError.HttpClientError
1292
1313
  | ParseResult.ParseError
1293
1314
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1294
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1295
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1296
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1315
+
1316
+
1317
+
1297
1318
  | ClientError<'AppendConditionFailed', typeof AppendConditionFailed.Type>
1298
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1319
+
1299
1320
  >
1300
1321
  /**
1301
1322
  * Check the tail.
@@ -1307,10 +1328,10 @@ export interface Client {
1307
1328
  | HttpClientError.HttpClientError
1308
1329
  | ParseResult.ParseError
1309
1330
  | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1310
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1311
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1312
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1313
- | ClientError<'ErrorResponse', typeof ErrorResponse.Type>
1331
+
1332
+
1333
+
1334
+
1314
1335
  >
1315
1336
  }
1316
1337
 
@@ -1,5 +1,7 @@
1
- import type { EventSequenceNumber, LiveStoreEvent } from '@livestore/common/schema'
2
1
  import { describe, expect, it } from 'vitest'
2
+
3
+ import type { EventSequenceNumber, LiveStoreEvent } from '@livestore/common/schema'
4
+
3
5
  import {
4
6
  chunkEventsForS2,
5
7
  computeRecordMeteredBytes,
package/src/limits.ts CHANGED
@@ -21,7 +21,7 @@ export const MAX_RECORDS_PER_BATCH = 1_000
21
21
 
22
22
  const LimitType = Schema.Literal('record-metered-bytes', 'batch-metered-bytes', 'batch-count')
23
23
 
24
- export class S2LimitExceededError extends Schema.TaggedError<S2LimitExceededError>()('S2LimitExceededError', {
24
+ export class S2LimitExceededError extends Schema.TaggedError<S2LimitExceededError>('~@livestore/sync-s2/S2LimitExceededError')('S2LimitExceededError', {
25
25
  limitType: LimitType,
26
26
  max: Schema.Number,
27
27
  actual: Schema.Number,
@@ -121,7 +121,7 @@ export const chunkEventsForS2 = (events: ReadonlyArray<LiveStoreEvent.Global.Enc
121
121
 
122
122
  return mapPreparedChunks(chunks)
123
123
  } catch (error) {
124
- if (error && typeof error === 'object' && (error as any)._tag === 'OversizeChunkItemError') {
124
+ if (error !== undefined && typeof error === 'object' && (error as any)._tag === 'OversizeChunkItemError') {
125
125
  const oversize = error as { size: number; maxBytes: number; _tag: string }
126
126
  throw new S2LimitExceededError({
127
127
  limitType: 'record-metered-bytes',
@@ -1,5 +1,6 @@
1
1
  import { shouldNeverHappen } from '@livestore/utils'
2
2
  import { Schema } from '@livestore/utils/effect'
3
+
3
4
  import * as ApiSchema from './api-schema.ts'
4
5
 
5
6
  export const makeS2StreamName = (storeId: string) => storeId.replace(/[^a-zA-Z0-9_-]/g, '-').slice(0, 100)
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import type { LiveStoreEvent } from '@livestore/livestore'
7
+
7
8
  import type { PullArgs } from './api-schema.ts'
8
9
  import { chunkEventsForS2 } from './limits.ts'
9
10
  import { makeS2StreamName } from './make-s2-url.ts'
@@ -16,8 +17,20 @@ export interface S2Config {
16
17
  accountBase?: string
17
18
  /** @default 'https://{basin}.b.aws.s2.dev/v1' */
18
19
  basinBase?: string
20
+ /**
21
+ * When true, adds `S2-Basin` header to requests. This is required for s2-lite
22
+ * (the open-source self-hosted S2) which uses header-based basin routing instead
23
+ * of subdomain-based routing used by hosted S2.
24
+ * @see https://github.com/s2-streamstore/s2-lite
25
+ */
26
+ lite?: boolean
19
27
  }
20
28
 
29
+ export const isLiteMode = (config: S2Config): boolean => config.lite === true
30
+
31
+ const getBasinHeader = (config: S2Config): Record<string, string> =>
32
+ isLiteMode(config) === true ? { 's2-basin': config.basin } : {}
33
+
21
34
  // URL construction helpers
22
35
  export const getBasinUrl = (config: S2Config, path: string): string => {
23
36
  const base = config.basinBase ?? `https://${config.basin}.b.aws.s2.dev/v1`
@@ -35,7 +48,7 @@ export const getStreamRecordsUrl = (
35
48
  params?: { seq_num?: number; count?: number; clamp?: boolean; wait?: number },
36
49
  ): string => {
37
50
  const base = getBasinUrl(config, `/streams/${encodeURIComponent(stream)}/records`)
38
- if (!params) return base
51
+ if (params == null) return base
39
52
 
40
53
  const searchParams = new URLSearchParams()
41
54
  /** seq_num - The sequence number to start from. See: https://docs.s2.dev/api#seq_num */
@@ -47,7 +60,8 @@ export const getStreamRecordsUrl = (
47
60
  /** wait - How long to wait for new records before returning. See: https://docs.s2.dev/api#wait */
48
61
  if (params.wait !== undefined) searchParams.append('wait', params.wait.toString())
49
62
 
50
- return searchParams.toString() ? `${base}?${searchParams}` : base
63
+ const searchParamsString = searchParams.toString()
64
+ return searchParamsString.length > 0 ? `${base}?${searchParams}` : base
51
65
  }
52
66
 
53
67
  // Header helpers
@@ -55,14 +69,16 @@ export const getAuthHeaders = (token: string): Record<string, string> => ({
55
69
  Authorization: `Bearer ${token}`,
56
70
  })
57
71
 
58
- export const getSSEHeaders = (token: string): Record<string, string> => ({
59
- ...getAuthHeaders(token),
72
+ export const getSSEHeaders = (config: S2Config): Record<string, string> => ({
73
+ ...getAuthHeaders(config.token),
74
+ ...getBasinHeader(config),
60
75
  accept: 'text/event-stream',
61
76
  's2-format': 'raw',
62
77
  })
63
78
 
64
- export const getPushHeaders = (token: string): Record<string, string> => ({
65
- ...getAuthHeaders(token),
79
+ export const getPushHeaders = (config: S2Config): Record<string, string> => ({
80
+ ...getAuthHeaders(config.token),
81
+ ...getBasinHeader(config),
66
82
  'content-type': 'application/json',
67
83
  's2-format': 'raw',
68
84
  })
@@ -89,6 +105,7 @@ export const ensureStream = async (config: S2Config, stream: string): Promise<vo
89
105
  method: 'POST',
90
106
  headers: {
91
107
  ...getAuthHeaders(config.token),
108
+ ...getBasinHeader(config),
92
109
  'content-type': 'application/json',
93
110
  },
94
111
  body: JSON.stringify({ stream }),
@@ -114,15 +131,15 @@ export const buildPullRequest = ({
114
131
  // cursor points to last processed record, seq_num needs to be the next record
115
132
  const seq_num = args.s2SeqNum === 'from-start' ? 0 : args.s2SeqNum + 1
116
133
 
117
- if (args.live) {
134
+ if (args.live === true) {
118
135
  const url = getStreamRecordsUrl(config, streamName, { seq_num, clamp: true })
119
- return { url, headers: getSSEHeaders(config.token) }
136
+ return { url, headers: getSSEHeaders(config) }
120
137
  } else {
121
138
  // Non-live pulls also stream over SSE. We ask S2 to return immediately when
122
139
  // the tail is reached by setting wait=0 which gives us an explicit
123
140
  // end-of-stream without requesting an arbitrarily large page size.
124
141
  const url = getStreamRecordsUrl(config, streamName, { seq_num, wait: 0, clamp: true })
125
- return { url, headers: getSSEHeaders(config.token) }
142
+ return { url, headers: getSSEHeaders(config) }
126
143
  }
127
144
  }
128
145
 
@@ -155,7 +172,7 @@ export const buildPushRequests = ({
155
172
  return chunks.map((chunk) => ({
156
173
  url,
157
174
  method: 'POST' as const,
158
- headers: getPushHeaders(config.token),
175
+ headers: getPushHeaders(config),
159
176
  body: JSON.stringify({ records: chunk.records }),
160
177
  }))
161
178
  }