TeraGeneratedRuntimeBackend.swift (30229B)
1 import Foundation 2 import TeraKitBindings 3 4 private actor TeraGeneratedSubscriptionToken: TeraRuntimeSubscriptionToken { 5 private var handle: FfiSubscriptionHandle? 6 private var observer: TeraGeneratedRuntimeObserver? 7 private var deliveryTask: Task<Void, Never>? 8 9 init( 10 handle: FfiSubscriptionHandle, 11 observer: TeraGeneratedRuntimeObserver, 12 deliveryTask: Task<Void, Never> 13 ) { 14 self.handle = handle 15 self.observer = observer 16 self.deliveryTask = deliveryTask 17 } 18 19 func cancel() async { 20 guard let handle else { return } 21 self.handle = nil 22 observer?.finish() 23 observer = nil 24 handle.unsubscribe() 25 deliveryTask?.cancel() 26 await deliveryTask?.value 27 deliveryTask = nil 28 } 29 } 30 31 final class TeraGeneratedRuntimeBackend: TeraRuntimeBackend, @unchecked Sendable { 32 let runtime: TeraRuntime 33 34 init(runtime: TeraRuntime) { 35 self.runtime = runtime 36 } 37 38 func snapshot() async throws -> TeraRuntimeSnapshot { 39 do { 40 let identity = try runtime.identityStatus() 41 let relay = try runtime.sdkRelayStatus() 42 let blossomConfiguration = try runtime.sdkBlossomConfiguration() 43 let blossomEvidence = try runtime.sdkBlossomEvidence() 44 let info = runtime.info() 45 return TeraRuntimeSnapshot( 46 identity: TeraRuntimeIdentity( 47 publicKeyHex: identity.publicKey, 48 hostSignerConfigured: identity.hostSignerConfigured 49 ), 50 relay: relay.map { report in 51 TeraRelayStatus( 52 profile: report.profile, 53 state: report.state, 54 readAvailability: report.readAvailability, 55 writeAvailability: report.writeAvailability, 56 relays: report.relays.map { relay in 57 TeraRelayEndpointStatus( 58 url: relay.relayUrl, 59 access: relay.access.appValue, 60 readState: relay.readState, 61 writeState: relay.writeState, 62 readLastAttemptUnixMilliseconds: relay.readLastAttemptUnixMs, 63 writeLastAttemptUnixMilliseconds: relay.writeLastAttemptUnixMs, 64 readNextAttemptUnixMilliseconds: relay.readNextAttemptUnixMs, 65 writeNextAttemptUnixMilliseconds: relay.writeNextAttemptUnixMs 66 ) 67 } 68 ) 69 }, 70 blossomConfiguration: blossomConfiguration?.appValue, 71 blossomEvidence: blossomEvidence?.appValue, 72 crateName: info.sdk.crateName, 73 crateVersion: info.sdk.crateVersion, 74 isClosed: info.sdkClosed 75 ) 76 } catch { 77 throw TeraGeneratedRuntimeFailure.from(error) 78 } 79 } 80 81 func search( 82 context: TeraLocalNetwork, 83 query: String, 84 limit: UInt16, 85 asOfUnixSeconds: UInt64 86 ) async throws -> [TeraSearchResult] { 87 do { 88 return try await runtime.phase1Search( 89 context: context.generatedValue, 90 query: query, 91 limit: limit, 92 asOfUnixS: asOfUnixSeconds, viewerTimeZone: TimeZone.current.identifier 93 ).map { try $0.appValue() } 94 } catch { 95 throw TeraGeneratedRuntimeFailure.from(error) 96 } 97 } 98 99 func me( 100 context: TeraLocalNetwork, 101 asOfUnixSeconds: UInt64 102 ) async throws -> TeraMeSnapshot { 103 do { 104 return try await runtime.phase1Me( 105 context: context.generatedValue, 106 asOfUnixS: asOfUnixSeconds, viewerTimeZone: TimeZone.current.identifier 107 ).appValue() 108 } catch { 109 throw TeraGeneratedRuntimeFailure.from(error) 110 } 111 } 112 113 func retrieveMedia( 114 context: TeraLocalNetwork, 115 reference: TeraMediaReference 116 ) async throws -> TeraVerifiedMediaArtifact { 117 do { 118 let operation = try FfiMediaOperation() 119 let record = try await withTaskCancellationHandler { 120 try await runtime.phase1RetrieveMedia( 121 context: context.generatedValue, 122 referenceFingerprint: reference.referenceFingerprint, 123 operation: operation 124 ) 125 } onCancel: { 126 operation.cancel() 127 } 128 return try Self.verifiedMediaArtifact( 129 record, 130 expectedArtifactID: reference.sha256, 131 requiresOperationID: true 132 ) 133 } catch { 134 throw TeraGeneratedRuntimeFailure.from(error) 135 } 136 } 137 138 func verifiedMediaArtifact( 139 context: TeraLocalNetwork, 140 artifactID: String 141 ) async throws -> TeraVerifiedMediaArtifact? { 142 do { 143 guard let record = try await runtime.phase1VerifiedMediaArtifact( 144 context: context.generatedValue, 145 artifactId: artifactID 146 ) else { return nil } 147 return try Self.verifiedMediaArtifact( 148 record, 149 expectedArtifactID: artifactID, 150 requiresOperationID: false 151 ) 152 } catch { 153 throw TeraGeneratedRuntimeFailure.from(error) 154 } 155 } 156 157 func invalidateMediaArtifact( 158 context: TeraLocalNetwork, 159 artifactID: String 160 ) async throws -> Bool { 161 do { 162 return try await runtime.phase1InvalidateMediaArtifact( 163 context: context.generatedValue, 164 artifactId: artifactID 165 ) 166 } catch { 167 throw TeraGeneratedRuntimeFailure.from(error) 168 } 169 } 170 171 func addSchemas() async throws -> [TeraAddSchema] { 172 runtime.phase1AddSchemas().map(\.appValue) 173 } 174 175 func saveAddIntent( 176 input: TeraAddRuntimeInput, 177 existingDraftID: String?, 178 expectedRevision: UInt64? 179 ) async throws -> TeraDraftStatus { 180 do { 181 return try await runtime.phase1SaveAddIntent( 182 input: input.generatedValue, 183 existingDraftId: existingDraftID, 184 expectedRevision: expectedRevision 185 ).appValue 186 } catch { 187 throw TeraGeneratedRuntimeFailure.from(error) 188 } 189 } 190 191 func saveRetractionDraft( 192 id: String, 193 input: TeraRetractionDraftInput, 194 authoredAtUnixSeconds: UInt64, 195 persistedAtUnixMilliseconds: UInt64 196 ) async throws -> TeraDraftStatus { 197 do { 198 return try await runtime.phase1SaveRetractionDraft( 199 draftId: id, 200 input: input.generatedValue, 201 authoredAtUnixS: authoredAtUnixSeconds, 202 persistedAtUnixMs: persistedAtUnixMilliseconds 203 ).appValue 204 } catch { 205 throw TeraGeneratedRuntimeFailure.from(error) 206 } 207 } 208 209 func queueAddIntent( 210 id: String, 211 expectedRevision: UInt64 212 ) async throws -> TeraDraftStatus { 213 do { 214 return try await runtime.phase1QueueAddIntent( 215 draftId: id, 216 expectedRevision: expectedRevision 217 ).appValue 218 } catch { 219 throw TeraGeneratedRuntimeFailure.from(error) 220 } 221 } 222 223 func recoverAddIntent(id: String) async throws -> TeraDraftStatus { 224 do { 225 return try await runtime.phase1RecoverAddIntent(draftId: id).appValue 226 } catch { 227 throw TeraGeneratedRuntimeFailure.from(error) 228 } 229 } 230 231 func uploadAddMediaIntent(input: TeraBlossomUploadIntent) async throws -> TeraDraftStatus { 232 do { 233 return try await runtime.phase1UploadAddMediaIntent(input: input.generatedValue).appValue 234 } catch { 235 throw TeraGeneratedRuntimeFailure.from(error) 236 } 237 } 238 239 func prepareAddMediaBackground( 240 input: TeraBlossomUploadIntent 241 ) async throws -> TeraNativeUploadJob { 242 do { 243 return try await runtime.phase1PrepareAddMediaBackground( 244 input: input.generatedValue 245 ).appValue 246 } catch { 247 throw TeraGeneratedRuntimeFailure.from(error) 248 } 249 } 250 251 func completeAddMediaBackground( 252 input: TeraNativeUploadCompletion 253 ) async throws -> TeraDraftStatus { 254 do { 255 return try await runtime.phase1CompleteAddMediaBackground( 256 input: input.generatedValue 257 ).appValue 258 } catch { 259 throw TeraGeneratedRuntimeFailure.from(error) 260 } 261 } 262 263 func probeBlossom() async throws -> TeraBlossomEvidence { 264 do { 265 return try await runtime.probeBlossom().appValue 266 } catch { 267 throw TeraGeneratedRuntimeFailure.from(error) 268 } 269 } 270 271 func mobileSettings() async throws -> TeraMobileSettings { 272 do { 273 return try await runtime.phase1Settings().appValue 274 } catch { 275 throw TeraGeneratedRuntimeFailure.from(error) 276 } 277 } 278 279 func replaceMobileSettings( 280 input: TeraReplaceSettings 281 ) async throws -> TeraSettingsTransition { 282 do { 283 return try await runtime.phase1ReplaceSettings(input: input.generatedValue).appValue 284 } catch { 285 throw TeraGeneratedRuntimeFailure.from(error) 286 } 287 } 288 289 func applyIdentityCommand( 290 expectedRevision: UInt64, 291 command: TeraIdentityCommand 292 ) async throws -> TeraSettingsTransition { 293 do { 294 return try await runtime.phase1ApplyIdentityCommand( 295 expectedRevision: expectedRevision, 296 command: command.generatedValue 297 ).appValue 298 } catch { 299 throw TeraGeneratedRuntimeFailure.from(error) 300 } 301 } 302 303 func saveProfileMetadata(input: TeraProfileMetadataInput) async throws 304 -> TeraProfileStatus 305 { 306 do { 307 return try await runtime.phase1SaveProfileMetadata(input: input.generatedValue).appValue 308 } catch { 309 throw TeraGeneratedRuntimeFailure.from(error) 310 } 311 } 312 313 func profileStatus(operationID: String) async throws -> TeraProfileStatus { 314 do { 315 return try await runtime.phase1ProfileStatus(operationId: operationID).appValue 316 } catch { 317 throw TeraGeneratedRuntimeFailure.from(error) 318 } 319 } 320 321 func advanceProfile(operationID: String) async throws -> TeraProfileStatus { 322 do { 323 return try await runtime.phase1AdvanceProfile(operationId: operationID).appValue 324 } catch { 325 throw TeraGeneratedRuntimeFailure.from(error) 326 } 327 } 328 329 func cancelProfile( 330 operationID: String, 331 expectedRevision: UInt64 332 ) async throws -> TeraProfileStatus { 333 do { 334 return try await runtime.phase1CancelProfile( 335 operationId: operationID, 336 expectedRevision: expectedRevision 337 ).appValue 338 } catch { 339 throw TeraGeneratedRuntimeFailure.from(error) 340 } 341 } 342 343 func advanceDraft(id: String, expectedRevision: UInt64) async throws -> TeraDraftStatus { 344 do { 345 return try await runtime.phase1AdvanceDraft( 346 draftId: id, 347 expectedRevision: expectedRevision 348 ).appValue 349 } catch { 350 throw TeraGeneratedRuntimeFailure.from(error) 351 } 352 } 353 354 func cancelAddIntent( 355 id: String, 356 expectedRevision: UInt64 357 ) async throws -> TeraDraftStatus { 358 do { 359 return try await runtime.phase1CancelAddIntent( 360 draftId: id, 361 expectedRevision: expectedRevision 362 ).appValue 363 } catch { 364 throw TeraGeneratedRuntimeFailure.from(error) 365 } 366 } 367 368 func subscribe( 369 bufferCapacity: Int, 370 receive: @escaping @Sendable (TeraRuntimeChange) async -> Void 371 ) async throws -> any TeraRuntimeSubscriptionToken { 372 let pair = AsyncStream.makeStream( 373 of: TeraRuntimeChange.self, 374 bufferingPolicy: .bufferingNewest(bufferCapacity) 375 ) 376 do { 377 let observer = TeraGeneratedRuntimeObserver(continuation: pair.continuation) 378 let handle = try runtime.subscribeChanges(observer: observer) 379 let deliveryTask = Task { 380 for await change in pair.stream { 381 guard !Task.isCancelled else { break } 382 await receive(change) 383 } 384 } 385 return TeraGeneratedSubscriptionToken( 386 handle: handle, 387 observer: observer, 388 deliveryTask: deliveryTask 389 ) 390 } catch { 391 pair.continuation.finish() 392 throw TeraGeneratedRuntimeFailure.from(error) 393 } 394 } 395 396 func shutdown() async throws -> TeraRuntimeShutdownReceipt { 397 do { 398 let receipt = try await runtime.shutdown() 399 return TeraRuntimeShutdownReceipt( 400 state: receipt.state, 401 alreadyClosed: receipt.alreadyClosed 402 ) 403 } catch { 404 throw TeraGeneratedRuntimeFailure.from(error) 405 } 406 } 407 408 private static func verifiedMediaArtifact( 409 _ record: FfiVerifiedMediaArtifactRecord, 410 expectedArtifactID: String?, 411 requiresOperationID: Bool 412 ) throws -> TeraVerifiedMediaArtifact { 413 guard record.schemaVersion == 1, 414 !requiresOperationID || record.operationId?.isEmpty == false, 415 expectedArtifactID == nil || expectedArtifactID == record.artifactId, 416 let artifact = TeraVerifiedMediaArtifact( 417 artifactID: record.artifactId, 418 bytes: record.bytes, 419 byteSize: record.byteSize, 420 mediaType: record.mediaType, 421 width: record.width, 422 height: record.height 423 ) 424 else { 425 throw TeraRuntimeFailure.local( 426 operation: "runtime.media.artifact", 427 code: "ios.media.artifact_invalid", 428 safeMessage: "The verified photo artifact is invalid." 429 ) 430 } 431 return artifact 432 } 433 } 434 435 extension TeraBlossomHostKind { 436 fileprivate var generatedValue: FfiBlossomHostKind { 437 switch self { 438 case .native: .native 439 case .simulator: .simulator 440 case .physicalDevice: .physicalDevice 441 } 442 } 443 } 444 445 extension TeraBlossomEndpointAuthority { 446 fileprivate var generatedValue: FfiBlossomEndpointAuthority { 447 switch self { 448 case .publicWebPKI: .publicWebPki 449 case .loopbackDevelopment: .loopbackDevelopment 450 case .privateNetworkDevelopment: .privateNetworkDevelopment 451 } 452 } 453 } 454 455 extension FfiBlossomConfigurationRecord { 456 fileprivate var appValue: TeraBlossomConfigurationStatus { 457 TeraBlossomConfigurationStatus( 458 schemaVersion: schemaVersion, 459 hostKind: hostKind, 460 endpointAuthority: endpointAuthority, 461 primaryOrigin: primaryOrigin, 462 fallbackOrigins: fallbackOrigins, 463 configFingerprint: configFingerprint 464 ) 465 } 466 } 467 468 extension FfiBlossomEvidenceRecord { 469 fileprivate var appValue: TeraBlossomEvidence { 470 TeraBlossomEvidence( 471 schemaVersion: schemaVersion, 472 origin: origin, 473 configFingerprint: configFingerprint, 474 state: state, 475 lastSuccessfulState: lastSuccessfulState, 476 transportSecurity: transportSecurity, 477 observedAtUnixMilliseconds: observedAtUnixMs, 478 httpStatus: httpStatus, 479 errorCode: errorCode, 480 serverErrorCode: serverErrorCode, 481 errorPhase: errorPhase, 482 retryable: retryable, 483 possibleOrphan: possibleOrphan, 484 attempts: attempts 485 ) 486 } 487 } 488 489 extension TeraLocalNetwork { 490 var generatedValue: FfiLocalNetworkRecord { 491 FfiLocalNetworkRecord( 492 schemaVersion: schemaVersion, 493 id: id, 494 label: label, 495 relayUrls: relayURLs, 496 locality: locality, 497 followedAuthors: followedAuthors, 498 generation: generation 499 ) 500 } 501 } 502 503 extension TeraTodayProjectionUpdate { 504 fileprivate var generatedValue: FfiTodayProjectionUpdate { 505 switch self { 506 case .incremental: .incremental 507 case .rebuild: .rebuild 508 } 509 } 510 } 511 512 extension FfiMediaReferenceRecord { 513 var appValue: TeraMediaReference { 514 TeraMediaReference( 515 referenceFingerprint: referenceFingerprint, 516 url: url, 517 sha256: sha256, 518 mediaType: mediaType, 519 width: width, 520 height: height, 521 byteSize: byteSize, 522 alt: alt, 523 verification: verification.appValue 524 ) 525 } 526 } 527 528 extension FfiMediaVerificationState { 529 fileprivate var appValue: TeraMediaVerificationState { 530 switch self { 531 case .pending: .pending 532 case .verified: .verified 533 case .failed: .failed 534 case .unavailable: .unavailable 535 } 536 } 537 } 538 539 extension FfiProfileRecord { 540 var appValue: TeraProfileSummary { 541 TeraProfileSummary( 542 authorPublicKey: authorPublicKey, 543 name: name, 544 displayName: displayName, 545 about: about, 546 picture: picture?.appValue, 547 banner: banner?.appValue, 548 nip05: nip05, 549 website: website, 550 lightningAddress: lightningAddress 551 ) 552 } 553 } 554 555 extension FfiSearchResultRecord { 556 fileprivate func appValue() throws -> TeraSearchResult { 557 try TeraSearchResult(type: resultType.appValue, id: stableId, card: card?.appValue(), profile: profile?.appValue) 558 } 559 } 560 561 extension FfiSearchResultType { 562 fileprivate var appValue: TeraSearchResultType { 563 switch self { 564 case .card: .card 565 case .profile: .profile 566 } 567 } 568 } 569 570 extension FfiMeRecord { 571 fileprivate func appValue() throws -> TeraMeSnapshot { 572 try TeraMeSnapshot(publicKey: publicKey, profile: profile?.appValue, cards: cards.map { try $0.appValue() }) 573 } 574 } 575 576 extension FfiThreadEntryRecord { 577 var appValue: TeraThreadEntry { 578 TeraThreadEntry( 579 id: eventId, 580 authorPublicKey: authorPublicKey, 581 content: content, 582 authoredAtUnixSeconds: authoredAtUnixS, 583 type: profile.appValue, 584 root: root, 585 parentEventID: parentEventId, 586 authorProfile: authorProfile?.appValue 587 ) 588 } 589 } 590 591 extension FfiThreadProfile { 592 fileprivate var appValue: TeraThreadEntryType { 593 switch self { 594 case .profile: .profile 595 case .reply: .reply 596 case .comment: .comment 597 case .deletion: .deletion 598 } 599 } 600 } 601 602 extension FfiCardLifecycleState { 603 var appValue: TeraCardLifecycleState { 604 switch self { 605 case .active: .active 606 case .sold: .sold 607 case .past: .past 608 } 609 } 610 } 611 612 extension FfiAddSchemaRecord { 613 fileprivate var appValue: TeraAddSchema { 614 TeraAddSchema( 615 schemaVersion: schemaVersion, 616 commandType: commandType.appValue, 617 label: label, 618 fields: fields.map(\.appValue) 619 ) 620 } 621 } 622 623 extension FfiAddFieldRecord { 624 fileprivate var appValue: TeraAddField { 625 TeraAddField( 626 schemaVersion: schemaVersion, 627 id: id, 628 label: label, 629 kind: kind.appValue, 630 required: required, 631 choices: choices, 632 maxBytes: maxBytes, 633 maxItems: maxItems 634 ) 635 } 636 } 637 638 extension FfiAddFieldKind { 639 fileprivate var appValue: TeraAddFieldKind { 640 switch self { 641 case .text: .text 642 case .multilineText: .multilineText 643 case .date: .date 644 case .dateTime: .dateTime 645 case .decimal: .decimal 646 case .choice: .choice 647 case .location: .location 648 case .media: .media 649 } 650 } 651 } 652 653 extension TeraAddCommandType { 654 var generatedValue: FfiAddCommandType { 655 switch self { 656 case .createUpdate: .createUpdate 657 case .createPhotoUpdate: .createPhotoUpdate 658 case .createAsk: .createAsk 659 case .createEvent: .createEvent 660 case .createFoodAvailability: .createFoodAvailability 661 } 662 } 663 } 664 665 extension FfiEventTimingKind { 666 fileprivate var appValue: TeraEventTiming { 667 switch self { 668 case .allDay: .allDay 669 case .timed: .timed 670 } 671 } 672 } 673 674 extension TeraEventTiming { 675 fileprivate var generatedValue: FfiEventTimingKind { 676 switch self { 677 case .allDay: .allDay 678 case .timed: .timed 679 } 680 } 681 } 682 683 extension TeraAddRuntimeInput { 684 var generatedValue: FfiAddDraftInput { 685 FfiAddDraftInput( 686 schemaVersion: 1, 687 commandType: form.commandType.generatedValue, 688 content: form.content, 689 identifier: form.identifier, 690 title: form.title, 691 summary: form.summary, 692 location: form.location, 693 eventTiming: form.eventTiming?.generatedValue, 694 eventStartDate: TeraCivilDateInput(raw: form.eventStartDate).canonicalOrRaw, 695 eventEndDate: TeraCivilDateInput(raw: form.eventEndDate).canonicalOrRaw, 696 eventStartUnixS: form.eventStartUnixSeconds, 697 eventEndUnixS: form.eventEndUnixSeconds, 698 eventTimezone: form.eventTimezone, 699 priceAmount: form.priceAmount, 700 currency: form.currency, 701 unit: form.unit, 702 quantity: form.quantity, 703 foodPublishedAtUnixS: form.foodPublishedAtUnixSeconds, 704 foodStatus: form.foodStatus, 705 media: media.map(\.generatedValue) 706 ) 707 } 708 } 709 710 extension FfiIdentityLockState { 711 fileprivate var appValue: TeraSettingsIdentityLockState { 712 switch self { 713 case .locked: .locked 714 case .unlocked: .unlocked 715 } 716 } 717 } 718 719 extension FfiSettingsIdentityRecord { 720 fileprivate var appValue: TeraSettingsIdentity { 721 TeraSettingsIdentity(id: id, publicKeyHex: publicKey) 722 } 723 } 724 725 extension FfiIdentityStateRecord { 726 fileprivate var appValue: TeraSettingsIdentityState { 727 TeraSettingsIdentityState( 728 identities: identities.map(\.appValue), 729 activeIdentityID: activeIdentityId, 730 lockState: lockState.appValue, 731 pendingImportOperationID: pendingImportOperationId 732 ) 733 } 734 } 735 736 extension FfiMobileNetworkEnvironment { 737 fileprivate var appValue: TeraSettingsNetworkEnvironment { 738 switch self { 739 case .public: .publicNetwork 740 case .simulator: .simulator 741 case .physicalDevice: .physicalDevice 742 } 743 } 744 } 745 746 extension TeraSettingsNetworkEnvironment { 747 fileprivate var generatedValue: FfiMobileNetworkEnvironment { 748 switch self { 749 case .publicNetwork: .public 750 case .simulator: .simulator 751 case .physicalDevice: .physicalDevice 752 } 753 } 754 } 755 756 extension FfiRelayAccessPreference { 757 fileprivate var appValue: TeraRelayAccessPreference { 758 switch self { 759 case .readOnly: .readOnly 760 case .readWrite: .readWrite 761 } 762 } 763 } 764 765 extension TeraRelayAccessPreference { 766 fileprivate var generatedValue: FfiRelayAccessPreference { 767 switch self { 768 case .readOnly: .readOnly 769 case .readWrite: .readWrite 770 } 771 } 772 } 773 774 extension FfiBlossomAuthorityPreference { 775 fileprivate var appValue: TeraBlossomAuthorityPreference { 776 switch self { 777 case .publicWebPki: .publicWebPKI 778 case .loopbackDevelopment: .loopbackDevelopment 779 case .privateNetworkDevelopment: .privateNetworkDevelopment 780 } 781 } 782 } 783 784 extension TeraBlossomAuthorityPreference { 785 fileprivate var generatedValue: FfiBlossomAuthorityPreference { 786 switch self { 787 case .publicWebPKI: .publicWebPki 788 case .loopbackDevelopment: .loopbackDevelopment 789 case .privateNetworkDevelopment: .privateNetworkDevelopment 790 } 791 } 792 } 793 794 extension FfiMobileSettingsRecord { 795 fileprivate var appValue: TeraMobileSettings { 796 TeraMobileSettings( 797 revision: revision, 798 identity: identity.appValue, 799 networkEnvironment: relays.environment.appValue, 800 relays: relays.endpoints.map { 801 TeraRelayPreference(url: $0.url, access: $0.access.appValue) 802 }, 803 blossomAuthority: blossom.authority.appValue, 804 blossomPrimaryOrigin: blossom.primaryOrigin, 805 blossomFallbackOrigins: blossom.fallbackOrigins, 806 allowCellularDownloads: mediaNetwork.allowCellularDownloads, 807 allowCellularUploads: mediaNetwork.allowCellularUploads, 808 allowBackgroundTransfers: mediaNetwork.allowBackgroundTransfers, 809 mediaCacheBytes: localStorage.mediaCacheBytes, 810 mediaCacheArtifacts: localStorage.mediaCacheArtifacts 811 ) 812 } 813 } 814 815 extension TeraReplaceSettings { 816 fileprivate var generatedValue: FfiReplaceSettingsRecord { 817 let environment = networkEnvironment.generatedValue 818 return FfiReplaceSettingsRecord( 819 schemaVersion: 1, 820 expectedRevision: expectedRevision, 821 relays: FfiRelayPreferencesRecord( 822 schemaVersion: 1, 823 environment: environment, 824 endpoints: relays.map { 825 FfiRelayPreferenceRecord( 826 schemaVersion: 1, 827 url: $0.url, 828 access: $0.access.generatedValue 829 ) 830 } 831 ), 832 blossom: FfiBlossomPreferencesRecord( 833 schemaVersion: 1, 834 environment: environment, 835 authority: blossomAuthority.generatedValue, 836 primaryOrigin: blossomPrimaryOrigin, 837 fallbackOrigins: blossomFallbackOrigins 838 ), 839 mediaNetwork: FfiMediaNetworkPolicyRecord( 840 schemaVersion: 1, 841 allowCellularDownloads: allowCellularDownloads, 842 allowCellularUploads: allowCellularUploads, 843 allowBackgroundTransfers: allowBackgroundTransfers 844 ), 845 localStorage: FfiLocalStoragePolicyRecord( 846 schemaVersion: 1, 847 mediaCacheBytes: mediaCacheBytes, 848 mediaCacheArtifacts: mediaCacheArtifacts 849 ) 850 ) 851 } 852 } 853 854 extension FfiSettingsTransitionRecord { 855 fileprivate var appValue: TeraSettingsTransition { 856 TeraSettingsTransition( 857 settings: settings.appValue, 858 runtimeRestartRequired: runtimeRestartRequired, 859 outboxRequeueRequired: outboxRequeueRequired, 860 mediaCacheInvalidationRequired: mediaCacheInvalidationRequired 861 ) 862 } 863 } 864 865 extension TeraIdentityCommandKind { 866 fileprivate var generatedValue: FfiIdentityCommandKind { 867 switch self { 868 case .beginImport: .beginImport 869 case .completeImport: .completeImport 870 case .cancelImport: .cancelImport 871 case .select: .select 872 case .lock: .lock 873 case .unlock: .unlock 874 case .recover: .recover 875 } 876 } 877 } 878 879 extension TeraIdentityCommand { 880 fileprivate var generatedValue: FfiIdentityCommandRecord { 881 FfiIdentityCommandRecord( 882 schemaVersion: 1, 883 kind: kind.generatedValue, 884 operationId: operationID, 885 identityId: identityID, 886 publicKey: publicKeyHex 887 ) 888 } 889 } 890 891 extension TeraProfileMetadataInput { 892 fileprivate var generatedValue: FfiProfileMetadataInputRecord { 893 FfiProfileMetadataInputRecord( 894 schemaVersion: 1, 895 name: name, 896 displayName: displayName, 897 about: about, 898 picture: picture?.generatedValue, 899 banner: banner?.generatedValue, 900 nip05: nip05, 901 bot: bot 902 ) 903 } 904 } 905 906 extension FfiProfileStatusRecord { 907 fileprivate var appValue: TeraProfileStatus { 908 TeraProfileStatus( 909 id: operationId, 910 revision: revision, 911 authorPublicKey: authorPublicKey, 912 state: state.appValue, 913 deliveryID: deliveryId, 914 createdAtUnixMilliseconds: createdAtUnixMs, 915 updatedAtUnixMilliseconds: updatedAtUnixMs, 916 settlement: settlement?.appValue 917 ) 918 } 919 } 920 921 extension FfiDraftFormMediaRecord { 922 fileprivate var appValue: TeraPreparedMedia { 923 TeraPreparedMedia( 924 opaqueReference: opaqueReference, 925 remoteURL: url, 926 sha256: sha256, 927 mediaType: mediaType, 928 byteSize: byteSize, 929 width: width, 930 height: height, 931 alt: alt, 932 preparedAtUnixSeconds: preparedAtUnixS 933 ) 934 } 935 } 936 937 extension FfiDraftFormRecord { 938 var appValue: TeraAddForm { 939 TeraAddForm( 940 commandType: commandType.appValue, 941 content: content, 942 identifier: identifier, 943 title: title, 944 summary: summary, 945 location: location, 946 eventTiming: eventTiming?.appValue, 947 eventStartDate: eventStartDate, 948 eventEndDate: eventEndDate, 949 eventStartUnixSeconds: eventStartUnixS, 950 eventEndUnixSeconds: eventEndUnixS, 951 eventTimezone: eventTimezone, 952 priceAmount: priceAmount, 953 currency: currency, 954 unit: unit, 955 quantity: quantity, 956 foodPublishedAtUnixSeconds: foodPublishedAtUnixS, 957 foodStatus: foodStatus, 958 media: media.map(\.appValue) 959 ) 960 } 961 } 962 963 extension FfiRelayAccessRecord { 964 fileprivate var appValue: TeraRelayAccess { 965 switch self { 966 case .readOnly: .readOnly 967 case .readWrite: .readWrite 968 } 969 } 970 } 971 972 extension FfiMediaStage { 973 var appValue: TeraDraftMediaStage { 974 switch self { 975 case .pending: .pending 976 case .preparing: .preparing 977 case .uploading: .uploading 978 case .verified: .verified 979 case .failed: .failed 980 case .orphaned: .orphaned 981 } 982 } 983 } 984 985 extension FfiOperationSettlementRecord { 986 var appValue: TeraOperationSettlement { 987 TeraOperationSettlement( 988 artifacts: artifacts, 989 signed: signed, 990 admitted: admitted, 991 pending: pending, 992 retryable: retryable, 993 indeterminate: indeterminate, 994 failedTerminal: failedTerminal, 995 cancelled: cancelled, 996 deliveryPlans: deliveryPlans, 997 deliverySatisfied: deliverySatisfied, 998 deliveryPending: deliveryPending, 999 deliveryRetryable: deliveryRetryable, 1000 deliveryExhausted: deliveryExhausted, 1001 deliveryFailedTerminal: deliveryFailedTerminal, 1002 deliveryCancelled: deliveryCancelled 1003 ) 1004 } 1005 } 1006 1007 extension TeraRetractionDraftInput { 1008 fileprivate var generatedValue: FfiRetractionDraftInput { 1009 FfiRetractionDraftInput( 1010 schemaVersion: 1, 1011 commandType: commandType.generatedValue, 1012 targetCardId: targetCardID, 1013 targetEventId: targetEventID, 1014 targetKind: targetKind, 1015 targetAddress: targetAddress, 1016 reason: reason 1017 ) 1018 } 1019 } 1020 1021 extension TeraBlossomUploadIntent { 1022 fileprivate var generatedValue: FfiBlossomUploadIntent { 1023 FfiBlossomUploadIntent( 1024 schemaVersion: 1, 1025 draftId: draftID, 1026 expectedRevision: expectedRevision, 1027 media: media.generatedValue 1028 ) 1029 } 1030 } 1031 1032 extension TeraNativeUploadCompletion { 1033 fileprivate var generatedValue: FfiNativeUploadCompletionInput { 1034 FfiNativeUploadCompletionInput( 1035 schemaVersion: 1, 1036 draftId: draftID, 1037 expectedRevision: expectedRevision, 1038 media: media.generatedValue, 1039 statusCode: statusCode, 1040 responseMediaType: responseMediaType, 1041 responseContentEncoding: responseContentEncoding, 1042 responseBody: responseBody 1043 ) 1044 } 1045 } 1046 1047 extension TeraGeneratedRuntimeBackend { 1048 func reconcileToday(request: TeraTodayReconcileRequest) async throws -> TeraTodayPage { 1049 do { return try await TeraGeneratedTodayReads.reconcile(runtime: runtime, request: request) } catch { throw TeraGeneratedRuntimeFailure.from(error) } 1050 } 1051 1052 func todayPage(request: TeraTodayPageRequest) async throws -> TeraTodayPage { 1053 do { return try await TeraGeneratedTodayReads.page(runtime: runtime, request: request) } catch { throw TeraGeneratedRuntimeFailure.from(error) } 1054 } 1055 1056 func refreshToday( 1057 context: TeraLocalNetwork, nowUnixSeconds: UInt64, 1058 update: TeraTodayProjectionUpdate, backfillCursor: String? 1059 ) async throws -> TeraTodaySyncReceipt { 1060 do { 1061 return try await TeraGeneratedTodayOperation.run( 1062 runtime: runtime, context: context.generatedValue, nowUnixSeconds: nowUnixSeconds, 1063 update: update.generatedValue, backfillCursor: backfillCursor 1064 ).appValue 1065 } catch { throw TeraGeneratedRuntimeFailure.from(error) } 1066 } 1067 } 1068 1069 extension TeraGeneratedRuntimeBackend { 1070 func draftStatus(id: String) async throws -> TeraDraftStatus { 1071 do { 1072 return try await runtime.phase1DraftStatus(draftId: id).appValue 1073 } catch { 1074 throw TeraGeneratedRuntimeFailure.from(error) 1075 } 1076 } 1077 1078 func draftHeads(limit: UInt16) async throws -> [TeraDraftStatus] { 1079 do { 1080 return try await runtime.phase1DraftHeads(limit: limit).map(\.appValue) 1081 } catch { 1082 throw TeraGeneratedRuntimeFailure.from(error) 1083 } 1084 } 1085 1086 func legacyDraftPage(limit: UInt16, cursor: String?) async throws -> TeraLegacyDraftPage { 1087 do { return try await TeraGeneratedDraftInventory.page(runtime: runtime, limit: limit, cursor: cursor) } catch { throw TeraGeneratedRuntimeFailure.from(error) } 1088 } 1089 }