Use WoofWare.Myriad entirely to generate the REST API (#9)
All checks were successful
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/push/all-checks-complete Pipeline was successful

Co-authored-by: Smaug123 <patrick+github@patrickstevens.co.uk>
Reviewed-on: #9
This commit is contained in:
2024-01-30 00:17:45 +00:00
parent 58fdb23719
commit e96ae78665
15 changed files with 306 additions and 119 deletions

View File

@@ -1,5 +1,6 @@
namespace PureGym.App
open System.Threading
open Argu
open System
open PureGym
@@ -50,7 +51,7 @@ module Authenticate =
let run (creds : UsernamePin) =
task {
let! cred = AuthToken.get creds
let! cred = AuthToken.get creds CancellationToken.None
Console.WriteLine cred.AccessToken
match cred.ExpiryTime with

View File

@@ -1,5 +1,6 @@
namespace PureGym.App
open System.Threading
open Argu
open PureGym
@@ -48,7 +49,7 @@ module Fullness =
let run (args : FullnessArgs) =
task {
let! client = Api.make args.Creds
let! client = Api.makeWithoutRefresh CancellationToken.None args.Creds
let! id = GymSelector.canonicalId client args.Gym
let! attendance = client.GetGymAttendance id

View File

@@ -1,5 +1,6 @@
namespace PureGym.App
open System.Threading
open Argu
open PureGym
@@ -44,7 +45,7 @@ module LookupGym =
let run (args : LookupGymArgs) =
task {
let! client = Api.make args.Creds
let! client = Api.makeWithoutRefresh CancellationToken.None args.Creds
let! s = client.GetGym 19
System.Console.WriteLine (string<Gym> s)
return 0

View File

@@ -1,5 +1,6 @@
namespace PureGym.App
open System.Threading
open Argu
open PureGym
@@ -31,7 +32,7 @@ module MemberActivity =
let run (args : MemberActivityArgs) =
task {
let! client = Api.make args.Creds
let! client = Api.makeWithoutRefresh CancellationToken.None args.Creds
let! activity = client.GetMemberActivity ()
let activity = activity.ToMemberActivity ()
System.Console.WriteLine (string<MemberActivityThisMonth> activity)

View File

@@ -1,5 +1,6 @@
namespace PureGym.App
open System.Threading
open Argu
open PureGym
open System
@@ -41,7 +42,7 @@ module Sessions =
let run (args : SessionsArgs) =
task {
let! client = Api.make args.Creds
let! client = Api.makeWithoutRefresh CancellationToken.None args.Creds
let! activity = client.GetSessions (args.FromDate, args.ToDate)
System.Console.WriteLine (string<Sessions> activity)

View File

@@ -2,26 +2,42 @@ namespace PureGym
open System
open System.Net.Http
open System.Threading
open System.Threading.Tasks
/// Methods for interacting with the PureGym REST API.
[<RequireQualifiedAccess>]
module Api =
/// Create a REST client, authenticated as the specified user.
let make (auth : Auth) : IPureGymApi Task =
/// Create a REST client, authenticated as the specified user. Creds will be refreshed if possible as long as
/// the returned disposable is not disposed.
let make (auth : Auth) : (IPureGymApi * IDisposable) Task =
let cache, getToken =
match auth with
| Auth.Token t ->
{ new IDisposable with
member _.Dispose () = ()
},
fun () -> t
| Auth.User cred ->
let cache = new Cache<_> (AuthToken.get cred, _.ExpiryTime)
cache :> _, (fun () -> Async.RunSynchronously (cache.GetCurrentValue ()))
task {
let client = new HttpClient ()
return PureGymApi.make (getToken >> _.AccessToken >> sprintf "Bearer %s") client, cache
}
/// Create a REST client, authenticated as the specified user. Do not refresh creds.
let makeWithoutRefresh (ct : CancellationToken) (auth : Auth) : IPureGymApi Task =
task {
let! token =
match auth with
| Auth.Token t -> Task.FromResult<_> t
| Auth.User cred -> AuthToken.get cred
| Auth.User cred -> AuthToken.get cred ct
let client = new HttpClient ()
client.BaseAddress <- Uri "https://capi.puregym.com/api/"
client.DefaultRequestHeaders.Authorization <-
Headers.AuthenticationHeaderValue ("Bearer", token.AccessToken)
client.DefaultRequestHeaders.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
return PureGymApi.make client
return PureGymApi.make (fun () -> $"Bearer %s{token.AccessToken}") client
}

View File

@@ -5,6 +5,7 @@ open System.Collections.Generic
open System.Net.Http
open System.Text.Json
open System.Text.Json.Serialization
open System.Threading
open System.Threading.Tasks
// System.Text.Json does not support internal F# records as of .NET 8, presumably because it can't find the constructor.
@@ -72,8 +73,9 @@ module AuthToken =
let private options = JsonSerializerOptions (IncludeFields = true)
/// Get an AuthToken for the given user email address with the given eight-digit PureGym PIN.
let get (creds : UsernamePin) : Task<AuthToken> =
task {
let get (creds : UsernamePin) (ct : CancellationToken) : Task<AuthToken> =
async {
let! ct = Async.CancellationToken
use client = new HttpClient ()
client.BaseAddress <- Uri "https://auth.puregym.com"
client.DefaultRequestHeaders.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
@@ -89,14 +91,21 @@ module AuthToken =
|> List.map KeyValuePair
use content = new FormUrlEncodedContent (request)
let! response = client.PostAsync (Uri "https://auth.puregym.com/connect/token", content)
let! response =
Async.AwaitTask (
client.PostAsync (Uri "https://auth.puregym.com/connect/token", content, cancellationToken = ct)
)
if response.IsSuccessStatusCode then
let! content = response.Content.ReadAsStreamAsync ()
let! response = JsonSerializer.DeserializeAsync<AuthResponseRaw> (content, options)
// let! response = JsonSerializer.DeserializeAsync<AuthResponseRaw> (content, options)
let! content = Async.AwaitTask (response.Content.ReadAsStreamAsync ct)
let! response =
Async.AwaitTask (JsonSerializer.DeserializeAsync<AuthResponseRaw>(content, options, ct).AsTask ())
return AuthToken.Parse response
else
let! content = response.Content.ReadAsStringAsync ()
let! content = Async.AwaitTask (response.Content.ReadAsStringAsync ct)
return failwithf $"bad status code: %+A{response.StatusCode}\n%s{content}"
}
|> fun a -> Async.StartAsTask (a, cancellationToken = ct)

85
PureGym/Cache.fs Normal file
View File

@@ -0,0 +1,85 @@
namespace PureGym
open System
open System.Threading
open System.Threading.Tasks
type private CacheMessage<'a> =
| TriggerUpdate
| UpdateStored of 'a Task
| Get of AsyncReplyChannel<'a>
| Quit of AsyncReplyChannel<unit>
type internal Cache<'a> (obtainNew : CancellationToken -> 'a Task, expiry : 'a -> DateTime option) =
let cts = new CancellationTokenSource ()
let initialValue = obtainNew cts.Token
let rec handle (value : 'a Task) (mailbox : MailboxProcessor<CacheMessage<'a>>) : Async<unit> =
async {
let! message = mailbox.Receive ()
match message with
| Quit channel ->
channel.Reply ()
return ()
| CacheMessage.UpdateStored newValue -> return! handle newValue mailbox
| CacheMessage.TriggerUpdate ->
async {
let! a = Async.AwaitTask (obtainNew cts.Token)
let expiry = expiry a
match expiry with
| None -> return ()
| Some expiry ->
// a bit sloppy but :shrug:
do! Async.Sleep ((expiry - DateTime.Now) - TimeSpan.FromMinutes 1.0)
try
mailbox.Post CacheMessage.TriggerUpdate
with _ ->
// Post during shutdown sequence: drop it on the floor
()
return ()
}
|> fun a -> Async.Start (a, cancellationToken = cts.Token)
return! handle value mailbox
| CacheMessage.Get reply ->
let! valueAwaited = Async.AwaitTask value
reply.Reply valueAwaited
return! handle value mailbox
}
let mailbox = new MailboxProcessor<_> (handle initialValue)
do
mailbox.Start ()
mailbox.Post CacheMessage.TriggerUpdate
let isDisposing = ref 0
let hasDisposed = TaskCompletionSource<unit> ()
member this.GetCurrentValue () =
try
mailbox.PostAndAsyncReply CacheMessage.Get
with
// TODO I think this is the right exception...
| :? InvalidOperationException ->
raise (ObjectDisposedException (nameof (Cache)))
interface IDisposable with
member _.Dispose () =
if Interlocked.Increment isDisposing = 1 then
mailbox.PostAndReply CacheMessage.Quit
(mailbox :> IDisposable).Dispose ()
// We can't terminate the CTS until the mailbox has processed all client requests.
// Otherwise we terminate the mailbox's state Task before it has finished querying that
// task on behalf of clients.
cts.Cancel ()
cts.Dispose ()
hasDisposed.SetResult ()
else
hasDisposed.Task.Result

View File

@@ -9,7 +9,11 @@ open RestEase
/// The PureGym REST API. You probably want to instantiate one of these with `Api.make`.
[<WoofWare.Myriad.Plugins.HttpClient>]
[<Header("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")>]
[<BaseAddress "https://capi.puregym.com/api/">]
type IPureGymApi =
[<Header "Authorization">]
abstract AuthHeader : string
/// Get the complete list of all gyms known to PureGym.
[<Get "v1/gyms/">]
abstract GetGyms : ?ct : CancellationToken -> Task<Gym list>

View File

@@ -4,6 +4,8 @@
//------------------------------------------------------------------------------
namespace PureGym
open System
@@ -16,23 +18,19 @@ open RestEase
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<RequireQualifiedAccess>]
module PureGymApi =
/// Create a REST client.
let make (client : System.Net.Http.HttpClient) : IPureGymApi =
/// Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties.
let make (authHeader : unit -> string) (client : System.Net.Http.HttpClient) : IPureGymApi =
{ new IPureGymApi with
member _.GetGyms (ct : CancellationToken option) =
member _.AuthHeader : string = authHeader ()
member this.GetGyms (ct : CancellationToken option) =
async {
let! ct = Async.CancellationToken
let uri =
System.Uri (
(match client.BaseAddress with
| null ->
raise (
System.ArgumentNullException (
nameof (client.BaseAddress),
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
)
)
| null -> System.Uri "https://capi.puregym.com/api/"
| v -> v),
System.Uri ("v1/gyms/", System.UriKind.Relative)
)
@@ -43,32 +41,28 @@ module PureGymApi =
RequestUri = uri
)
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct)
let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask
return node.AsArray () |> Seq.map (fun elt -> Gym.jsonParse elt) |> List.ofSeq
return jsonNode.AsArray () |> Seq.map (fun elt -> Gym.jsonParse elt) |> List.ofSeq
}
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
member _.GetMember (ct : CancellationToken option) =
member this.GetMember (ct : CancellationToken option) =
async {
let! ct = Async.CancellationToken
let uri =
System.Uri (
(match client.BaseAddress with
| null ->
raise (
System.ArgumentNullException (
nameof (client.BaseAddress),
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
)
)
| null -> System.Uri "https://capi.puregym.com/api/"
| v -> v),
System.Uri ("v1/member", System.UriKind.Relative)
)
@@ -79,32 +73,28 @@ module PureGymApi =
RequestUri = uri
)
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct)
let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask
return Member.jsonParse node
return Member.jsonParse jsonNode
}
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
member _.GetGymAttendance (gymId : int, ct : CancellationToken option) =
member this.GetGymAttendance (gymId : int, ct : CancellationToken option) =
async {
let! ct = Async.CancellationToken
let uri =
System.Uri (
(match client.BaseAddress with
| null ->
raise (
System.ArgumentNullException (
nameof (client.BaseAddress),
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
)
)
| null -> System.Uri "https://capi.puregym.com/api/"
| v -> v),
System.Uri (
"v1/gyms/{gym_id}/attendance"
@@ -119,32 +109,28 @@ module PureGymApi =
RequestUri = uri
)
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct)
let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask
return GymAttendance.jsonParse node
return GymAttendance.jsonParse jsonNode
}
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
member _.GetGym (gymId : int, ct : CancellationToken option) =
member this.GetGym (gymId : int, ct : CancellationToken option) =
async {
let! ct = Async.CancellationToken
let uri =
System.Uri (
(match client.BaseAddress with
| null ->
raise (
System.ArgumentNullException (
nameof (client.BaseAddress),
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
)
)
| null -> System.Uri "https://capi.puregym.com/api/"
| v -> v),
System.Uri (
"v1/gyms/{gym_id}"
@@ -159,32 +145,28 @@ module PureGymApi =
RequestUri = uri
)
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct)
let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask
return Gym.jsonParse node
return Gym.jsonParse jsonNode
}
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
member _.GetMemberActivity (ct : CancellationToken option) =
member this.GetMemberActivity (ct : CancellationToken option) =
async {
let! ct = Async.CancellationToken
let uri =
System.Uri (
(match client.BaseAddress with
| null ->
raise (
System.ArgumentNullException (
nameof (client.BaseAddress),
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
)
)
| null -> System.Uri "https://capi.puregym.com/api/"
| v -> v),
System.Uri ("v1/member/activity", System.UriKind.Relative)
)
@@ -195,32 +177,28 @@ module PureGymApi =
RequestUri = uri
)
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct)
let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask
return MemberActivityDto.jsonParse node
return MemberActivityDto.jsonParse jsonNode
}
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
member _.GetSessions (fromDate : DateOnly, toDate : DateOnly, ct : CancellationToken option) =
member this.GetSessions (fromDate : DateOnly, toDate : DateOnly, ct : CancellationToken option) =
async {
let! ct = Async.CancellationToken
let uri =
System.Uri (
(match client.BaseAddress with
| null ->
raise (
System.ArgumentNullException (
nameof (client.BaseAddress),
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
)
)
| null -> System.Uri "https://capi.puregym.com/api/"
| v -> v),
System.Uri (
("v2/gymSessions/member"
@@ -238,15 +216,17 @@ module PureGymApi =
RequestUri = uri
)
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct)
let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask
return Sessions.jsonParse node
return Sessions.jsonParse jsonNode
}
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
}

View File

@@ -3,6 +3,8 @@
// Changes to this file will be lost when the code is regenerated.
//------------------------------------------------------------------------------
namespace PureGym
/// Module containing JSON parsing methods for the GymOpeningHours type
@@ -253,9 +255,41 @@ module Gym =
.AsValue()
.GetValue<string> ()
let Location = GymLocation.jsonParse node.["location"]
let AccessOptions = GymAccessOptions.jsonParse node.["accessOptions"]
let GymOpeningHours = GymOpeningHours.jsonParse node.["gymOpeningHours"]
let Location =
GymLocation.jsonParse (
match node.["location"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("location")
)
)
| v -> v
)
let AccessOptions =
GymAccessOptions.jsonParse (
match node.["accessOptions"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("accessOptions")
)
)
| v -> v
)
let GymOpeningHours =
GymOpeningHours.jsonParse (
match node.["gymOpeningHours"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("gymOpeningHours")
)
)
| v -> v
)
let EmailAddress =
(match node.["emailAddress"] with
@@ -281,7 +315,17 @@ module Gym =
.AsValue()
.GetValue<string> ()
let Address = GymAddress.jsonParse node.["address"]
let Address =
GymAddress.jsonParse (
match node.["address"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("address")
)
)
| v -> v
)
let Status =
(match node.["status"] with
@@ -856,7 +900,17 @@ namespace PureGym
module Visit =
/// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Visit =
let Gym = VisitGym.jsonParse node.["Gym"]
let Gym =
VisitGym.jsonParse (
match node.["Gym"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("Gym")
)
)
| v -> v
)
let Duration =
(match node.["Duration"] with
@@ -909,8 +963,29 @@ namespace PureGym
module SessionsSummary =
/// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsSummary =
let ThisWeek = SessionsAggregate.jsonParse node.["ThisWeek"]
let Total = SessionsAggregate.jsonParse node.["Total"]
let ThisWeek =
SessionsAggregate.jsonParse (
match node.["ThisWeek"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("ThisWeek")
)
)
| v -> v
)
let Total =
SessionsAggregate.jsonParse (
match node.["Total"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("Total")
)
)
| v -> v
)
{
Total = Total
@@ -937,7 +1012,17 @@ module Sessions =
|> Seq.map (fun elt -> Visit.jsonParse elt)
|> List.ofSeq
let Summary = SessionsSummary.jsonParse node.["Summary"]
let Summary =
SessionsSummary.jsonParse (
match node.["Summary"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("Summary")
)
)
| v -> v
)
{
Summary = Summary

View File

@@ -6,20 +6,21 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarnOn>FS3559</WarnOn>
<WoofWareMyriadPluginVersion>1.1.13</WoofWareMyriadPluginVersion>
<WoofWareMyriadPluginVersion>1.4.8</WoofWareMyriadPluginVersion>
</PropertyGroup>
<ItemGroup>
<Compile Include="String.fs" />
<Compile Include="Auth.fs" />
<Compile Include="Dto.fs" />
<Compile Include="GeneratedDto.fs"> <!--1-->
<MyriadFile>Dto.fs</MyriadFile> <!--2-->
<Compile Include="GeneratedDto.fs">
<MyriadFile>Dto.fs</MyriadFile>
</Compile>
<Compile Include="Client.fs" />
<Compile Include="GeneratedClient.fs">
<MyriadFile>Client.fs</MyriadFile> <!--2-->
<MyriadFile>Client.fs</MyriadFile>
</Compile>
<Compile Include="Cache.fs" />
<Compile Include="Api.fs" />
<Compile Include="GymSelector.fs" />
<EmbeddedResource Include="SurfaceBaseline.txt" />
@@ -35,8 +36,7 @@
<PackageReference Update="FSharp.Core" Version="6.0.1" />
<PackageReference Include="System.Text.Json" Version="8.0.0" />
<PackageReference Include="Fastenshtein" Version="1.0.0.8" />
<PackageReference Include="Myriad.Core" Version="0.8.3" />
<PackageReference Include="Myriad.Sdk" Version="0.8.3" />
<PackageReference Include="Myriad.Sdk" Version="0.8.3" PrivateAssets="all" />
<PackageReference Include="WoofWare.Myriad.Plugins" Version="$(WoofWareMyriadPluginVersion)" />
</ItemGroup>

View File

@@ -1,3 +1,6 @@
PureGym.Api inherit obj
PureGym.Api.make [static method]: PureGym.Auth -> (PureGym.IPureGymApi * IDisposable) System.Threading.Tasks.Task
PureGym.Api.makeWithoutRefresh [static method]: System.Threading.CancellationToken -> PureGym.Auth -> PureGym.IPureGymApi System.Threading.Tasks.Task
PureGym.Auth inherit obj, implements PureGym.Auth System.IEquatable, System.Collections.IStructuralEquatable, PureGym.Auth System.IComparable, System.IComparable, System.Collections.IStructuralComparable - union type with 2 cases
PureGym.Auth+Tags inherit obj
PureGym.Auth+Tags.Token [static field]: int = 1
@@ -33,10 +36,8 @@ PureGym.AuthToken.ExpiryTime [property]: [read-only] System.DateTime option
PureGym.AuthToken.get_AccessToken [method]: unit -> string
PureGym.AuthToken.get_ExpiryTime [method]: unit -> System.DateTime option
PureGym.AuthTokenModule inherit obj
PureGym.AuthTokenModule.get [static method]: PureGym.UsernamePin -> PureGym.AuthToken System.Threading.Tasks.Task
PureGym.AuthTokenModule.get [static method]: PureGym.UsernamePin -> System.Threading.CancellationToken -> PureGym.AuthToken System.Threading.Tasks.Task
PureGym.AuthTokenModule.ofBearerToken [static method]: string -> PureGym.AuthToken
PureGym.Api inherit obj
PureGym.Api.make [static method]: PureGym.Auth -> PureGym.IPureGymApi System.Threading.Tasks.Task
PureGym.Gym inherit obj, implements PureGym.Gym System.IEquatable, System.Collections.IStructuralEquatable, PureGym.Gym System.IComparable, System.IComparable, System.Collections.IStructuralComparable
PureGym.Gym..ctor [constructor]: (string, int, int, PureGym.GymAddress, string, string, PureGym.GymOpeningHours, PureGym.GymAccessOptions, PureGym.GymLocation, string, string)
PureGym.Gym.AccessOptions [property]: [read-only] PureGym.GymAccessOptions
@@ -150,7 +151,9 @@ PureGym.GymSelector.NewName [static method]: string -> PureGym.GymSelector
PureGym.GymSelector.Tag [property]: [read-only] int
PureGym.GymSelectorModule inherit obj
PureGym.GymSelectorModule.canonicalId [static method]: PureGym.IPureGymApi -> PureGym.GymSelector -> int System.Threading.Tasks.Task
PureGym.IPureGymApi - interface with 6 member(s)
PureGym.IPureGymApi - interface with 8 member(s)
PureGym.IPureGymApi.AuthHeader [property]: [read-only] string
PureGym.IPureGymApi.get_AuthHeader [method]: unit -> string
PureGym.IPureGymApi.GetGym [method]: (int, System.Threading.CancellationToken option) -> PureGym.Gym System.Threading.Tasks.Task
PureGym.IPureGymApi.GetGymAttendance [method]: (int, System.Threading.CancellationToken option) -> PureGym.GymAttendance System.Threading.Tasks.Task
PureGym.IPureGymApi.GetGyms [method]: System.Threading.CancellationToken option -> PureGym.Gym list System.Threading.Tasks.Task
@@ -223,7 +226,7 @@ PureGym.MemberActivityThisMonth.TotalVisits [property]: [read-only] int
PureGym.MemberModule inherit obj
PureGym.MemberModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.Member
PureGym.PureGymApiModule inherit obj
PureGym.PureGymApiModule.make [static method]: System.Net.Http.HttpClient -> PureGym.IPureGymApi
PureGym.PureGymApiModule.make [static method]: (unit -> string) -> System.Net.Http.HttpClient -> PureGym.IPureGymApi
PureGym.Sessions inherit obj, implements PureGym.Sessions System.IEquatable, System.Collections.IStructuralEquatable, PureGym.Sessions System.IComparable, System.IComparable, System.Collections.IStructuralComparable
PureGym.Sessions..ctor [constructor]: (PureGym.SessionsSummary, PureGym.Visit list)
PureGym.Sessions.get_Summary [method]: unit -> PureGym.SessionsSummary
@@ -277,4 +280,4 @@ PureGym.VisitGym.Status [property]: [read-only] string
PureGym.VisitGymModule inherit obj
PureGym.VisitGymModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.VisitGym
PureGym.VisitModule inherit obj
PureGym.VisitModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.Visit
PureGym.VisitModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.Visit

View File

@@ -1,5 +1,5 @@
{
"version": "3.0",
"version": "4.0",
"publicReleaseRefSpec": [
"^refs/heads/main$"
],

View File

@@ -438,7 +438,7 @@
})
(fetchNuGet {
pname = "WoofWare.Myriad.Plugins";
version = "1.1.13";
sha256 = "sha256-TjR+3spu9vXb2kOoXM9p6yzjpt2rja1Tu7cAOmIMhog= ";
version = "1.4.8";
sha256 = "sha256-HdqiXz4pSQ+pPkj82RsWR7zn3JePQm5/IFl4dlR2O5Y=";
})
]