@effect/platform-browser 4.0.0-beta.7 → 4.0.0-beta.70

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 (91) hide show
  1. package/dist/BrowserCrypto.d.ts +23 -0
  2. package/dist/BrowserCrypto.d.ts.map +1 -0
  3. package/dist/BrowserCrypto.js +61 -0
  4. package/dist/BrowserCrypto.js.map +1 -0
  5. package/dist/BrowserHttpClient.d.ts +32 -16
  6. package/dist/BrowserHttpClient.d.ts.map +1 -1
  7. package/dist/BrowserHttpClient.js +66 -18
  8. package/dist/BrowserHttpClient.js.map +1 -1
  9. package/dist/BrowserKeyValueStore.d.ts +17 -14
  10. package/dist/BrowserKeyValueStore.d.ts.map +1 -1
  11. package/dist/BrowserKeyValueStore.js +130 -10
  12. package/dist/BrowserKeyValueStore.js.map +1 -1
  13. package/dist/BrowserPersistence.d.ts +21 -0
  14. package/dist/BrowserPersistence.d.ts.map +1 -0
  15. package/dist/BrowserPersistence.js +188 -0
  16. package/dist/BrowserPersistence.js.map +1 -0
  17. package/dist/BrowserRuntime.d.ts +31 -4
  18. package/dist/BrowserRuntime.d.ts.map +1 -1
  19. package/dist/BrowserRuntime.js +3 -1
  20. package/dist/BrowserRuntime.js.map +1 -1
  21. package/dist/BrowserSocket.d.ts +31 -6
  22. package/dist/BrowserSocket.d.ts.map +1 -1
  23. package/dist/BrowserSocket.js +31 -6
  24. package/dist/BrowserSocket.js.map +1 -1
  25. package/dist/BrowserStream.d.ts +33 -5
  26. package/dist/BrowserStream.d.ts.map +1 -1
  27. package/dist/BrowserStream.js +33 -5
  28. package/dist/BrowserStream.js.map +1 -1
  29. package/dist/BrowserWorker.d.ts +8 -4
  30. package/dist/BrowserWorker.d.ts.map +1 -1
  31. package/dist/BrowserWorker.js +30 -6
  32. package/dist/BrowserWorker.js.map +1 -1
  33. package/dist/BrowserWorkerRunner.d.ts +12 -6
  34. package/dist/BrowserWorkerRunner.d.ts.map +1 -1
  35. package/dist/BrowserWorkerRunner.js +34 -10
  36. package/dist/BrowserWorkerRunner.js.map +1 -1
  37. package/dist/Clipboard.d.ts +40 -13
  38. package/dist/Clipboard.d.ts.map +1 -1
  39. package/dist/Clipboard.js +33 -11
  40. package/dist/Clipboard.js.map +1 -1
  41. package/dist/Geolocation.d.ts +58 -24
  42. package/dist/Geolocation.d.ts.map +1 -1
  43. package/dist/Geolocation.js +46 -16
  44. package/dist/Geolocation.js.map +1 -1
  45. package/dist/IndexedDb.d.ts +77 -0
  46. package/dist/IndexedDb.d.ts.map +1 -0
  47. package/dist/IndexedDb.js +87 -0
  48. package/dist/IndexedDb.js.map +1 -0
  49. package/dist/IndexedDbDatabase.d.ts +150 -0
  50. package/dist/IndexedDbDatabase.d.ts.map +1 -0
  51. package/dist/IndexedDbDatabase.js +324 -0
  52. package/dist/IndexedDbDatabase.js.map +1 -0
  53. package/dist/IndexedDbQueryBuilder.d.ts +430 -0
  54. package/dist/IndexedDbQueryBuilder.d.ts.map +1 -0
  55. package/dist/IndexedDbQueryBuilder.js +927 -0
  56. package/dist/IndexedDbQueryBuilder.js.map +1 -0
  57. package/dist/IndexedDbTable.d.ts +153 -0
  58. package/dist/IndexedDbTable.d.ts.map +1 -0
  59. package/dist/IndexedDbTable.js +58 -0
  60. package/dist/IndexedDbTable.js.map +1 -0
  61. package/dist/IndexedDbVersion.d.ts +80 -0
  62. package/dist/IndexedDbVersion.d.ts.map +1 -0
  63. package/dist/IndexedDbVersion.js +25 -0
  64. package/dist/IndexedDbVersion.js.map +1 -0
  65. package/dist/Permissions.d.ts +45 -15
  66. package/dist/Permissions.d.ts.map +1 -1
  67. package/dist/Permissions.js +35 -10
  68. package/dist/Permissions.js.map +1 -1
  69. package/dist/index.d.ts +357 -10
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +357 -10
  72. package/dist/index.js.map +1 -1
  73. package/package.json +4 -3
  74. package/src/BrowserCrypto.ts +71 -0
  75. package/src/BrowserHttpClient.ts +76 -24
  76. package/src/BrowserKeyValueStore.ts +146 -12
  77. package/src/BrowserPersistence.ts +319 -0
  78. package/src/BrowserRuntime.ts +31 -4
  79. package/src/BrowserSocket.ts +31 -6
  80. package/src/BrowserStream.ts +33 -5
  81. package/src/BrowserWorker.ts +30 -6
  82. package/src/BrowserWorkerRunner.ts +34 -10
  83. package/src/Clipboard.ts +37 -13
  84. package/src/Geolocation.ts +54 -20
  85. package/src/IndexedDb.ts +115 -0
  86. package/src/IndexedDbDatabase.ts +645 -0
  87. package/src/IndexedDbQueryBuilder.ts +2040 -0
  88. package/src/IndexedDbTable.ts +247 -0
  89. package/src/IndexedDbVersion.ts +119 -0
  90. package/src/Permissions.ts +40 -13
  91. package/src/index.ts +364 -10
@@ -1,17 +1,42 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Browser entry-point helpers for running Effect programs.
3
+ *
4
+ * This module exposes `runMain`, a browser-oriented main runner for launching
5
+ * an Effect as the root program of a page, single-page application, demo, or
6
+ * browser test harness. It delegates execution to the core Effect runtime while
7
+ * adding the browser lifecycle hook needed to interrupt the main fiber when the
8
+ * page receives `beforeunload`.
9
+ *
10
+ * `BrowserRuntime` does not provide application services by itself. Provide
11
+ * any required layers, such as browser HTTP, storage, worker, geolocation, or
12
+ * permission services, before passing the effect to `runMain`. Keep long-lived
13
+ * browser resources scoped so interruption can run their finalizers while the
14
+ * page is still active.
15
+ *
16
+ * Browser unload is more constrained than a process signal. Finalizers that
17
+ * need the network, timers, prompts, or long asynchronous work may not complete
18
+ * once navigation or tab close has started, and browsers do not expose a
19
+ * process exit status. Use `runMain` to connect the page lifecycle to Effect
20
+ * interruption, and use browser-specific persistence or delivery APIs for work
21
+ * that must survive page teardown.
22
+ *
23
+ * @since 4.0.0
3
24
  */
4
25
  import type * as Effect from "effect/Effect"
5
26
  import { makeRunMain, type Teardown } from "effect/Runtime"
6
27
 
7
28
  /**
8
- * @since 1.0.0
29
+ * Runs an effect as the browser main program and interrupts its fiber when the page receives a `beforeunload` event.
30
+ *
9
31
  * @category Runtime
32
+ * @since 4.0.0
10
33
  */
11
34
  export const runMain: {
12
35
  /**
13
- * @since 1.0.0
36
+ * Runs an effect as the browser main program and interrupts its fiber when the page receives a `beforeunload` event.
37
+ *
14
38
  * @category Runtime
39
+ * @since 4.0.0
15
40
  */
16
41
  (
17
42
  options?: {
@@ -20,8 +45,10 @@ export const runMain: {
20
45
  }
21
46
  ): <E, A>(effect: Effect.Effect<A, E>) => void
22
47
  /**
23
- * @since 1.0.0
48
+ * Runs an effect as the browser main program and interrupts its fiber when the page receives a `beforeunload` event.
49
+ *
24
50
  * @category Runtime
51
+ * @since 4.0.0
25
52
  */
26
53
  <E, A>(
27
54
  effect: Effect.Effect<A, E>,
@@ -1,12 +1,37 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Browser WebSocket layers for Effect sockets.
3
+ *
4
+ * This module provides the browser entry point for `Socket.Socket` values
5
+ * backed by the platform `WebSocket` implementation. Use `layerWebSocket` when
6
+ * client-side Effect programs, browser tests, RPC transports, or realtime UI
7
+ * features need a bidirectional socket connected to a WebSocket URL, and use
8
+ * `layerWebSocketConstructor` when lower-level socket APIs need access to the
9
+ * browser constructor service.
10
+ *
11
+ * Browser WebSocket rules still apply. Connections are created through
12
+ * `globalThis.WebSocket`, so URL schemes, subprotocol negotiation, mixed-content
13
+ * blocking, cookies, authentication, CORS-like origin checks, and extension
14
+ * negotiation are controlled by the browser and server rather than by Effect.
15
+ * Close events are translated into socket errors unless the provided
16
+ * `closeCodeIsError` predicate classifies the close code as clean, which is
17
+ * useful for protocols that use application-specific close codes.
18
+ *
19
+ * Messages are delivered as strings or binary `Uint8Array` values; browser
20
+ * `Blob` messages are read into bytes before they reach the socket handler.
21
+ * Outgoing data should already be serialized to a string or bytes, and protocol
22
+ * frames that represent an intentional close should be sent as `CloseEvent`
23
+ * values so the underlying `WebSocket.close` code and reason are preserved.
24
+ *
25
+ * @since 4.0.0
3
26
  */
4
27
  import * as Layer from "effect/Layer"
5
28
  import * as Socket from "effect/unstable/socket/Socket"
6
29
 
7
30
  /**
8
- * @since 1.0.0
9
- * @category Layers
31
+ * Creates a `Socket` layer connected to the given URL using the browser `WebSocket` constructor.
32
+ *
33
+ * @category layers
34
+ * @since 4.0.0
10
35
  */
11
36
  export const layerWebSocket = (url: string, options?: {
12
37
  readonly closeCodeIsError?: (code: number) => boolean
@@ -16,10 +41,10 @@ export const layerWebSocket = (url: string, options?: {
16
41
  )
17
42
 
18
43
  /**
19
- * A WebSocket constructor that uses `globalThis.WebSocket`.
44
+ * Layer that provides a `WebSocketConstructor` service backed by `globalThis.WebSocket`.
20
45
  *
21
- * @since 1.0.0
22
- * @category Layers
46
+ * @category layers
47
+ * @since 4.0.0
23
48
  */
24
49
  export const layerWebSocketConstructor: Layer.Layer<Socket.WebSocketConstructor> =
25
50
  Socket.layerWebSocketConstructorGlobal
@@ -1,5 +1,27 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Browser `Stream` constructors for DOM event targets.
3
+ *
4
+ * This module provides typed helpers for turning `window.addEventListener` and
5
+ * `document.addEventListener` callbacks into Effect `Stream`s. They are useful
6
+ * for UI and runtime signals such as resize, visibility, keyboard, pointer,
7
+ * focus, online / offline, and other browser events that should be composed
8
+ * with Effect stream operators and finalized with the consuming fiber.
9
+ *
10
+ * Browser events are push-based `EventTarget` notifications, so they do not
11
+ * apply Web Streams backpressure to the browser event source. Events are
12
+ * buffered until downstream pulls them; the default buffer is unbounded, so
13
+ * high-frequency sources like scroll, pointermove, or mousemove should usually
14
+ * set `bufferSize` and use stream operators that sample, debounce, throttle, or
15
+ * drop work as appropriate.
16
+ *
17
+ * These helpers are for DOM events, not for adapting `ReadableStream` request
18
+ * or response bodies. Fetch bodies follow the Web Streams body rules, including
19
+ * single-consumer locking and disturbed bodies after reads, and should be
20
+ * handled with body-specific HTTP or Web Streams APIs instead. When using the
21
+ * browser `once` option, pair the stream with `Stream.take(1)` if a finite
22
+ * stream is required.
23
+ *
24
+ * @since 4.0.0
3
25
  */
4
26
 
5
27
  import * as Stream from "effect/Stream"
@@ -7,11 +29,14 @@ import * as Stream from "effect/Stream"
7
29
  /**
8
30
  * Creates a `Stream` from `window.addEventListener`.
9
31
  *
32
+ * **Details**
33
+ *
10
34
  * By default, the underlying buffer is unbounded in size. You can customize the
11
- * buffer size an object as the second argument with the `bufferSize` field.
35
+ * buffer size by passing an object as the second argument with the `bufferSize`
36
+ * field.
12
37
  *
13
- * @since 1.0.0
14
38
  * @category Streams
39
+ * @since 4.0.0
15
40
  */
16
41
  export const fromEventListenerWindow = <K extends keyof WindowEventMap>(
17
42
  type: K,
@@ -26,11 +51,14 @@ export const fromEventListenerWindow = <K extends keyof WindowEventMap>(
26
51
  /**
27
52
  * Creates a `Stream` from `document.addEventListener`.
28
53
  *
54
+ * **Details**
55
+ *
29
56
  * By default, the underlying buffer is unbounded in size. You can customize the
30
- * buffer size an object as the second argument with the `bufferSize` field.
57
+ * buffer size by passing an object as the second argument with the `bufferSize`
58
+ * field.
31
59
  *
32
- * @since 1.0.0
33
60
  * @category Streams
61
+ * @since 4.0.0
34
62
  */
35
63
  export const fromEventListenerDocument = <K extends keyof DocumentEventMap>(
36
64
  type: K,
@@ -1,5 +1,25 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Parent-side browser support for Effect workers.
3
+ *
4
+ * This module provides the `WorkerPlatform` used by browser applications that
5
+ * spawn or connect to `Worker`, `SharedWorker`, and `MessagePort` endpoints
6
+ * through Effect's worker protocol. Pair it with `BrowserWorkerRunner` in the
7
+ * worker entrypoint when building worker-backed RPC clients, moving CPU-bound
8
+ * work off the main thread, isolating browser-only services, or adapting an
9
+ * existing `MessageChannel` in tests and custom transports.
10
+ *
11
+ * Dedicated workers communicate through the worker object itself, while shared
12
+ * workers communicate through `worker.port`; raw `MessagePort` values are also
13
+ * accepted and are started when supported. Messages are posted with the browser
14
+ * structured-clone algorithm, so payloads must be cloneable by the target
15
+ * runtime. Transfer lists can avoid copying values such as `ArrayBuffer` or
16
+ * `MessagePort`, but transferring moves ownership away from the sender and
17
+ * invalid or mismatched transferables can fail the send. Scope finalization
18
+ * sends the worker close signal over the port; the application that created a
19
+ * dedicated `Worker` remains responsible for any broader lifecycle such as
20
+ * terminating it.
21
+ *
22
+ * @since 4.0.0
3
23
  */
4
24
  import * as Deferred from "effect/Deferred"
5
25
  import * as Effect from "effect/Effect"
@@ -9,8 +29,10 @@ import * as Worker from "effect/unstable/workers/Worker"
9
29
  import { WorkerError, WorkerReceiveError } from "effect/unstable/workers/WorkerError"
10
30
 
11
31
  /**
12
- * @since 1.0.0
13
- * @category Layers
32
+ * Creates browser worker layers by combining the default `WorkerPlatform` with a spawner for `Worker`, `SharedWorker`, or `MessagePort` instances.
33
+ *
34
+ * @category layers
35
+ * @since 4.0.0
14
36
  */
15
37
  export const layer = (
16
38
  spawn: (id: number) => Worker | SharedWorker | MessagePort
@@ -21,8 +43,10 @@ export const layer = (
21
43
  )
22
44
 
23
45
  /**
24
- * @since 1.0.0
25
- * @category Layers
46
+ * Layer that provides the browser `WorkerPlatform` for `Worker`, `SharedWorker`, and `MessagePort` communication.
47
+ *
48
+ * @category layers
49
+ * @since 4.0.0
26
50
  */
27
51
  export const layerPlatform: Layer.Layer<Worker.WorkerPlatform> = Layer.succeed(Worker.WorkerPlatform)(
28
52
  Worker.makePlatform<globalThis.SharedWorker | globalThis.Worker | MessagePort>()({
@@ -50,7 +74,7 @@ export const layerPlatform: Layer.Layer<Worker.WorkerPlatform> = Layer.succeed(W
50
74
  message: "An error event was emitter",
51
75
  cause: event.error ?? event.message
52
76
  })
53
- }).asEffect()
77
+ })
54
78
  )
55
79
  }
56
80
  port.addEventListener("message", onMessage as any)
@@ -1,5 +1,23 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Browser runtime support for Effect worker runners.
3
+ *
4
+ * This module is intended for code that is already executing in a browser
5
+ * worker context, or for tests and adapters that supply a `MessagePort` or
6
+ * `Window` endpoint directly. It provides the `WorkerRunnerPlatform` used by
7
+ * `WorkerRunner` and `RpcServer.layerProtocolWorkerRunner` to receive parent
8
+ * or client requests, run Effect handlers, and send responses through the
9
+ * browser `postMessage` channel.
10
+ *
11
+ * Use it with `BrowserWorker` when a browser application needs to move RPC
12
+ * handlers, CPU-bound computations, or browser-only services into a dedicated
13
+ * worker or shared worker. Dedicated workers communicate through the current
14
+ * `self` endpoint; shared workers accept multiple `onconnect` ports and cache
15
+ * ports that connect before the runner layer starts. Messages still use the
16
+ * browser structured-clone algorithm, so payload schemas, transfer lists,
17
+ * `messageerror` events, and the lifetime of each `MessagePort` must be
18
+ * considered when crossing worker boundaries.
19
+ *
20
+ * @since 4.0.0
3
21
  */
4
22
  import * as Cause from "effect/Cause"
5
23
  import * as Deferred from "effect/Deferred"
@@ -22,8 +40,10 @@ if (typeof self !== "undefined" && "onconnect" in self) {
22
40
  }
23
41
 
24
42
  /**
25
- * @since 1.0.0
26
- * @category Constructors
43
+ * Creates a `WorkerRunnerPlatform` service that runs worker handlers over a `MessagePort` or `Window`.
44
+ *
45
+ * @category constructors
46
+ * @since 4.0.0
27
47
  */
28
48
  export const make = (self: MessagePort | Window): WorkerRunner.WorkerRunnerPlatform["Service"] => ({
29
49
  start: Effect.fnUntraced(function*<O = unknown, I = unknown>() {
@@ -44,7 +64,7 @@ export const make = (self: MessagePort | Window): WorkerRunner.WorkerRunnerPlatf
44
64
  Effect.scopedWith(Effect.fnUntraced(function*(scope) {
45
65
  const closeLatch = Deferred.makeUnsafe<void, WorkerError>()
46
66
  const trackFiber = Fiber.runIn(scope)
47
- const services = yield* Effect.services<R>()
67
+ const services = yield* Effect.context<R>()
48
68
  const runFork = Effect.runForkWith(services)
49
69
  const onExit = (exit: Exit.Exit<any, E>) => {
50
70
  if (exit._tag === "Failure" && !Cause.hasInterruptsOnly(exit.cause)) {
@@ -83,7 +103,7 @@ export const make = (self: MessagePort | Window): WorkerRunner.WorkerRunnerPlatf
83
103
  message: "An messageerror event was emitted",
84
104
  cause: error.data
85
105
  })
86
- }).asEffect()
106
+ })
87
107
  )
88
108
  }
89
109
  function onError(error: any) {
@@ -94,7 +114,7 @@ export const make = (self: MessagePort | Window): WorkerRunner.WorkerRunnerPlatf
94
114
  message: "An error event was emitted",
95
115
  cause: error.data
96
116
  })
97
- }).asEffect()
117
+ })
98
118
  )
99
119
  }
100
120
  function handlePort(port: MessagePort) {
@@ -151,16 +171,20 @@ export const make = (self: MessagePort | Window): WorkerRunner.WorkerRunnerPlatf
151
171
  })
152
172
 
153
173
  /**
154
- * @since 1.0.0
155
- * @category Layers
174
+ * Layer that provides a browser `WorkerRunnerPlatform` using the global `self` worker context.
175
+ *
176
+ * @category layers
177
+ * @since 4.0.0
156
178
  */
157
179
  export const layer: Layer.Layer<WorkerRunner.WorkerRunnerPlatform> = Layer.sync(WorkerRunner.WorkerRunnerPlatform)(() =>
158
180
  make(self)
159
181
  )
160
182
 
161
183
  /**
162
- * @since 1.0.0
163
- * @category Layers
184
+ * Layer that provides a `WorkerRunnerPlatform` using the supplied `MessagePort` or `Window`.
185
+ *
186
+ * @category layers
187
+ * @since 4.0.0
164
188
  */
165
189
  export const layerMessagePort = (port: MessagePort | Window): Layer.Layer<WorkerRunner.WorkerRunnerPlatform> =>
166
190
  Layer.succeed(WorkerRunner.WorkerRunnerPlatform)(make(port))
package/src/Clipboard.ts CHANGED
@@ -1,17 +1,35 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Browser clipboard service for Effect programs.
3
+ *
4
+ * This module wraps the browser `navigator.clipboard` API in a `Clipboard`
5
+ * service so client-side applications can read, write, and clear clipboard
6
+ * contents as typed Effects. It is useful for common UI workflows such as copy
7
+ * buttons, paste/import actions, sharing generated text, and moving rich
8
+ * clipboard payloads like `Blob`-backed `ClipboardItem`s through an Effect
9
+ * environment.
10
+ *
11
+ * Browser clipboard rules still apply. Clipboard access generally requires a
12
+ * secure context, and browsers may require a user gesture, permission prompt, or
13
+ * active focused document before reads or writes are allowed. Support also
14
+ * varies by operation and payload type: text helpers are the most portable,
15
+ * while `ClipboardItem` and non-text MIME types may be unavailable or restricted
16
+ * in some browsers. Failed browser operations are surfaced as `ClipboardError`.
17
+ *
18
+ * @since 4.0.0
3
19
  */
20
+ import * as Context from "effect/Context"
4
21
  import * as Data from "effect/Data"
5
22
  import * as Effect from "effect/Effect"
6
23
  import * as Layer from "effect/Layer"
7
- import * as ServiceMap from "effect/ServiceMap"
8
24
 
9
25
  const TypeId = "~@effect/platform-browser/Clipboard"
10
26
  const ErrorTypeId = "~@effect/platform-browser/Clipboard/ClipboardError"
11
27
 
12
28
  /**
13
- * @since 1.0.0
14
- * @category Models
29
+ * Service interface for reading from, writing to, and clearing the browser clipboard.
30
+ *
31
+ * @category models
32
+ * @since 4.0.0
15
33
  */
16
34
  export interface Clipboard {
17
35
  readonly [TypeId]: typeof TypeId
@@ -24,8 +42,10 @@ export interface Clipboard {
24
42
  }
25
43
 
26
44
  /**
27
- * @since 1.0.0
28
- * @category Errors
45
+ * Tagged error raised when a browser clipboard operation fails.
46
+ *
47
+ * @category errors
48
+ * @since 4.0.0
29
49
  */
30
50
  export class ClipboardError extends Data.TaggedError("ClipboardError")<{
31
51
  readonly message: string
@@ -35,14 +55,18 @@ export class ClipboardError extends Data.TaggedError("ClipboardError")<{
35
55
  }
36
56
 
37
57
  /**
38
- * @since 1.0.0
39
- * @category Service
58
+ * Service tag for the browser `Clipboard` service.
59
+ *
60
+ * @category services
61
+ * @since 4.0.0
40
62
  */
41
- export const Clipboard: ServiceMap.Service<Clipboard, Clipboard> = ServiceMap.Service<Clipboard>(TypeId)
63
+ export const Clipboard: Context.Service<Clipboard, Clipboard> = Context.Service<Clipboard>(TypeId)
42
64
 
43
65
  /**
44
- * @since 1.0.0
45
- * @category Constructors
66
+ * Builds a `Clipboard` service from primitive read and write operations, deriving `clear` and `writeBlob` helpers.
67
+ *
68
+ * @category constructors
69
+ * @since 4.0.0
46
70
  */
47
71
  export const make = (
48
72
  impl: Omit<Clipboard, "clear" | "writeBlob" | typeof TypeId>
@@ -57,8 +81,8 @@ export const make = (
57
81
  /**
58
82
  * A layer that directly interfaces with the navigator.clipboard api
59
83
  *
60
- * @since 1.0.0
61
- * @category Layers
84
+ * @category layers
85
+ * @since 4.0.0
62
86
  */
63
87
  export const layer: Layer.Layer<Clipboard> = Layer.succeed(
64
88
  Clipboard,
@@ -1,20 +1,38 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Browser geolocation support for Effect programs.
3
+ *
4
+ * This module provides a `Geolocation` service and browser-backed layer for
5
+ * reading device location through `navigator.geolocation`. Use
6
+ * `getCurrentPosition` when an application needs one location fix, such as a
7
+ * nearby-search, check-in, or delivery estimate, and `watchPosition` when it
8
+ * needs a stream of updates for navigation, tracking, or location-aware UI.
9
+ *
10
+ * The implementation is browser-only and relies on the browser permission and
11
+ * policy model for geolocation. Calls may prompt the user, fail when permission
12
+ * is denied, time out, or report that position data is unavailable because of
13
+ * device, browser, privacy, origin, or secure-context restrictions. Watched
14
+ * positions are scoped so the underlying browser watch is cleared when the
15
+ * stream is finalized, and slow consumers should account for the sliding
16
+ * buffer used by `watchPosition`.
17
+ *
18
+ * @since 4.0.0
3
19
  */
4
20
  import * as Cause from "effect/Cause"
21
+ import * as Context from "effect/Context"
5
22
  import * as Data from "effect/Data"
6
23
  import * as Effect from "effect/Effect"
7
24
  import * as Layer from "effect/Layer"
8
25
  import * as Queue from "effect/Queue"
9
- import * as ServiceMap from "effect/ServiceMap"
10
26
  import * as Stream from "effect/Stream"
11
27
 
12
28
  const TypeId = "~@effect/platform-browser/Geolocation"
13
29
  const ErrorTypeId = "~@effect/platform-browser/Geolocation/GeolocationError"
14
30
 
15
31
  /**
16
- * @since 1.0.0
17
- * @category Models
32
+ * Service interface for browser geolocation, providing effects for the current position and streams of watched positions.
33
+ *
34
+ * @category models
35
+ * @since 4.0.0
18
36
  */
19
37
  export interface Geolocation {
20
38
  readonly [TypeId]: typeof TypeId
@@ -31,14 +49,18 @@ export interface Geolocation {
31
49
  }
32
50
 
33
51
  /**
34
- * @since 1.0.0
35
- * @category Service
52
+ * Service tag for the browser `Geolocation` service.
53
+ *
54
+ * @category services
55
+ * @since 4.0.0
36
56
  */
37
- export const Geolocation: ServiceMap.Service<Geolocation, Geolocation> = ServiceMap.Service<Geolocation>(TypeId)
57
+ export const Geolocation: Context.Service<Geolocation, Geolocation> = Context.Service<Geolocation>(TypeId)
38
58
 
39
59
  /**
40
- * @since 1.0.0
41
- * @category Errors
60
+ * Tagged error wrapping a browser geolocation failure reason.
61
+ *
62
+ * @category errors
63
+ * @since 4.0.0
42
64
  */
43
65
  export class GeolocationError extends Data.TaggedError("GeolocationError")<{
44
66
  readonly reason: GeolocationErrorReason
@@ -60,8 +82,10 @@ export class GeolocationError extends Data.TaggedError("GeolocationError")<{
60
82
  }
61
83
 
62
84
  /**
63
- * @since 1.0.0
64
- * @category Errors
85
+ * Error reason for the browser geolocation `POSITION_UNAVAILABLE` failure.
86
+ *
87
+ * @category errors
88
+ * @since 4.0.0
65
89
  */
66
90
  export class PositionUnavailable extends Data.TaggedError("PositionUnavailable")<{
67
91
  readonly cause: unknown
@@ -72,8 +96,10 @@ export class PositionUnavailable extends Data.TaggedError("PositionUnavailable")
72
96
  }
73
97
 
74
98
  /**
75
- * @since 1.0.0
76
- * @category Errors
99
+ * Error reason for the browser geolocation `PERMISSION_DENIED` failure.
100
+ *
101
+ * @category errors
102
+ * @since 4.0.0
77
103
  */
78
104
  export class PermissionDenied extends Data.TaggedError("PermissionDenied")<{
79
105
  readonly cause: unknown
@@ -84,8 +110,10 @@ export class PermissionDenied extends Data.TaggedError("PermissionDenied")<{
84
110
  }
85
111
 
86
112
  /**
87
- * @since 1.0.0
88
- * @category Errors
113
+ * Error reason for the browser geolocation `TIMEOUT` failure.
114
+ *
115
+ * @category errors
116
+ * @since 4.0.0
89
117
  */
90
118
  export class Timeout extends Data.TaggedError("Timeout")<{
91
119
  readonly cause: unknown
@@ -96,8 +124,10 @@ export class Timeout extends Data.TaggedError("Timeout")<{
96
124
  }
97
125
 
98
126
  /**
99
- * @since 1.0.0
100
- * @category Errors
127
+ * Union of browser geolocation error reasons represented by the service.
128
+ *
129
+ * @category errors
130
+ * @since 4.0.0
101
131
  */
102
132
  export type GeolocationErrorReason = PositionUnavailable | PermissionDenied | Timeout
103
133
 
@@ -141,8 +171,10 @@ const makeQueue = (
141
171
  )
142
172
 
143
173
  /**
144
- * @since 1.0.0
145
- * @category Layers
174
+ * Layer that provides `Geolocation` using `navigator.geolocation`, with watched positions buffered in a sliding queue.
175
+ *
176
+ * @category layers
177
+ * @since 4.0.0
146
178
  */
147
179
  export const layer: Layer.Layer<Geolocation> = Layer.succeed(
148
180
  Geolocation,
@@ -162,8 +194,10 @@ export const layer: Layer.Layer<Geolocation> = Layer.succeed(
162
194
  )
163
195
 
164
196
  /**
165
- * @since 1.0.0
197
+ * Streams positions from the `Geolocation` service using `watchPosition`, with an optional sliding buffer size.
198
+ *
166
199
  * @category Accessors
200
+ * @since 4.0.0
167
201
  */
168
202
  export const watchPosition = (
169
203
  options?:
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Browser IndexedDB primitives and key schemas for Effect applications.
3
+ *
4
+ * This module is the low-level bridge used by the platform-browser IndexedDB
5
+ * integration. It provides an `IndexedDb` service around the browser
6
+ * `indexedDB` factory and `IDBKeyRange` constructor, a `layerWindow` layer for
7
+ * wiring those primitives from `window`, and schemas for the key shapes accepted
8
+ * by IndexedDB object stores and indexes.
9
+ *
10
+ * Use it when building typed local persistence for browser caches,
11
+ * offline-first state, background queues, drafts, or other client-side data
12
+ * that should be validated before it reaches IndexedDB. Higher-level database,
13
+ * version, table, and query modules build on these primitives for migrations
14
+ * and typed transactions.
15
+ *
16
+ * IndexedDB still follows the browser rules: schema changes happen only during
17
+ * version upgrades, upgrades may be blocked by other open tabs or connections,
18
+ * and reads or writes must run in transactions scoped to the object stores they
19
+ * touch. The `layerWindow` constructor should be used only where browser
20
+ * globals are available, and code that also runs during SSR or in restricted
21
+ * browser contexts should account for `indexedDB` or `IDBKeyRange` being
22
+ * missing.
23
+ *
24
+ * @since 4.0.0
25
+ */
26
+ import * as Context from "effect/Context"
27
+ import * as Effect from "effect/Effect"
28
+ import * as Layer from "effect/Layer"
29
+ import * as Schema from "effect/Schema"
30
+
31
+ const TypeId = "~@effect/platform-browser/IndexedDb"
32
+
33
+ /**
34
+ * Service interface that provides the browser `indexedDB` factory and `IDBKeyRange` constructor.
35
+ *
36
+ * @category models
37
+ * @since 4.0.0
38
+ */
39
+ export interface IndexedDb {
40
+ readonly [TypeId]: typeof TypeId
41
+ readonly indexedDB: globalThis.IDBFactory
42
+ readonly IDBKeyRange: typeof globalThis.IDBKeyRange
43
+ }
44
+
45
+ /**
46
+ * Service tag for browser IndexedDB primitives.
47
+ *
48
+ * @category tag
49
+ * @since 4.0.0
50
+ */
51
+ export const IndexedDb: Context.Service<IndexedDb, IndexedDb> = Context.Service<IndexedDb, IndexedDb>(TypeId)
52
+
53
+ /** @internal */
54
+ const IDBFlatKey = Schema.Union([
55
+ Schema.String,
56
+ Schema.Number.check(Schema.makeFilter((input) => !Number.isNaN(input))),
57
+ Schema.DateValid,
58
+ Schema.declare(
59
+ (input): input is BufferSource =>
60
+ input instanceof ArrayBuffer ||
61
+ (ArrayBuffer.isView(input) && input.buffer instanceof ArrayBuffer)
62
+ )
63
+ ])
64
+
65
+ /**
66
+ * Schema for IndexedDB keys: strings, non-NaN numbers, valid dates, buffer sources, or arrays of those flat key values.
67
+ *
68
+ * @category schemas
69
+ * @since 4.0.0
70
+ */
71
+ export const IDBValidKey = Schema.Union([IDBFlatKey, Schema.Array(IDBFlatKey)])
72
+
73
+ /**
74
+ * Schema for auto-incremented IndexedDB keys, accepting integers from 1 through `2 ** 53`.
75
+ *
76
+ * @category schemas
77
+ * @since 4.0.0
78
+ */
79
+ export const AutoIncrement = Schema.Int.check(
80
+ Schema.isBetween({ minimum: 1, maximum: 2 ** 53 })
81
+ ).annotate({
82
+ identifier: "AutoIncrement",
83
+ title: "autoIncrement",
84
+ description: "Defines a valid autoIncrement key path for the IndexedDb table"
85
+ })
86
+
87
+ /**
88
+ * Creates an `IndexedDb` service from an `IDBFactory` and `IDBKeyRange` constructor.
89
+ *
90
+ * @category constructors
91
+ * @since 4.0.0
92
+ */
93
+ export const make = (impl: Omit<IndexedDb, typeof TypeId>): IndexedDb => IndexedDb.of({ [TypeId]: TypeId, ...impl })
94
+
95
+ /**
96
+ * Layer that provides `IndexedDb` from `window.indexedDB` and `window.IDBKeyRange`, failing with a config error when they are unavailable.
97
+ *
98
+ * @category constructors
99
+ * @since 4.0.0
100
+ */
101
+ export const layerWindow: Layer.Layer<IndexedDb> = Layer.effect(
102
+ IndexedDb,
103
+ Effect.suspend(() => {
104
+ if (window.indexedDB && window.IDBKeyRange) {
105
+ return Effect.succeed(
106
+ make({
107
+ indexedDB: window.indexedDB,
108
+ IDBKeyRange: window.IDBKeyRange
109
+ })
110
+ )
111
+ } else {
112
+ return Effect.die(new Error("window.indexedDB is not available"))
113
+ }
114
+ })
115
+ )