Skip to content

Commit 92d56a5

Browse files
committed
feat(effect-svelte): init
Signed-off-by: Eric Hegnes <[email protected]>
1 parent 7245f96 commit 92d56a5

33 files changed

+1476
-45
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,9 @@ docs/src/content/docs/reference/@unionlabs/sdk-evm
122122
docs/src/content/docs/reference/@unionlabs/sdk-cosmos
123123
docs/src/content/docs/integrations/typescript/examples/*
124124
!docs/src/content/docs/integrations/typescript/examples/index.mdx
125+
126+
# effect-svelte
127+
effect-svelte/build
128+
129+
# vitest
130+
coverage/

app2/app2.nix

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,21 @@ _: {
3232
packageJsonPath = ./package.json;
3333
extraSrcs = [
3434
../app2
35+
../effect-svelte
3536
../ts-sdk
36-
../ts-sdk-evm
3737
../ts-sdk-cosmos
38+
../ts-sdk-evm
3839
../ts-sdk-sui
3940
];
40-
hash = "sha256-VkzzXZr7WNTSE8pBOcLLd9vZThjFqsSJaEKwb7bi4PY=";
41+
hash = "sha256-SQZGMqbhiWyJdWluVYCpdTjMvZ9duKZQXJtCxMPO6Cg=";
4142
buildInputs = deps;
4243
nativeBuildInputs = buildInputs;
4344
pnpmWorkspaces = [
4445
"app2"
46+
"@unionlabs/effect-svelte"
4547
"@unionlabs/sdk"
46-
"@unionlabs/sdk-evm"
4748
"@unionlabs/sdk-cosmos"
49+
"@unionlabs/sdk-evm"
4850
"@unionlabs/sdk-sui"
4951
];
5052
buildPhase = ''
@@ -55,7 +57,7 @@ _: {
5557
export PUBLIC_LAST_MODIFIED_EPOCH="${PUBLIC_LAST_MODIFIED_EPOCH}"
5658
export PUBLIC_SUPABASE_URL="${PUBLIC_SUPABASE_URL}"
5759
export PUBLIC_SUPABASE_ANON_KEY="${PUBLIC_SUPABASE_ANON_KEY}"
58-
pnpm --filter=app2 prepare
60+
pnpm --filter=app2 --filter=effect-svelte prepare
5961
pnpm --filter=app2 build
6062
runHook postBuild
6163
'';

app2/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"@testing-library/jest-dom": "^6.6.3",
4646
"@testing-library/svelte": "catalog:svelte",
4747
"@types/node": "24.6.1",
48+
"@unionlabs/effect-svelte": "workspace:*",
4849
"@unionlabs/sdk": "workspace:*",
4950
"@unionlabs/sdk-cosmos": "workspace:*",
5051
"@unionlabs/sdk-evm": "workspace:*",

app2/src/lib/runtime.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { runForkWithRuntime, runPromiseExitWithRuntime } from "$lib/utils/effect.svelte.js"
1+
import { Runtime } from "@unionlabs/effect-svelte"
22
import type { PriceOracle } from "@unionlabs/sdk/PriceOracle"
33
import { Layer, ManagedRuntime, Match, pipe } from "effect"
44
import { isNotUndefined } from "effect/Predicate"
@@ -32,8 +32,8 @@ const make = async () => {
3232

3333
const runtime = await _runtime()
3434

35-
const runFork$ = runForkWithRuntime(runtime)
36-
const runPromiseExit$ = runPromiseExitWithRuntime(runtime)
35+
const runFork$ = Runtime.runForkWithRuntime(runtime)
36+
const runPromiseExit$ = Runtime.runPromiseExitWithRuntime(runtime)
3737

3838
return {
3939
runFork$,

app2/src/lib/stores/fee.svelte.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ import { AtomicGasPrice, BaseGasPrice, GasPrice } from "$lib/gasprice/service"
44
import { chainInfoMap } from "$lib/services/cosmos/chain-info/config"
55
import { transferData as TransferData } from "$lib/transfer/shared/data/transfer-data.svelte"
66
import type { Intent } from "$lib/transfer/shared/services/filling/create-context"
7-
import * as Writer from "$lib/typeclass/Writer.js"
87
import * as ArrayInstances from "@effect/typeclass/data/Array"
98
import * as FlatMap from "@effect/typeclass/FlatMap"
109
import { Token } from "@unionlabs/sdk"
1110
import { GAS_DENOMS } from "@unionlabs/sdk/Constants"
1211
import { VIEM_CHAINS } from "@unionlabs/sdk/constants/viem-chains"
1312
import { PriceError, PriceOracle, PriceResult } from "@unionlabs/sdk/PriceOracle"
14-
import { Chain, TokenRawAmount } from "@unionlabs/sdk/schema"
1513
import { type Fees, GasFee } from "@unionlabs/sdk/schema/fee"
14+
import { Chain, TokenRawAmount } from "@unionlabs/sdk/schema/index"
15+
import * as Writer from "@unionlabs/sdk/typeclass/Writer"
1616
import {
1717
Array as A,
1818
BigDecimal,

app2/src/lib/transfer/shared/components/ChainAsset/RepresentationSelector.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script lang="ts">
22
import Truncate from "$lib/components/ui/Truncate.svelte"
3-
import { mapOption } from "$lib/utils/snippets.svelte"
4-
import { TokenWrapping } from "@unionlabs/sdk/schema"
3+
import { Snippets } from "@unionlabs/effect-svelte"
4+
import { TokenWrapping } from "@unionlabs/sdk/schema/token"
55
import { Option } from "effect"
66
import { transferData } from "../../data/transfer-data.svelte"
77
@@ -46,6 +46,6 @@ const onSelect = (wrapping: TokenWrapping) => {
4646
contract address of the asset you want to receive.
4747
</div>
4848
<div class="flex flex-col">
49-
{@render mapOption(transferData.representations, renderWrappings)}
49+
{@render Snippets.mapOption(transferData.representations, renderWrappings)}
5050
</div>
5151
</div>

app2/src/lib/transfer/shared/components/FeeDetails.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Tooltip from "$lib/components/ui/Tooltip.svelte"
99
import * as AppRuntime from "$lib/runtime"
1010
import { FeeStore } from "$lib/stores/fee.svelte"
1111
import { cn } from "$lib/utils"
12-
import { getOptionOrNull, mapOption } from "$lib/utils/snippets.svelte"
12+
import { Snippets } from "@unionlabs/effect-svelte"
1313
import { PriceSource } from "@unionlabs/sdk/PriceOracle"
1414
import { Array as A, BigDecimal as BD, Boolean as B, Option as O, Record as R } from "effect"
1515
import { onDestroy } from "svelte"
@@ -87,7 +87,7 @@ const calculating = false
8787
{/snippet}
8888

8989
{#snippet gasTokenSymbol()}
90-
{@render getOptionOrNull(FeeStore.symbol)}
90+
{@render Snippets.getOptionOrNull(FeeStore.symbol)}
9191
{/snippet}
9292

9393
<!-- NOTE: presently only **BOB -> BABYLON** and **BABYLON -> BOB** -->
@@ -118,7 +118,7 @@ const calculating = false
118118
<Skeleton class="h-3 w-26" />
119119
<Skeleton class="h-3 w-12" />
120120
{:else}
121-
{@render mapOption(
121+
{@render Snippets.mapOption(
122122
O.all({
123123
value: FeeStore.feeDisplay,
124124
symbol: FeeStore.symbol,

app2/svelte.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ const config = {
2020
alias: {
2121
"@unionlabs/sdk": "../ts-sdk/src/index.js",
2222
"@unionlabs/sdk/*": "../ts-sdk/src/*",
23+
"@unionlabs/sdk-evm": "../ts-sdk-evm/src/index.js",
24+
"@unionlabs/sdk-evm/*": "../ts-sdk-evm/src/*",
25+
"@unionlabs/sdk-cosmos": "../ts-sdk-cosmos/src/index.js",
26+
"@unionlabs/sdk-cosmos/*": "../ts-sdk-cosmos/src/*",
27+
"@unionlabs/effect-svelte": "../effect-svelte/src/lib/index.js",
28+
"@unionlabs/effect-svelte/*": "../ts-sdk-cosmos/src/lib/*",
2329
},
2430
},
2531
}

effect-svelte/README.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Union Svelte + Effect Library
2+
3+
> \[!CAUTION\]
4+
> This package is experimental and subject to breaking changes.
5+
6+
## Modules
7+
8+
- `Runtime`: Provides management of Effect runtime in Svelte components and reactive rune-like Effect execution.
9+
- `Snippets`: Provides Svelte snippets to perform matching on common Effect ADTs (e.g. `Option`, `Either`, `Exit`, etc.)
10+
- `SvelteConfigProvider`: Provides [`ConfigProvider`](https://effect-ts.github.io/effect/effect/ConfigProvider.ts.html#configprovider) for common SvelteKit environment patterns.
11+
12+
## Getting Started
13+
14+
In lieu of a known alterative, it is suggested to initialize the runtime as a module singleton and to trigger construction in a client hook.
15+
16+
### Runtime Definition
17+
18+
Define layers and re-export helper functions.
19+
20+
`src/lib/runtime.ts`
21+
22+
```ts
23+
import { Runtime } from "@unionlabs/effect-svelte"
24+
import { Layer, ManagedRuntime, Match, Predicate, pipe } from "effect"
25+
26+
/**
27+
* Ensure "vitest/importMeta" is defined in `tsconfig.json` "types".
28+
*/
29+
const IS_VITEST = Predicate.isNotUndefined(import.meta.vitest)
30+
31+
type AppLayer = Layer.Layer<never, never, never>
32+
export type AppContext = Layer.Layer.Success<AppLayer>
33+
34+
const make = async () => {
35+
const AppLayer = (
36+
await pipe(
37+
Match.value(IS_VITEST),
38+
Match.when(true, () => import("$lib/layers/test.js")),
39+
Match.when(false, () => import("$lib/layers/live.js")),
40+
Match.exhaustive
41+
)
42+
).default satisfies AppLayer
43+
44+
const {
45+
runFork,
46+
runPromise,
47+
runPromiseExit,
48+
runSync,
49+
runSyncExit,
50+
runtime: _runtime
51+
} = ManagedRuntime.make(AppLayer)
52+
53+
const runtime = await _runtime()
54+
55+
const runFork$ = Runtime.runForkWithRuntime(runtime)
56+
const runPromiseExit$ = Runtime.runPromiseExitWithRuntime(runtime)
57+
58+
return {
59+
runFork$,
60+
runFork,
61+
runPromise,
62+
runPromiseExit$,
63+
runPromiseExit,
64+
runSync,
65+
runSyncExit,
66+
} as const
67+
}
68+
69+
type Runtime = Awaited<ReturnType<typeof make>>
70+
71+
/** @public */
72+
export let runFork$: Runtime["runFork$"]
73+
/** @public */
74+
export let runFork: Runtime["runFork"]
75+
/** @public */
76+
export let runPromise: Runtime["runPromise"]
77+
/** @public */
78+
export let runPromiseExit$: Runtime["runPromiseExit$"]
79+
/** @public */
80+
export let runPromiseExit: Runtime["runPromiseExit"]
81+
/** @public */
82+
export let runSync: Runtime["runSync"]
83+
/** @public */
84+
export let runSyncExit: Runtime["runSyncExit"]
85+
86+
/** @public */
87+
export const __init = async () => {
88+
const runtime = await make()
89+
;({
90+
runFork$,
91+
runFork,
92+
runPromise,
93+
runPromiseExit$,
94+
runPromiseExit,
95+
runSync,
96+
runSyncExit
97+
} = runtime)
98+
}
99+
```
100+
101+
### Runtime Initialization
102+
103+
This client hook guarantees that the Effect runtime is initalized as early as possbile.
104+
105+
`src/hooks.client.ts`:
106+
107+
```ts
108+
import type { ClientInit } from "@sveltejs/kit"
109+
110+
export const init: ClientInit = async () => {
111+
await import("$lib/runtime.js").then((_) => _.__init())
112+
}
113+
```
114+
115+
### Usage
116+
117+
See [test cases](https://github.com/unionlabs/union/blob/main/effect-svelte/lib/test/Runtime.test.ts) for inspiration.

effect-svelte/effect-svelte.nix

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
_: {
2+
perSystem =
3+
{
4+
pkgs,
5+
lib,
6+
self',
7+
...
8+
}:
9+
let
10+
buildPnpmPackage = import ../tools/typescript/buildPnpmPackage.nix {
11+
inherit pkgs lib;
12+
};
13+
in
14+
{
15+
packages = {
16+
effect-svelte = buildPnpmPackage {
17+
packageJsonPath = ./package.json;
18+
extraSrcs = [ ../effect-svelte ];
19+
pnpmWorkspaces = [ "@unionlabs/effect-svelte" ];
20+
hash = "sha256-ORcfyxx5Llp+wXYa0BsZW1SV7cBXbPJ/84KgaZWLxQs=";
21+
doCheck = true;
22+
buildPhase = ''
23+
runHook preBuild
24+
pnpm --filter=@unionlabs/effect-svelte build
25+
runHook postBuild
26+
'';
27+
installPhase = ''
28+
mkdir -p $out
29+
cp -r ./effect-svelte/* $out
30+
'';
31+
checkPhase = ''
32+
pnpm --filter=@unionlabs/effect-svelte check
33+
pnpm --filter=@unionlabs/effect-svelte test
34+
'';
35+
};
36+
};
37+
apps = {
38+
publish-effect-svelte = {
39+
type = "app";
40+
program = pkgs.writeShellApplication {
41+
name = "publish-effect-svelte";
42+
text = ''
43+
cd ${self'.packages.effect-svelte}/
44+
${pkgs.pnpm}/bin/pnpm publish --access='public'
45+
'';
46+
};
47+
};
48+
};
49+
};
50+
}

0 commit comments

Comments
 (0)