@tryterra/react-native 0.0.0-stage → 2.2.1

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 (112) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +142 -2
  3. package/TerraReactNative.podspec +48 -0
  4. package/android/build.gradle +87 -0
  5. package/android/src/bridgeCore/kotlin/README.md +1 -0
  6. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/BridgeBootstrap.kt +133 -0
  7. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/BridgeHost.kt +32 -0
  8. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/Conversions.kt +557 -0
  9. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/LauncherSlots.kt +41 -0
  10. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/ReadConversions.kt +250 -0
  11. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/Rejections.kt +150 -0
  12. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/StreamRegistry.kt +77 -0
  13. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/TerraBridge.kt +86 -0
  14. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/TerraBridgeOpsImpl.kt +300 -0
  15. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/TerraBridgeStreamsImpl.kt +50 -0
  16. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/TokenBroker.kt +198 -0
  17. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/generated/BridgeErrors.kt +217 -0
  18. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/generated/BridgeOps.kt +582 -0
  19. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/generated/BridgeTypes.kt +1569 -0
  20. package/android/src/healthConnectOnly/kotlin/co/tryterra/sdk/reactnative/TerraStores.kt +11 -0
  21. package/android/src/main/AndroidManifest.xml +24 -0
  22. package/android/src/main/java/co/tryterra/sdk/reactnative/TerraBridgeModule.kt +96 -0
  23. package/android/src/main/java/co/tryterra/sdk/reactnative/TerraReactNativePackage.kt +26 -0
  24. package/android/src/main/java/co/tryterra/sdk/reactnative/TerraStartup.kt +46 -0
  25. package/android/src/samsung/kotlin/co/tryterra/sdk/reactnative/TerraStores.kt +13 -0
  26. package/docs/availability.md +396 -0
  27. package/frameworks/TerraSDK.xcframework/Info.plist +48 -0
  28. package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Info.plist +0 -0
  29. package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios.abi.json +82672 -0
  30. package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios.package.swiftinterface +2186 -0
  31. package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +2186 -0
  32. package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  33. package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios.swiftinterface +2163 -0
  34. package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/PrivacyInfo.xcprivacy +96 -0
  35. package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/TerraSDK +0 -0
  36. package/frameworks/TerraSDK.xcframework/ios-arm64/dSYMs/TerraSDK.framework.dSYM/Contents/Info.plist +20 -0
  37. package/frameworks/TerraSDK.xcframework/ios-arm64/dSYMs/TerraSDK.framework.dSYM/Contents/Resources/DWARF/TerraSDK +0 -0
  38. package/frameworks/TerraSDK.xcframework/ios-arm64/dSYMs/TerraSDK.framework.dSYM/Contents/Resources/Relocations/aarch64/TerraSDK.yml +6594 -0
  39. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Info.plist +0 -0
  40. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +82672 -0
  41. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios-simulator.package.swiftinterface +2186 -0
  42. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +2186 -0
  43. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  44. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +2163 -0
  45. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json +82672 -0
  46. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/x86_64-apple-ios-simulator.package.swiftinterface +2186 -0
  47. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +2186 -0
  48. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
  49. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +2163 -0
  50. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/PrivacyInfo.xcprivacy +96 -0
  51. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/TerraSDK +0 -0
  52. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/_CodeSignature/CodeResources +223 -0
  53. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/TerraSDK.framework.dSYM/Contents/Info.plist +20 -0
  54. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/TerraSDK.framework.dSYM/Contents/Resources/DWARF/TerraSDK +0 -0
  55. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/TerraSDK.framework.dSYM/Contents/Resources/Relocations/aarch64/TerraSDK.yml +6595 -0
  56. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/TerraSDK.framework.dSYM/Contents/Resources/Relocations/x86_64/TerraSDK.yml +6513 -0
  57. package/ios/TerraBridgeCore/BridgeBootstrap.swift +89 -0
  58. package/ios/TerraBridgeCore/BridgeHost.swift +13 -0
  59. package/ios/TerraBridgeCore/Conversions+Reads.swift +259 -0
  60. package/ios/TerraBridgeCore/Conversions.swift +594 -0
  61. package/ios/TerraBridgeCore/Generated/BridgeErrors.swift +179 -0
  62. package/ios/TerraBridgeCore/Generated/BridgeOps.swift +967 -0
  63. package/ios/TerraBridgeCore/Generated/BridgeTypes.swift +2050 -0
  64. package/ios/TerraBridgeCore/Locked.swift +15 -0
  65. package/ios/TerraBridgeCore/README.md +1 -0
  66. package/ios/TerraBridgeCore/Rejections.swift +130 -0
  67. package/ios/TerraBridgeCore/RuntimeAttachment.swift +60 -0
  68. package/ios/TerraBridgeCore/StreamRegistry.swift +59 -0
  69. package/ios/TerraBridgeCore/TerraBridge.swift +122 -0
  70. package/ios/TerraBridgeCore/TerraBridgeOpsImpl.swift +318 -0
  71. package/ios/TerraBridgeCore/TerraBridgeStreamsImpl.swift +60 -0
  72. package/ios/TerraBridgeCore/TokenBroker.swift +147 -0
  73. package/ios/TerraBridgeModule.mm +79 -0
  74. package/ios/TerraBridgeModuleImpl.swift +49 -0
  75. package/ios/TerraReactNative.swift +19 -0
  76. package/lib/EndUser.d.ts +12 -0
  77. package/lib/EndUser.js +13 -0
  78. package/lib/NativeTerraBridge.d.ts +23 -0
  79. package/lib/NativeTerraBridge.js +13 -0
  80. package/lib/Terra.d.ts +223 -0
  81. package/lib/Terra.js +336 -0
  82. package/lib/TerraError.d.ts +42 -0
  83. package/lib/TerraError.js +95 -0
  84. package/lib/createTerra.d.ts +8 -0
  85. package/lib/createTerra.js +19 -0
  86. package/lib/generated/client.d.ts +128 -0
  87. package/lib/generated/client.js +256 -0
  88. package/lib/generated/codecs.d.ts +219 -0
  89. package/lib/generated/codecs.js +2066 -0
  90. package/lib/generated/errors.d.ts +13 -0
  91. package/lib/generated/errors.js +68 -0
  92. package/lib/generated/ops.d.ts +13 -0
  93. package/lib/generated/ops.js +161 -0
  94. package/lib/generated/streams.d.ts +23 -0
  95. package/lib/generated/streams.js +58 -0
  96. package/lib/generated/types.d.ts +794 -0
  97. package/lib/generated/types.js +224 -0
  98. package/lib/index.d.ts +29 -0
  99. package/lib/index.js +55 -0
  100. package/package.json +71 -4
  101. package/src/EndUser.ts +15 -0
  102. package/src/NativeTerraBridge.ts +27 -0
  103. package/src/Terra.ts +592 -0
  104. package/src/TerraError.ts +116 -0
  105. package/src/createTerra.ts +18 -0
  106. package/src/generated/client.ts +315 -0
  107. package/src/generated/codecs.ts +1989 -0
  108. package/src/generated/errors.ts +113 -0
  109. package/src/generated/ops.ts +233 -0
  110. package/src/generated/streams.ts +74 -0
  111. package/src/generated/types.ts +1222 -0
  112. package/src/index.ts +54 -0
@@ -0,0 +1,116 @@
1
+ /**
2
+ * The error every rejected op carries, hydrated from the bridge's JSON.
3
+ *
4
+ * Hand-written, and one of only two files here that are: the shape is fixed, while the *vocabulary*
5
+ * it carries is generated. `code` is a `TerraErrorCode`, so a code renamed natively stops a
6
+ * `switch` over it compiling rather than silently never matching.
7
+ */
8
+
9
+ import { decodeTerraErrorPayload } from "./generated/codecs";
10
+ import { retryableByCode, type TerraErrorCode } from "./generated/errors";
11
+ import type { Source, TerraErrorPayload } from "./generated/types";
12
+
13
+ /**
14
+ * The JSON a native rejection carries in its userInfo / message: the schema's own payload, except
15
+ * that `retryable` may be left out, in which case the per-code table answers.
16
+ */
17
+ export type TerraErrorJSON = Omit<TerraErrorPayload, "retryable"> & { readonly retryable?: boolean };
18
+
19
+ export class TerraError extends Error {
20
+ readonly code: TerraErrorCode;
21
+ /**
22
+ * Whether the same call could succeed if repeated.
23
+ *
24
+ * Read from the rejection rather than from `retryableByCode`, because one code decides per
25
+ * instance: `network.server_error` is retryable for a 503 and not for a 400. The table is the
26
+ * fallback for a rejection that did not carry the flag at all.
27
+ */
28
+ readonly retryable: boolean;
29
+ readonly source: Source | undefined;
30
+ readonly details: Record<string, unknown> | undefined;
31
+
32
+ constructor(json: TerraErrorJSON, options?: { readonly cause?: unknown }) {
33
+ super(json.message, options);
34
+ this.name = "TerraError";
35
+ const known = isKnownCode(json.code);
36
+ this.code = known ? json.code : "platform";
37
+ this.retryable = known ? (json.retryable ?? fallbackRetryable(json.code)) : false;
38
+ this.source = json.source;
39
+ this.details = known ? json.details : { ...json.details, unrecognisedCode: json.code };
40
+ }
41
+
42
+ /**
43
+ * Rebuilds a `TerraError` from whatever the native module rejected with.
44
+ *
45
+ * Anything unrecognisable becomes `platform` rather than being rethrown as-is: a caller that has
46
+ * to handle both `TerraError` and an arbitrary `Error` ends up handling neither properly, and the
47
+ * original is kept as `cause` and its text in `message`.
48
+ */
49
+ static from(thrown: unknown): TerraError {
50
+ if (thrown instanceof TerraError) return thrown;
51
+ const json = readJSON(thrown);
52
+ if (json !== undefined) return new TerraError(json, { cause: thrown });
53
+ return new TerraError({ code: "platform", retryable: false, message: messageOf(thrown) }, { cause: thrown });
54
+ }
55
+
56
+ /** A response the bridge resolved that this build cannot read: the native side and JS disagree. */
57
+ static invalidPayload(op: string, thrown: unknown): TerraError {
58
+ return new TerraError(
59
+ { code: "bridge.invalid_payload", message: `${op}: ${messageOf(thrown)}`, details: { op } },
60
+ { cause: thrown },
61
+ );
62
+ }
63
+ }
64
+
65
+ function isKnownCode(code: string): code is TerraErrorCode {
66
+ return Object.prototype.hasOwnProperty.call(retryableByCode, code);
67
+ }
68
+
69
+ function messageOf(thrown: unknown): string {
70
+ if (thrown instanceof Error) return thrown.message;
71
+ if (isObject(thrown) && typeof thrown.message === "string") return thrown.message;
72
+ return String(thrown);
73
+ }
74
+
75
+ function fallbackRetryable(code: TerraErrorCode): boolean {
76
+ return retryableByCode[code] === true;
77
+ }
78
+
79
+ /** A JSON string preserves payload types across `NSError` and `WritableMap`, unlike a nested map. */
80
+ function readJSON(thrown: unknown): TerraErrorJSON | undefined {
81
+ if (typeof thrown !== "object" || thrown === null) return undefined;
82
+ const candidate = thrown as Record<string, unknown>;
83
+ const userInfo = candidate.userInfo;
84
+ const encoded = isObject(userInfo) ? userInfo.payload : undefined;
85
+ return (typeof encoded === "string" ? decode(parse(encoded)) : undefined) ?? decode(userInfo) ?? decode(candidate);
86
+ }
87
+
88
+ function parse(encoded: string): unknown {
89
+ try {
90
+ return JSON.parse(encoded);
91
+ } catch {
92
+ return undefined;
93
+ }
94
+ }
95
+
96
+ /** The generated decoder does the checking: a string code, a boolean flag, a known source. */
97
+ function decode(raw: unknown): TerraErrorJSON | undefined {
98
+ if (!isObject(raw) || typeof raw.code !== "string") return undefined;
99
+ try {
100
+ // Read field by field: an Error's `message` is not enumerable, so spreading one drops it.
101
+ const { retryable, ...rest } = decodeTerraErrorPayload({
102
+ code: raw.code,
103
+ retryable: raw.retryable ?? false,
104
+ message: raw.message,
105
+ source: raw.source,
106
+ details: raw.details,
107
+ });
108
+ return raw.retryable === undefined ? rest : { ...rest, retryable };
109
+ } catch {
110
+ return undefined;
111
+ }
112
+ }
113
+
114
+ function isObject(value: unknown): value is Record<string, unknown> {
115
+ return typeof value === "object" && value !== null;
116
+ }
@@ -0,0 +1,18 @@
1
+ import { Platform } from "react-native";
2
+
3
+ import NativeTerraBridge from "./NativeTerraBridge";
4
+ import { Terra, type TerraOptions } from "./Terra";
5
+
6
+ /**
7
+ * Attaches this JavaScript runtime to the native client the app built at launch.
8
+ *
9
+ * Call it once, at module scope. The native client outlives a reload, so a reload attaches again
10
+ * rather than building a second client.
11
+ */
12
+ export function createTerra(options: TerraOptions = {}): Terra {
13
+ const platform = Platform.OS;
14
+ if (platform !== "ios" && platform !== "android") {
15
+ throw new Error(`@tryterra/react-native runs on iOS and Android, not ${platform}`);
16
+ }
17
+ return new Terra(NativeTerraBridge, platform, options);
18
+ }
@@ -0,0 +1,315 @@
1
+ // Generated from surface/terra-surface.json by surface/gen. Do not edit by hand.
2
+ // Regenerate with: node surface/gen/src/cli.ts generate
3
+
4
+ import type { AthleteProfileResult, AvailabilityResult, BodyEntryList, BodyReadingList, BoolResult, BootstrapState, CategoryRequest, ConnectRequest, Connection, ConnectionList, DayTotalList, DiagnosticsState, DietaryQuantityList, Empty, HealthAccess, HeartRateEntryList, HeartRateList, HydrationList, IntradaySampleList, LastDeliveryResult, MarkCompleteRequest, MenstrualEventList, MenstruationFlowDayList, NutritionEntryList, PermissionGrant, PermissionRequest, PlannedWorkoutList, RangeRequest, RecordIdList, RecordIdRequest, RestingHeartRateList, SleepEntryList, SleepSegmentList, SourceRequest, StatusResult, StatusesResult, StepCountList, StepEntryList, SupportReport, TokenProviderRequest, TokenRejectRequest, TokenResolveRequest, WorkoutEntryList, WorkoutIntensityList, WorkoutList, WorkoutRouteList, WorkoutScheduling } from "./types";
5
+ import { encodeBodyEntryList, encodeCategoryRequest, encodeConnectRequest, encodeEmpty, encodeHeartRateEntryList, encodeMarkCompleteRequest, encodeNutritionEntryList, encodePermissionRequest, encodeRangeRequest, encodeRecordIdRequest, encodeSleepEntryList, encodeSourceRequest, encodeStepEntryList, encodeTokenProviderRequest, encodeTokenRejectRequest, encodeTokenResolveRequest, encodeWorkoutEntryList, decodeAthleteProfileResult, decodeAvailabilityResult, decodeBodyReadingList, decodeBoolResult, decodeBootstrapState, decodeConnection, decodeConnectionList, decodeDayTotalList, decodeDiagnosticsState, decodeDietaryQuantityList, decodeEmpty, decodeHealthAccess, decodeHeartRateList, decodeHydrationList, decodeIntradaySampleList, decodeLastDeliveryResult, decodeMenstrualEventList, decodeMenstruationFlowDayList, decodePermissionGrant, decodePlannedWorkoutList, decodeRecordIdList, decodeRestingHeartRateList, decodeSleepSegmentList, decodeStatusResult, decodeStatusesResult, decodeStepCountList, decodeSupportReport, decodeWorkoutIntensityList, decodeWorkoutList, decodeWorkoutRouteList, decodeWorkoutScheduling } from "./codecs";
6
+ import type { OpId } from "./ops";
7
+ import { TerraError } from "../TerraError";
8
+
9
+ /** What the facade needs from the native module. The TurboModule spec satisfies it; so does a test double. */
10
+ export interface Invoker {
11
+ invoke(op: OpId, payload: string): Promise<string>;
12
+ }
13
+
14
+ /**
15
+ * One generated method per op, and nothing else.
16
+ *
17
+ * The `op` string exists only between this file and the generated native dispatch, and a vector
18
+ * in `vectors/bridge` pins the two to each other. A caller never sees it.
19
+ */
20
+ export class GeneratedClient {
21
+ protected readonly invoker: Invoker;
22
+
23
+ constructor(invoker: Invoker) {
24
+ this.invoker = invoker;
25
+ }
26
+
27
+ private async call<T>(op: OpId, encode: () => Record<string, unknown>, decode: (raw: unknown) => T): Promise<T> {
28
+ let payload: string;
29
+ try {
30
+ payload = JSON.stringify(encode());
31
+ } catch (thrown) {
32
+ throw TerraError.invalidPayload(op, thrown);
33
+ }
34
+ let text: string;
35
+ try {
36
+ text = await this.invoker.invoke(op, payload);
37
+ } catch (thrown) {
38
+ throw TerraError.from(thrown);
39
+ }
40
+ try {
41
+ return decode(JSON.parse(text));
42
+ } catch (thrown) {
43
+ throw TerraError.invalidPayload(op, thrown);
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Reports the native client the JS side is attaching to. Idempotent, and safe to call after a
49
+ * JS reload.
50
+ */
51
+ async clientAttach(request: Empty): Promise<BootstrapState> {
52
+ return this.call("client.attach", () => encodeEmpty(request), (raw) => decodeBootstrapState(raw, "BootstrapState"));
53
+ }
54
+
55
+ async clientConnect(request: ConnectRequest): Promise<Connection> {
56
+ return this.call("client.connect", () => encodeConnectRequest(request), (raw) => decodeConnection(raw, "Connection"));
57
+ }
58
+
59
+ async clientConnections(request: Empty): Promise<ConnectionList> {
60
+ return this.call("client.connections", () => encodeEmpty(request), (raw) => decodeConnectionList(raw, "ConnectionList"));
61
+ }
62
+
63
+ /** Whether the device can serve the source at all. Needs no connection and prompts for nothing. */
64
+ async clientAvailability(request: SourceRequest): Promise<AvailabilityResult> {
65
+ return this.call("client.availability", () => encodeSourceRequest(request), (raw) => decodeAvailabilityResult(raw, "AvailabilityResult"));
66
+ }
67
+
68
+ async clientDisconnect(request: SourceRequest): Promise<Empty> {
69
+ return this.call("client.disconnect", () => encodeSourceRequest(request), (raw) => decodeEmpty(raw, "Empty"));
70
+ }
71
+
72
+ /**
73
+ * Tells the broker whether JS can answer at all. Without it a link asks a provider that is not
74
+ * there and waits out the timeout.
75
+ */
76
+ async tokenSetProviderPresent(request: TokenProviderRequest): Promise<Empty> {
77
+ return this.call("token.setProviderPresent", () => encodeTokenProviderRequest(request), (raw) => decodeEmpty(raw, "Empty"));
78
+ }
79
+
80
+ /**
81
+ * An unknown or already-settled requestId is ignored rather than rejected, so a reload cannot
82
+ * fail a link that has already moved on.
83
+ */
84
+ async tokenResolve(request: TokenResolveRequest): Promise<Empty> {
85
+ return this.call("token.resolve", () => encodeTokenResolveRequest(request), (raw) => decodeEmpty(raw, "Empty"));
86
+ }
87
+
88
+ async tokenReject(request: TokenRejectRequest): Promise<Empty> {
89
+ return this.call("token.reject", () => encodeTokenRejectRequest(request), (raw) => decodeEmpty(raw, "Empty"));
90
+ }
91
+
92
+ async permissionsRequest(request: PermissionRequest): Promise<PermissionGrant> {
93
+ return this.call("permissions.request", () => encodePermissionRequest(request), (raw) => decodePermissionGrant(raw, "PermissionGrant"));
94
+ }
95
+
96
+ async permissionsStatus(request: CategoryRequest): Promise<StatusResult> {
97
+ return this.call("permissions.status", () => encodeCategoryRequest(request), (raw) => decodeStatusResult(raw, "StatusResult"));
98
+ }
99
+
100
+ async permissionsWriteStatus(request: CategoryRequest): Promise<StatusResult> {
101
+ return this.call("permissions.writeStatus", () => encodeCategoryRequest(request), (raw) => decodeStatusResult(raw, "StatusResult"));
102
+ }
103
+
104
+ async permissionsRequested(request: SourceRequest): Promise<HealthAccess> {
105
+ return this.call("permissions.requested", () => encodeSourceRequest(request), (raw) => decodeHealthAccess(raw, "HealthAccess"));
106
+ }
107
+
108
+ /** Available on android only. */
109
+ async permissionsStatuses(request: SourceRequest): Promise<StatusesResult> {
110
+ return this.call("permissions.statuses", () => encodeSourceRequest(request), (raw) => decodeStatusesResult(raw, "StatusesResult"));
111
+ }
112
+
113
+ /** Available on android only. */
114
+ async permissionsBackgroundReadStatus(request: SourceRequest): Promise<StatusResult> {
115
+ return this.call("permissions.backgroundReadStatus", () => encodeSourceRequest(request), (raw) => decodeStatusResult(raw, "StatusResult"));
116
+ }
117
+
118
+ /** Available on android only. */
119
+ async permissionsHistoryReadStatus(request: SourceRequest): Promise<StatusResult> {
120
+ return this.call("permissions.historyReadStatus", () => encodeSourceRequest(request), (raw) => decodeStatusResult(raw, "StatusResult"));
121
+ }
122
+
123
+ async diagnosticsState(request: SourceRequest): Promise<DiagnosticsState> {
124
+ return this.call("diagnostics.state", () => encodeSourceRequest(request), (raw) => decodeDiagnosticsState(raw, "DiagnosticsState"));
125
+ }
126
+
127
+ async diagnosticsLastDelivery(request: SourceRequest): Promise<LastDeliveryResult> {
128
+ return this.call("diagnostics.lastDelivery", () => encodeSourceRequest(request), (raw) => decodeLastDeliveryResult(raw, "LastDeliveryResult"));
129
+ }
130
+
131
+ async diagnosticsReport(request: SourceRequest): Promise<SupportReport> {
132
+ return this.call("diagnostics.report", () => encodeSourceRequest(request), (raw) => decodeSupportReport(raw, "SupportReport"));
133
+ }
134
+
135
+ async diagnosticsSend(request: SourceRequest): Promise<Empty> {
136
+ return this.call("diagnostics.send", () => encodeSourceRequest(request), (raw) => decodeEmpty(raw, "Empty"));
137
+ }
138
+
139
+ /**
140
+ * False means bootstrap did not run. The SDK reports the same thing independently as
141
+ * backgroundRefreshUnscheduled.
142
+ */
143
+ async backgroundIsRegistered(request: Empty): Promise<BoolResult> {
144
+ return this.call("background.isRegistered", () => encodeEmpty(request), (raw) => decodeBoolResult(raw, "BoolResult"));
145
+ }
146
+
147
+ /** Available on android only. */
148
+ async backgroundCancel(request: Empty): Promise<BoolResult> {
149
+ return this.call("background.cancel", () => encodeEmpty(request), (raw) => decodeBoolResult(raw, "BoolResult"));
150
+ }
151
+
152
+ async bodyHeartRate(request: RangeRequest): Promise<HeartRateList> {
153
+ return this.call("body.heartRate", () => encodeRangeRequest(request), (raw) => decodeHeartRateList(raw, "HeartRateList"));
154
+ }
155
+
156
+ /**
157
+ * The store's own daily figures. Health Connect grants them under daily, so Android answers
158
+ * authorization_not_determined where only body was asked for.
159
+ */
160
+ async bodyRestingHeartRate(request: RangeRequest): Promise<RestingHeartRateList> {
161
+ return this.call("body.restingHeartRate", () => encodeRangeRequest(request), (raw) => decodeRestingHeartRateList(raw, "RestingHeartRateList"));
162
+ }
163
+
164
+ async bodyReadings(request: RangeRequest): Promise<BodyReadingList> {
165
+ return this.call("body.readings", () => encodeRangeRequest(request), (raw) => decodeBodyReadingList(raw, "BodyReadingList"));
166
+ }
167
+
168
+ /** Its own op rather than an overload: Swift overloads log by element type and JS cannot. */
169
+ async bodyLogHeartRate(request: HeartRateEntryList): Promise<RecordIdList> {
170
+ return this.call("body.logHeartRate", () => encodeHeartRateEntryList(request), (raw) => decodeRecordIdList(raw, "RecordIdList"));
171
+ }
172
+
173
+ async bodyLog(request: BodyEntryList): Promise<RecordIdList> {
174
+ return this.call("body.log", () => encodeBodyEntryList(request), (raw) => decodeRecordIdList(raw, "RecordIdList"));
175
+ }
176
+
177
+ async bodyDelete(request: RecordIdRequest): Promise<Empty> {
178
+ return this.call("body.delete", () => encodeRecordIdRequest(request), (raw) => decodeEmpty(raw, "Empty"));
179
+ }
180
+
181
+ async dailySteps(request: RangeRequest): Promise<StepCountList> {
182
+ return this.call("daily.steps", () => encodeRangeRequest(request), (raw) => decodeStepCountList(raw, "StepCountList"));
183
+ }
184
+
185
+ /**
186
+ * One total per metric per whole local day the range touches. A day with nothing recorded has
187
+ * no total, not a zero.
188
+ */
189
+ async dailyTotals(request: RangeRequest): Promise<DayTotalList> {
190
+ return this.call("daily.totals", () => encodeRangeRequest(request), (raw) => decodeDayTotalList(raw, "DayTotalList"));
191
+ }
192
+
193
+ /** The active energy, basal energy, distance and floors records the totals are made of. */
194
+ async dailyIntraday(request: RangeRequest): Promise<IntradaySampleList> {
195
+ return this.call("daily.intraday", () => encodeRangeRequest(request), (raw) => decodeIntradaySampleList(raw, "IntradaySampleList"));
196
+ }
197
+
198
+ async dailyLog(request: StepEntryList): Promise<RecordIdList> {
199
+ return this.call("daily.log", () => encodeStepEntryList(request), (raw) => decodeRecordIdList(raw, "RecordIdList"));
200
+ }
201
+
202
+ async dailyDelete(request: RecordIdRequest): Promise<Empty> {
203
+ return this.call("daily.delete", () => encodeRecordIdRequest(request), (raw) => decodeEmpty(raw, "Empty"));
204
+ }
205
+
206
+ async sleepSegments(request: RangeRequest): Promise<SleepSegmentList> {
207
+ return this.call("sleep.segments", () => encodeRangeRequest(request), (raw) => decodeSleepSegmentList(raw, "SleepSegmentList"));
208
+ }
209
+
210
+ async sleepLog(request: SleepEntryList): Promise<RecordIdList> {
211
+ return this.call("sleep.log", () => encodeSleepEntryList(request), (raw) => decodeRecordIdList(raw, "RecordIdList"));
212
+ }
213
+
214
+ async sleepDelete(request: RecordIdRequest): Promise<Empty> {
215
+ return this.call("sleep.delete", () => encodeRecordIdRequest(request), (raw) => decodeEmpty(raw, "Empty"));
216
+ }
217
+
218
+ async activityWorkouts(request: RangeRequest): Promise<WorkoutList> {
219
+ return this.call("activity.workouts", () => encodeRangeRequest(request), (raw) => decodeWorkoutList(raw, "WorkoutList"));
220
+ }
221
+
222
+ /** The GPS tracks of the workouts in the range, each naming its workout. */
223
+ async activityRoutes(request: RangeRequest): Promise<WorkoutRouteList> {
224
+ return this.call("activity.routes", () => encodeRangeRequest(request), (raw) => decodeWorkoutRouteList(raw, "WorkoutRouteList"));
225
+ }
226
+
227
+ /** Speed, power and cycling cadence readings in the range. */
228
+ async activityIntensity(request: RangeRequest): Promise<WorkoutIntensityList> {
229
+ return this.call("activity.intensity", () => encodeRangeRequest(request), (raw) => decodeWorkoutIntensityList(raw, "WorkoutIntensityList"));
230
+ }
231
+
232
+ async activityLog(request: WorkoutEntryList): Promise<RecordIdList> {
233
+ return this.call("activity.log", () => encodeWorkoutEntryList(request), (raw) => decodeRecordIdList(raw, "RecordIdList"));
234
+ }
235
+
236
+ async activityDelete(request: RecordIdRequest): Promise<Empty> {
237
+ return this.call("activity.delete", () => encodeRecordIdRequest(request), (raw) => decodeEmpty(raw, "Empty"));
238
+ }
239
+
240
+ /** One quantity per nutrient a meal recorded, not grouped into meals. Water is not among them. */
241
+ async nutritionQuantities(request: RangeRequest): Promise<DietaryQuantityList> {
242
+ return this.call("nutrition.quantities", () => encodeRangeRequest(request), (raw) => decodeDietaryQuantityList(raw, "DietaryQuantityList"));
243
+ }
244
+
245
+ async nutritionLog(request: NutritionEntryList): Promise<RecordIdList> {
246
+ return this.call("nutrition.log", () => encodeNutritionEntryList(request), (raw) => decodeRecordIdList(raw, "RecordIdList"));
247
+ }
248
+
249
+ async nutritionDelete(request: RecordIdRequest): Promise<Empty> {
250
+ return this.call("nutrition.delete", () => encodeRecordIdRequest(request), (raw) => decodeEmpty(raw, "Empty"));
251
+ }
252
+
253
+ /** Water drunk in the range, one sample per drink. */
254
+ async nutritionHydration(request: RangeRequest): Promise<HydrationList> {
255
+ return this.call("nutrition.hydration", () => encodeRangeRequest(request), (raw) => decodeHydrationList(raw, "HydrationList"));
256
+ }
257
+
258
+ /**
259
+ * Logged flow days overlapping the range, one per day. A day logged with no flow is noFlow,
260
+ * not left out.
261
+ */
262
+ async menstruationFlow(request: RangeRequest): Promise<MenstruationFlowDayList> {
263
+ return this.call("menstruation.flow", () => encodeRangeRequest(request), (raw) => decodeMenstruationFlowDayList(raw, "MenstruationFlowDayList"));
264
+ }
265
+
266
+ /** Ovulation tests, cervical mucus and intermenstrual bleeding logged in the range. */
267
+ async menstruationEvents(request: RangeRequest): Promise<MenstrualEventList> {
268
+ return this.call("menstruation.events", () => encodeRangeRequest(request), (raw) => decodeMenstrualEventList(raw, "MenstrualEventList"));
269
+ }
270
+
271
+ /**
272
+ * Characteristics have no history.
273
+ *
274
+ * Available on ios only.
275
+ */
276
+ async athleteProfile(request: Empty): Promise<AthleteProfileResult> {
277
+ return this.call("athlete.profile", () => encodeEmpty(request), (raw) => decodeAthleteProfileResult(raw, "AthleteProfileResult"));
278
+ }
279
+
280
+ /** Available on ios only. */
281
+ async plannedWorkoutsPlanned(request: Empty): Promise<PlannedWorkoutList> {
282
+ return this.call("plannedWorkouts.planned", () => encodeEmpty(request), (raw) => decodePlannedWorkoutList(raw, "PlannedWorkoutList"));
283
+ }
284
+
285
+ /** Available on ios only. */
286
+ async plannedWorkoutsMarkComplete(request: MarkCompleteRequest): Promise<Empty> {
287
+ return this.call("plannedWorkouts.markComplete", () => encodeMarkCompleteRequest(request), (raw) => decodeEmpty(raw, "Empty"));
288
+ }
289
+
290
+ /** Available on ios only. */
291
+ async plannedWorkoutsDelete(request: RecordIdRequest): Promise<Empty> {
292
+ return this.call("plannedWorkouts.delete", () => encodeRecordIdRequest(request), (raw) => decodeEmpty(raw, "Empty"));
293
+ }
294
+
295
+ /**
296
+ * Never prompts.
297
+ *
298
+ * Available on ios only.
299
+ */
300
+ async plannedWorkoutsSchedulingStatus(request: Empty): Promise<WorkoutScheduling> {
301
+ return this.call("plannedWorkouts.schedulingStatus", () => encodeEmpty(request), (raw) => decodeWorkoutScheduling(raw, "WorkoutScheduling"));
302
+ }
303
+
304
+ /**
305
+ * Shows WorkoutKit's sheet if the person has not been asked, and reconciles straight away once
306
+ * authorized.
307
+ *
308
+ * Available on ios only.
309
+ */
310
+ async plannedWorkoutsRequestScheduling(request: Empty): Promise<WorkoutScheduling> {
311
+ return this.call("plannedWorkouts.requestScheduling", () => encodeEmpty(request), (raw) => decodeWorkoutScheduling(raw, "WorkoutScheduling"));
312
+ }
313
+
314
+ }
315
+