├── .gitattributes
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── feature_request.md
│ └── something-else.md
└── workflows
│ └── ts.yml
├── .gitignore
├── .idea
├── .gitignore
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── compiler.xml
├── dictionaries
│ └── andym.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── jsLibraryMappings.xml
├── jsLinters
│ └── eslint.xml
├── markdown.xml
├── metabook.iml
├── misc.xml
├── modules.xml
├── prettier.xml
├── scopes
│ └── source_files.xml
├── vcs.xml
└── watcherTasks.xml
├── .node-version
├── .vscode
├── settings.json
└── tasks.json
├── LICENSE
├── LICENSE-AGPL-3.0-or-later
├── LICENSE-Apache-2.0
├── LICENSE-BUSL-1.1
├── NOTICE
├── Readme.md
├── bun.lockb
├── design
├── reveal answer - scale.origami
├── reveal answer and advance question - fade.origami
├── starburst-icon-iOS.svg
├── starburst-icon-iOS_1024x1024.png
├── starburst-icon-iOS_20x20.png
├── starburst-icon-iOS_20x20@2x.png
├── starburst-icon-iOS_20x20@3x.png
├── starburst-icon-iOS_29x29.png
├── starburst-icon-iOS_29x29@2x.png
├── starburst-icon-iOS_29x29@3x.png
├── starburst-icon-iOS_40x40.png
├── starburst-icon-iOS_40x40@2x.png
├── starburst-icon-iOS_40x40@3x.png
├── starburst-icon-iOS_60x60@2x.png
├── starburst-icon-iOS_60x60@3x.png
├── starburst-icon-iOS_76x76.png
├── starburst-icon-iOS_76x76@2x.png
├── starburst-icon-iOS_83-5x83-5@2x.png
├── starburst-icon-macOS_1024x1024.png
├── starburst-icon-macOS_128x128.png
├── starburst-icon-macOS_128x128@2x.png
├── starburst-icon-macOS_16x16.png
├── starburst-icon-macOS_16x16@2x.png
├── starburst-icon-macOS_256x256.png
├── starburst-icon-macOS_256x256@2x.png
├── starburst-icon-macOS_32x32.png
├── starburst-icon-macOS_32x32@2x.png
├── starburst-icon-macOS_512x512.png
├── starburst-icon-macOS_512x512@2x.png
├── starburst-icon.fig
├── starburst-icon.md
└── starburst-icon.svg
├── package.json
└── packages
├── .eslintignore
├── .eslintrc.js
├── .prettierrc.js
├── anki-import
├── LICENSE
├── Readme.md
├── babel.config.cjs
├── jest.config.cjs
├── package.json
├── src
│ ├── __fixtures__
│ │ ├── testAnkiData.ts
│ │ ├── testCollection.colpkg
│ │ └── withTestAnkiCollection.ts
│ ├── ankiPkg
│ │ ├── ankiAttachmentReference.ts
│ │ ├── ankiCollection.test.ts
│ │ ├── ankiCollection.ts
│ │ ├── ankiDBTypes.ts
│ │ ├── index.ts
│ │ ├── parseAnkiField.test.ts
│ │ ├── parseAnkiField.ts
│ │ ├── splitAnkiDBNoteFields.test.ts
│ │ └── splitAnkiDBNoteFields.ts
│ ├── convertAnkiID.ts
│ ├── importPlan.test.ts
│ ├── importPlan.ts
│ ├── index.ts
│ ├── modelMapping.test.ts
│ ├── modelMapping.ts
│ ├── noteMapping.test.ts
│ └── noteMapping.ts
└── tsconfig.json
├── api-client
├── .gitignore
├── LICENSE
├── Readme.md
├── babel.config.cjs
├── jest.config.cjs
├── package.json
├── src
│ ├── apiConfig.ts
│ ├── index.ts
│ ├── orbitAPIClient.ts
│ ├── requestManager.test.ts
│ ├── requestManager.ts
│ └── util
│ │ ├── fetch.native.ts
│ │ ├── fetch.ts
│ │ └── mockAPIValiation.ts
└── tsconfig.json
├── api
├── LICENSE
├── Readme.md
├── babel.config.cjs
├── jest.config.cjs
├── package.json
├── src
│ ├── genericHTTPAPI.ts
│ ├── index.ts
│ ├── orbitAPI.ts
│ ├── orbitAPISchema.json
│ ├── util
│ │ └── requiredSpec.ts
│ └── validation
│ │ ├── ajvAPIValidator.test.ts
│ │ ├── ajvAPIValidator.ts
│ │ ├── apiValidator.ts
│ │ └── orbitAPIValidator.ts
└── tsconfig.json
├── app
├── .firebaserc
├── .gitignore
├── LICENSE
├── LICENSE-AGPL-3.0-or-later
├── LICENSE-BUSL-1.1
├── Readme.md
├── app-assets
│ └── starburst-icon.png
├── app.json
├── assets
├── babel.config.js
├── expoPlugin
│ ├── expoPlugin.js
│ ├── ios
│ │ ├── AppDelegate+Intents.m
│ │ ├── AppDelegate+KeyHandling.m
│ │ ├── IngestEventEmitter.h
│ │ ├── IngestEventEmitter.m
│ │ ├── IngestEventHandler.h
│ │ ├── IngestEventHandler.m
│ │ ├── Intents.intentdefinition
│ │ ├── ORSQLImageURLLoader.h
│ │ ├── ORSQLImageURLLoader.m
│ │ ├── ORWidgetReloadBridge.m
│ │ └── ORWidgetReloadBridge.swift
│ ├── util.js
│ ├── withCatalystSupport.js
│ ├── withIngestIntent.js
│ ├── withReactNativeKeyEventSupport.js
│ ├── withSQLImageURLLoader.js
│ └── withWidgetPluginFixes.js
├── firebase.json
├── metro.config.js
├── package.json
├── public
│ ├── browserCompatibility.js
│ └── index.html
├── scripts
│ ├── buildWidget.ts
│ ├── deploy_web.sh
│ └── generate_browser_compatibility_regex.sh
├── serviceConfig.js
├── src
│ ├── ReviewSessionContainer.tsx
│ ├── app
│ │ ├── (auth)
│ │ │ ├── _layout.tsx
│ │ │ ├── embed.tsx
│ │ │ ├── login.tsx
│ │ │ ├── review.tsx
│ │ │ └── settings.tsx
│ │ ├── (index)
│ │ │ ├── _layout.tsx
│ │ │ ├── _layout.web.tsx
│ │ │ ├── index.tsx
│ │ │ └── index.web.tsx
│ │ ├── _layout.tsx
│ │ ├── download.tsx
│ │ ├── learnMore.tsx
│ │ └── terms.tsx
│ ├── authentication
│ │ ├── authContext.ts
│ │ ├── authenticationClient.ts
│ │ ├── firebaseAuthenticationClient.ts
│ │ ├── index.ts
│ │ ├── isBrowserStorageAvailable.native.ts
│ │ ├── isBrowserStorageAvailable.ts
│ │ └── loginTokenBroadcastChannel.ts
│ ├── embedded
│ │ ├── EmbeddedBanner.tsx
│ │ ├── OnboardingModal.web.tsx
│ │ ├── TestModeBanner.tsx
│ │ ├── embeddedNetworkQueue.ts
│ │ ├── ipc
│ │ │ ├── sendUpdatedReviewItemToHost.ts
│ │ │ └── useEmbeddedHostState.ts
│ │ ├── markingActions.ts
│ │ ├── useEmbeddedAuthenticationState.ts
│ │ ├── useRemoteTaskStates.ts
│ │ └── util
│ │ │ ├── findItemsToRetry.test.ts
│ │ │ ├── findItemsToRetry.ts
│ │ │ ├── getEmbeddedColorPalette.ts
│ │ │ └── getEmbeddedScreenConfigurationFromURL.ts
│ ├── errorReporting.ts
│ ├── homeRedirect
│ │ ├── homeRedirect.tsx
│ │ └── homeRedirect.web.tsx
│ ├── index.js
│ ├── infoPage
│ │ ├── InfoPage.tsx
│ │ ├── InfoPage.web.tsx
│ │ └── InfoPageShared.tsx
│ ├── model2
│ │ ├── databaseManager.ts
│ │ ├── orbitStoreFactory.ts
│ │ └── orbitStoreFactory.web.ts
│ ├── reviewSession
│ │ ├── LoadingScreen.tsx
│ │ └── ReviewSession.tsx
│ ├── reviewSessionManager.ts
│ ├── signIn
│ │ └── SignInForm.tsx
│ ├── util
│ │ ├── firebase.ts
│ │ ├── firebaseAuth.ts
│ │ ├── firebaseAuth.web.ts
│ │ ├── intents
│ │ │ ├── IntentHandler.ts
│ │ │ ├── IntentHandler.web.ts
│ │ │ └── handleIngestEvent.ts
│ │ ├── shims.ts
│ │ ├── shims.web.ts
│ │ ├── task.ts
│ │ ├── useAPIClient.tsx
│ │ ├── useAsyncResult.ts
│ │ ├── useByrefCallback.ts
│ │ ├── usePageViewTracking.ts
│ │ └── usePageViewTracking.web.ts
│ └── widget.ts
├── targets
│ └── widgets
│ │ ├── Assets.xcassets
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ ├── App-Icon-20x20@1x.png
│ │ │ ├── App-Icon-20x20@2x.png
│ │ │ ├── App-Icon-20x20@3x.png
│ │ │ ├── App-Icon-29x29@1x.png
│ │ │ ├── App-Icon-29x29@2x.png
│ │ │ ├── App-Icon-29x29@3x.png
│ │ │ ├── App-Icon-40x40@1x.png
│ │ │ ├── App-Icon-40x40@2x.png
│ │ │ ├── App-Icon-40x40@3x.png
│ │ │ ├── App-Icon-60x60@2x.png
│ │ │ ├── App-Icon-60x60@3x.png
│ │ │ ├── App-Icon-76x76@1x.png
│ │ │ ├── App-Icon-76x76@2x.png
│ │ │ ├── App-Icon-83.5x83.5@2x.png
│ │ │ ├── Contents.json
│ │ │ └── ItunesArtwork@2x.png
│ │ ├── Contents.json
│ │ ├── WidgetBackground.colorset
│ │ │ └── Contents.json
│ │ ├── check-center.imageset
│ │ │ ├── Contents.json
│ │ │ └── check-center.svg
│ │ ├── cross-center.imageset
│ │ │ ├── Contents.json
│ │ │ └── cross-center.svg
│ │ ├── reveal-accent-center.imageset
│ │ │ ├── Contents.json
│ │ │ └── reveal-accent-center.svg
│ │ └── reveal-center.imageset
│ │ │ ├── Contents.json
│ │ │ └── reveal-center.svg
│ │ ├── Bridge.swift
│ │ ├── Colors.swift
│ │ ├── Fonts.swift
│ │ ├── Info.plist
│ │ ├── OrbitTask.swift
│ │ ├── OrbitWidgetBundle.swift
│ │ ├── PrivacyInfo.xcprivacy
│ │ ├── Widget.swift
│ │ ├── expo-target.config.json
│ │ └── generated.entitlements
└── tsconfig.json
├── babel.config.js
├── backend
├── .firebaserc
├── .gitignore
├── LICENSE
├── LICENSE-AGPL-3.0-or-later
├── LICENSE-BUSL-1.1
├── Readme.md
├── babel.config.cjs
├── bigQuerySchemas
│ ├── events.json
│ ├── pageViews.json
│ ├── sessionNotifications.json
│ └── userEvents.json
├── emulator-data
│ ├── auth_export
│ │ ├── accounts.json
│ │ └── config.json
│ ├── firebase-export-metadata.json
│ └── firestore_export
│ │ ├── all_namespaces
│ │ └── all_kinds
│ │ │ ├── all_namespaces_all_kinds.export_metadata
│ │ │ └── output-0
│ │ └── firestore_export.overall_export_metadata
├── firebase-storage-cors.json
├── firebase.json
├── firestore.indexes.json
├── firestore.rules
├── jest.config.cjs
├── package.json
├── scripts
│ ├── deployShared.js
│ ├── postdeploy.js
│ └── predeploy.js
├── src
│ ├── @types
│ │ └── isbot-fast
│ │ │ └── index.d.ts
│ ├── __tests__
│ │ ├── emulators.ts
│ │ ├── firebaseTesting.ts
│ │ └── integration
│ │ │ ├── attachments.test.ts
│ │ │ ├── auth.test.ts
│ │ │ ├── events.test.ts
│ │ │ ├── updateNotificationSettings.test.ts
│ │ │ └── utils
│ │ │ └── fetchRoute.ts
│ ├── api.ts
│ ├── api
│ │ ├── attachments.ts
│ │ ├── events.ts
│ │ ├── internal
│ │ │ ├── auth
│ │ │ │ ├── consumeAccessCode.ts
│ │ │ │ ├── createLoginToken.ts
│ │ │ │ ├── personalAccessTokens.ts
│ │ │ │ ├── refreshSessionCookie.ts
│ │ │ │ └── sessionCookie.ts
│ │ │ └── recordPageView.ts
│ │ ├── internalSpec.ts
│ │ ├── tasks.ts
│ │ └── util
│ │ │ ├── authenticateRequest.ts
│ │ │ ├── corsHandler.ts
│ │ │ ├── putAndLogEvents.ts
│ │ │ └── typedRouter.ts
│ ├── attachments.test.ts
│ ├── attachments.ts
│ ├── db
│ │ ├── firebaseAccountData.ts
│ │ ├── firebaseAuth.ts
│ │ ├── firestore.ts
│ │ ├── firestoreDatabaseBackend.test.ts
│ │ ├── firestoreDatabaseBackend.ts
│ │ ├── index.ts
│ │ ├── orderedID.test.ts
│ │ ├── orderedID.ts
│ │ ├── userMetadata.ts
│ │ └── withFirebaseFields.ts
│ ├── email
│ │ ├── dummy.ts
│ │ ├── index.ts
│ │ ├── mailjet.ts
│ │ └── types.ts
│ ├── fileStorageService
│ │ ├── fileStorageService.ts
│ │ ├── googleCloudFileStorageService.ts
│ │ ├── index.ts
│ │ ├── localFileStorageService.test.ts
│ │ └── localFileStorageService.ts
│ ├── firebaseApp.ts
│ ├── firebaseFunctions
│ │ ├── api.ts
│ │ ├── notifier
│ │ │ ├── index.ts
│ │ │ ├── notificationScheduler.ts
│ │ │ └── processUserNotificationSubscriber.ts
│ │ ├── onUserCreate.ts
│ │ └── updateNotificationSettings.ts
│ ├── index.ts
│ ├── logging
│ │ ├── bigQuery.ts
│ │ ├── dummy.ts
│ │ ├── index.ts
│ │ └── interface.ts
│ ├── notifications
│ │ ├── __fixtures__
│ │ │ └── generateDueTasks.ts
│ │ ├── index.ts
│ │ ├── processUserNotification.test.ts
│ │ ├── processUserNotification.ts
│ │ ├── reviewSessionEmails.ts
│ │ ├── reviewSessionScheduling.test.ts
│ │ ├── reviewSessionScheduling.ts
│ │ ├── shouldEvaluateUserForNotification.test.ts
│ │ └── shouldEvaluateUserForNotification.ts
│ ├── serviceConfig.ts
│ └── util
│ │ ├── isRunningInEmulator.ts
│ │ └── isRunningInTest.ts
├── storage.rules
└── tsconfig.json
├── core
├── LICENSE
├── Readme.md
├── babel.config.cjs
├── jest.config.cjs
├── package.json
├── src
│ ├── __tests__
│ │ └── testTasks.ts
│ ├── colorPaletteName.ts
│ ├── entities
│ │ ├── attachmentReference.ts
│ │ ├── task.ts
│ │ └── util
│ │ │ └── parseClozeMarkup.ts
│ ├── entity.ts
│ ├── event.ts
│ ├── eventReducer.ts
│ ├── eventReducers
│ │ ├── attachmentReducers.ts
│ │ ├── taskReducers.test.ts
│ │ └── taskReducers.ts
│ ├── generateUniqueID.test.ts
│ ├── generateUniqueID.ts
│ ├── index.ts
│ ├── reviewQueue.test.ts
│ ├── reviewQueue.ts
│ ├── scheduler.ts
│ ├── schedulers
│ │ ├── spacedRepetitionScheduler.test.ts
│ │ └── spacedRepetitionScheduler.ts
│ └── util
│ │ ├── crypto.native.ts
│ │ ├── crypto.ts
│ │ └── crypto.web.ts
└── tsconfig.json
├── docs
├── .firebaserc
├── .gitignore
├── 404.html
├── LICENSE
├── Readme.md
├── firebase.json
├── index.html
├── package.json
├── test.html
└── toffoli.png
├── embedded-support
├── LICENSE
├── Readme.md
├── package.json
├── src
│ ├── embeddedScreenInterface.ts
│ ├── index.ts
│ └── ipc.ts
└── tsconfig.json
├── ingester
├── LICENSE
├── Readme.md
├── babel.config.cjs
├── jest.config.cjs
├── package.json
├── src
│ ├── bin
│ │ └── run.ts
│ ├── index.ts
│ ├── ingest.test.ts
│ ├── ingest.ts
│ ├── ingestible.json
│ ├── ingestible.ts
│ ├── validateIngestible.test.ts
│ └── validateIngestible.ts
└── tsconfig.json
├── interpreter
├── LICENSE
├── Readme.md
├── babel.config.cjs
├── jest.config.cjs
├── package.json
├── src
│ ├── bin
│ │ ├── migrateNoteSync.ts
│ │ └── run.ts
│ ├── hasher
│ │ ├── CryptoBase64Hasher.test.ts
│ │ ├── CryptoBase64Hasher.ts
│ │ └── hasher.ts
│ ├── interpreter.ts
│ └── interpreters
│ │ ├── index.ts
│ │ └── markdown
│ │ ├── MarkdownInterpreter.test.ts
│ │ ├── MarkdownInterpreter.ts
│ │ ├── __snapshots__
│ │ └── MarkdownInterpreter.test.ts.snap
│ │ ├── markdown.test.ts
│ │ ├── markdown.ts
│ │ ├── plugins
│ │ ├── bearIDPlugin.test.ts
│ │ ├── bearIDPlugin.ts
│ │ ├── clozePromptPlugin.test.ts
│ │ ├── clozePromptPlugin.ts
│ │ ├── qaPromptPlugin.test.ts
│ │ └── qaPromptPlugin.ts
│ │ └── utils
│ │ ├── getNoteTitle.test.ts
│ │ ├── getNoteTitle.ts
│ │ ├── getStableBearID.test.ts
│ │ └── getStableBearID.ts
└── tsconfig.json
├── jest.config.js
├── sample-data
├── LICENSE
├── Readme.md
├── package.json
├── src
│ ├── index.ts
│ ├── testClozeSpec.ts
│ ├── testQASpec.ts
│ └── testTasks.ts
└── tsconfig.json
├── store-fs
├── LICENSE
├── Readme.md
├── babel.config.cjs
├── jest.config.cjs
├── package.json
├── src
│ ├── attachmentStoreFS.ts
│ ├── database.test.ts
│ ├── index.ts
│ ├── orbitStoreFS.test.ts
│ ├── orbitStoreFS.ts
│ ├── orbitStoreInMemory.ts
│ ├── sqlite.test.ts
│ ├── sqlite.ts
│ ├── sqlite
│ │ ├── binding.native.ts
│ │ ├── binding.ts
│ │ ├── metadata.ts
│ │ ├── migration.ts
│ │ ├── migrations
│ │ │ ├── 20210612111147_createMetadataTable.ts
│ │ │ ├── 20210612112129_initialSchema.ts
│ │ │ ├── 20211019170802_createAttachmentsTable.ts
│ │ │ ├── 20230726103155_derived_taskComponents_whenNotDeleted.ts
│ │ │ ├── index.ts
│ │ │ └── migrationType.ts
│ │ ├── tables.ts
│ │ └── types.ts
│ └── util
│ │ └── getPathForAttachment.ts
└── tsconfig.json
├── store-shared
├── LICENSE
├── Readme.md
├── package.json
├── src
│ ├── attachmentStore.ts
│ ├── database.ts
│ ├── databaseBackend.ts
│ ├── databaseQuery.ts
│ ├── databaseTests.ts
│ ├── encodeDataURL.ts
│ ├── index.ts
│ ├── orbitStore.ts
│ └── validation
│ │ ├── AjvEventsValidator.ts
│ │ ├── events.json
│ │ └── eventsValidator.ts
└── tsconfig.json
├── store-web
├── LICENSE
├── Readme.md
├── babel.config.cjs
├── jest.config.cjs
├── package.json
├── src
│ ├── attachmentStoreWeb.test.ts
│ ├── attachmentStoreWeb.ts
│ ├── database.test.ts
│ ├── dexie
│ │ ├── dexie.ts
│ │ └── tables.ts
│ ├── index.ts
│ ├── indexedDB.test.ts
│ ├── indexedDB.ts
│ └── orbitStoreWeb.ts
└── tsconfig.json
├── sync
├── LICENSE
├── Readme.md
├── babel.config.cjs
├── jest.config.cjs
├── package.json
├── src
│ ├── APISyncAdapter.ts
│ ├── bin
│ │ └── run.ts
│ ├── index.ts
│ ├── orbitStoreSyncAdapter.ts
│ ├── sync.test.ts
│ ├── sync.ts
│ └── syncAdapter.ts
└── tsconfig.json
├── tsconfig.base.json
├── tsconfig.json
├── ui
├── .gitignore
├── .storybook
│ ├── main.cjs
│ └── preview.cjs
├── LICENSE
├── Readme.md
├── assets
│ ├── fonts
│ │ ├── .gitignore
│ │ ├── KaTeX_AMS-Regular.ttf
│ │ ├── KaTeX_AMS-Regular.woff
│ │ ├── KaTeX_AMS-Regular.woff2
│ │ ├── KaTeX_Caligraphic-Bold.ttf
│ │ ├── KaTeX_Caligraphic-Bold.woff
│ │ ├── KaTeX_Caligraphic-Bold.woff2
│ │ ├── KaTeX_Caligraphic-Regular.ttf
│ │ ├── KaTeX_Caligraphic-Regular.woff
│ │ ├── KaTeX_Caligraphic-Regular.woff2
│ │ ├── KaTeX_Fraktur-Bold.ttf
│ │ ├── KaTeX_Fraktur-Bold.woff
│ │ ├── KaTeX_Fraktur-Bold.woff2
│ │ ├── KaTeX_Fraktur-Regular.ttf
│ │ ├── KaTeX_Fraktur-Regular.woff
│ │ ├── KaTeX_Fraktur-Regular.woff2
│ │ ├── KaTeX_Main-Bold.ttf
│ │ ├── KaTeX_Main-Bold.woff
│ │ ├── KaTeX_Main-Bold.woff2
│ │ ├── KaTeX_Main-BoldItalic.ttf
│ │ ├── KaTeX_Main-BoldItalic.woff
│ │ ├── KaTeX_Main-BoldItalic.woff2
│ │ ├── KaTeX_Main-Italic.ttf
│ │ ├── KaTeX_Main-Italic.woff
│ │ ├── KaTeX_Main-Italic.woff2
│ │ ├── KaTeX_Main-Regular.ttf
│ │ ├── KaTeX_Main-Regular.woff
│ │ ├── KaTeX_Main-Regular.woff2
│ │ ├── KaTeX_Math-BoldItalic.ttf
│ │ ├── KaTeX_Math-BoldItalic.woff
│ │ ├── KaTeX_Math-BoldItalic.woff2
│ │ ├── KaTeX_Math-Italic.ttf
│ │ ├── KaTeX_Math-Italic.woff
│ │ ├── KaTeX_Math-Italic.woff2
│ │ ├── KaTeX_SansSerif-Bold.ttf
│ │ ├── KaTeX_SansSerif-Bold.woff
│ │ ├── KaTeX_SansSerif-Bold.woff2
│ │ ├── KaTeX_SansSerif-Italic.ttf
│ │ ├── KaTeX_SansSerif-Italic.woff
│ │ ├── KaTeX_SansSerif-Italic.woff2
│ │ ├── KaTeX_SansSerif-Regular.ttf
│ │ ├── KaTeX_SansSerif-Regular.woff
│ │ ├── KaTeX_SansSerif-Regular.woff2
│ │ ├── KaTeX_Script-Regular.ttf
│ │ ├── KaTeX_Script-Regular.woff
│ │ ├── KaTeX_Script-Regular.woff2
│ │ ├── KaTeX_Size1-Regular.ttf
│ │ ├── KaTeX_Size1-Regular.woff
│ │ ├── KaTeX_Size1-Regular.woff2
│ │ ├── KaTeX_Size2-Regular.ttf
│ │ ├── KaTeX_Size2-Regular.woff
│ │ ├── KaTeX_Size2-Regular.woff2
│ │ ├── KaTeX_Size3-Regular.ttf
│ │ ├── KaTeX_Size3-Regular.woff
│ │ ├── KaTeX_Size3-Regular.woff2
│ │ ├── KaTeX_Size4-Regular.ttf
│ │ ├── KaTeX_Size4-Regular.woff
│ │ ├── KaTeX_Size4-Regular.woff2
│ │ ├── KaTeX_Typewriter-Regular.ttf
│ │ ├── KaTeX_Typewriter-Regular.woff
│ │ └── KaTeX_Typewriter-Regular.woff2
│ ├── icons
│ │ ├── check-BL.png
│ │ ├── check-BL.svg
│ │ ├── check-BL@2x.png
│ │ ├── check-BL@3x.png
│ │ ├── check-BR.png
│ │ ├── check-BR.svg
│ │ ├── check-BR@2x.png
│ │ ├── check-BR@3x.png
│ │ ├── check-TL.png
│ │ ├── check-TL.svg
│ │ ├── check-TL@2x.png
│ │ ├── check-TL@3x.png
│ │ ├── check-TR.png
│ │ ├── check-TR.svg
│ │ ├── check-TR@2x.png
│ │ ├── check-TR@3x.png
│ │ ├── check-center.png
│ │ ├── check-center.svg
│ │ ├── check-center@2x.png
│ │ ├── check-center@3x.png
│ │ ├── cross-BL.png
│ │ ├── cross-BL.svg
│ │ ├── cross-BL@2x.png
│ │ ├── cross-BL@3x.png
│ │ ├── cross-BR.png
│ │ ├── cross-BR.svg
│ │ ├── cross-BR@2x.png
│ │ ├── cross-BR@3x.png
│ │ ├── cross-TL.png
│ │ ├── cross-TL.svg
│ │ ├── cross-TL@2x.png
│ │ ├── cross-TL@3x.png
│ │ ├── cross-TR.png
│ │ ├── cross-TR.svg
│ │ ├── cross-TR@2x.png
│ │ ├── cross-TR@3x.png
│ │ ├── cross-center.png
│ │ ├── cross-center.svg
│ │ ├── cross-center@2x.png
│ │ ├── cross-center@3x.png
│ │ ├── dots-center.png
│ │ ├── dots-center.svg
│ │ ├── dots-center@2x.png
│ │ ├── dots-center@3x.png
│ │ ├── doubleRight-TL.png
│ │ ├── doubleRight-TL.svg
│ │ ├── doubleRight-TL@2x.png
│ │ ├── doubleRight-TL@3x.png
│ │ ├── doubleRight-center.png
│ │ ├── doubleRight-center.svg
│ │ ├── doubleRight-center@2x.png
│ │ ├── doubleRight-center@3x.png
│ │ ├── left-center.png
│ │ ├── left-center.svg
│ │ ├── left-center@2x.png
│ │ ├── left-center@3x.png
│ │ ├── list-center.png
│ │ ├── list-center.svg
│ │ ├── list-center@2x.png
│ │ ├── list-center@3x.png
│ │ ├── reveal-accent-bottom.png
│ │ ├── reveal-accent-bottom.svg
│ │ ├── reveal-accent-bottom@2x.png
│ │ ├── reveal-accent-bottom@3x.png
│ │ ├── reveal-accent-center.png
│ │ ├── reveal-accent-center.svg
│ │ ├── reveal-accent-center@2x.png
│ │ ├── reveal-accent-center@3x.png
│ │ ├── reveal-accent-top.png
│ │ ├── reveal-accent-top.svg
│ │ ├── reveal-accent-top@2x.png
│ │ ├── reveal-accent-top@3x.png
│ │ ├── reveal-bottom.png
│ │ ├── reveal-bottom.svg
│ │ ├── reveal-bottom@2x.png
│ │ ├── reveal-bottom@3x.png
│ │ ├── reveal-center.png
│ │ ├── reveal-center.svg
│ │ ├── reveal-center@2x.png
│ │ ├── reveal-center@3x.png
│ │ ├── reveal-top.png
│ │ ├── reveal-top.svg
│ │ ├── reveal-top@2x.png
│ │ ├── reveal-top@3x.png
│ │ ├── right-BL.png
│ │ ├── right-BL.svg
│ │ ├── right-BL@2x.png
│ │ ├── right-BL@3x.png
│ │ ├── right-BR.png
│ │ ├── right-BR.svg
│ │ ├── right-BR@2x.png
│ │ ├── right-BR@3x.png
│ │ ├── right-TL.png
│ │ ├── right-TL.svg
│ │ ├── right-TL@2x.png
│ │ ├── right-TL@3x.png
│ │ ├── right-TR.png
│ │ ├── right-TR.svg
│ │ ├── right-TR@2x.png
│ │ ├── right-TR@3x.png
│ │ ├── right-center.png
│ │ ├── right-center.svg
│ │ ├── right-center@2x.png
│ │ └── right-center@3x.png
│ ├── katex.css
│ ├── learnMore
│ │ ├── starburst-red.svg
│ │ └── starburst.svg
│ └── logo
│ │ ├── 16.png
│ │ ├── 16.svg
│ │ ├── 16@2x.png
│ │ ├── 16@3x.png
│ │ ├── 24.png
│ │ ├── 24.svg
│ │ ├── 24@2x.png
│ │ ├── 24@3x.png
│ │ ├── 32.png
│ │ ├── 32.svg
│ │ ├── 32@2x.png
│ │ └── 32@3x.png
├── babel.config.cjs
├── package.json
├── src
│ ├── @types
│ │ └── markdown-it-texmath
│ │ │ └── index.d.ts
│ ├── components
│ │ ├── Button.stories.tsx
│ │ ├── Button.tsx
│ │ ├── Card.stories.tsx
│ │ ├── Card.tsx
│ │ ├── ContinueWithUser.stories.tsx
│ │ ├── ContinueWithUser.tsx
│ │ ├── DebugGrid.stories.tsx
│ │ ├── DebugGrid.tsx
│ │ ├── FadeView.stories.tsx
│ │ ├── FadeView.tsx
│ │ ├── Hoverable.tsx
│ │ ├── Icon.stories.tsx
│ │ ├── Icon.tsx
│ │ ├── Icon.web.tsx
│ │ ├── IconShared.ts
│ │ ├── Link.tsx
│ │ ├── Logo.stories.tsx
│ │ ├── Logo.tsx
│ │ ├── Logo.web.tsx
│ │ ├── LogoShared.ts
│ │ ├── Menu.stories.tsx
│ │ ├── Menu.tsx
│ │ ├── PromptFieldRenderer.tsx
│ │ ├── PromptFieldRenderer
│ │ │ ├── clozeHighlightPlugin.tsx
│ │ │ ├── markdown.ts
│ │ │ ├── markdownLatexSupport.tsx
│ │ │ └── markdownLatexSupport.web.tsx
│ │ ├── ReviewArea.stories.tsx
│ │ ├── ReviewArea.tsx
│ │ ├── ReviewButtonBar.tsx
│ │ ├── ReviewStarburst.stories.tsx
│ │ ├── ReviewStarburst.tsx
│ │ ├── SawtoothPattern.tsx
│ │ ├── Spacer.tsx
│ │ ├── Starburst.stories.tsx
│ │ ├── Starburst.tsx
│ │ ├── StarburstLegend.tsx
│ │ ├── TextInput.stories.tsx
│ │ ├── TextInput.tsx
│ │ ├── __fixtures__
│ │ │ ├── colorPaletteArgType.ts
│ │ │ └── generateReviewItem.ts
│ │ └── hooks
│ │ │ ├── useKey.ts
│ │ │ ├── useLayout.ts
│ │ │ ├── usePrevious.ts
│ │ │ ├── useTransitioningValue.stories.tsx
│ │ │ ├── useTransitioningValue.ts
│ │ │ └── useWeakRef.ts
│ ├── index.ts
│ ├── reviewAreaItem.ts
│ ├── styles
│ │ ├── colors.stories.tsx
│ │ ├── colors.ts
│ │ ├── index.ts
│ │ ├── layout.ts
│ │ ├── type.stories.tsx
│ │ └── type.ts
│ └── util
│ │ ├── Size.ts
│ │ ├── clamp.ts
│ │ ├── generateIntervalSequence.ts
│ │ ├── lerp.ts
│ │ └── unreachableCaseError.ts
└── tsconfig.json
└── web-component
├── .firebaserc
├── .gitignore
├── LICENSE
├── Readme.md
├── babel.config.cjs
├── firebase.json
├── jest.config.cjs
├── package.json
├── scripts
├── bundleDev.ts
├── bundleProd.ts
├── bundleShared.ts
└── tsconfig.json
├── src
├── OrbitPromptElement.ts
├── OrbitReviewAreaElement.ts
├── extractItems.test.ts
├── extractItems.ts
├── index.ts
└── metadataMonitor.ts
├── test
├── index.html
└── orbit-web-component.js
└── tsconfig.json
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.lockb binary diff=lockb
2 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | patreon: quantumcountry
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | 🛑
11 |
12 | Please read the "Contributing" section of the project README before continuing. We don't have the capacity to engage with feature requests without preliminary conversation unless you're already a well-known contributor.
13 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/something-else.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Something else
3 | about: Something else on your mind?
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | 🛑
11 |
12 | Please read the "Contributing" section of the project README before continuing. We don't currently have the capacity to engage with most new issues from new collaborators.
13 |
14 | If you'd like to discuss something about Orbit, you can try [emailing Andy](mailto:andy@andymatuschak.org).
15 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /workspace.xml
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/dictionaries/andym.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/jsLibraryMappings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/jsLinters/eslint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/markdown.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/prettier.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.node-version:
--------------------------------------------------------------------------------
1 | 20
2 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "jest.pathToJest": "bun run test"
3 | }
4 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "type": "npm",
6 | "script": "build",
7 | "problemMatcher": [
8 | "$tsc"
9 | ],
10 | "group": {
11 | "kind": "build",
12 | "isDefault": true
13 | },
14 | "label": "npm: build",
15 | "detail": "tsc -b packages/tsconfig.base.json"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2020 Andy Matuschak.
2 |
3 | All sources in this repository, except those in the subtrees packages/app and packages/backend, and all compiled distribution binaries, are licensed under Apache 2.0 (see LICENSE.Apache-2.0 for text).
4 |
5 | Sources in packages/app and packages/backend are licensed under AGPL 3.0+ or BUSL 1.1 (your choice; see LICENSE.AGPL-3.0-or-later and LICENSE.BUSL1.1 for respective texts).
6 |
7 | See discussion in Readme.md for more background.
8 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | Orbit
2 | Copyright 2020 Andy Matuschak
3 |
--------------------------------------------------------------------------------
/bun.lockb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/bun.lockb
--------------------------------------------------------------------------------
/design/reveal answer - scale.origami:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/reveal answer - scale.origami
--------------------------------------------------------------------------------
/design/reveal answer and advance question - fade.origami:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/reveal answer and advance question - fade.origami
--------------------------------------------------------------------------------
/design/starburst-icon-iOS_1024x1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-iOS_1024x1024.png
--------------------------------------------------------------------------------
/design/starburst-icon-iOS_20x20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-iOS_20x20.png
--------------------------------------------------------------------------------
/design/starburst-icon-iOS_20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-iOS_20x20@2x.png
--------------------------------------------------------------------------------
/design/starburst-icon-iOS_20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-iOS_20x20@3x.png
--------------------------------------------------------------------------------
/design/starburst-icon-iOS_29x29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-iOS_29x29.png
--------------------------------------------------------------------------------
/design/starburst-icon-iOS_29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-iOS_29x29@2x.png
--------------------------------------------------------------------------------
/design/starburst-icon-iOS_29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-iOS_29x29@3x.png
--------------------------------------------------------------------------------
/design/starburst-icon-iOS_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-iOS_40x40.png
--------------------------------------------------------------------------------
/design/starburst-icon-iOS_40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-iOS_40x40@2x.png
--------------------------------------------------------------------------------
/design/starburst-icon-iOS_40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-iOS_40x40@3x.png
--------------------------------------------------------------------------------
/design/starburst-icon-iOS_60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-iOS_60x60@2x.png
--------------------------------------------------------------------------------
/design/starburst-icon-iOS_60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-iOS_60x60@3x.png
--------------------------------------------------------------------------------
/design/starburst-icon-iOS_76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-iOS_76x76.png
--------------------------------------------------------------------------------
/design/starburst-icon-iOS_76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-iOS_76x76@2x.png
--------------------------------------------------------------------------------
/design/starburst-icon-iOS_83-5x83-5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-iOS_83-5x83-5@2x.png
--------------------------------------------------------------------------------
/design/starburst-icon-macOS_1024x1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-macOS_1024x1024.png
--------------------------------------------------------------------------------
/design/starburst-icon-macOS_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-macOS_128x128.png
--------------------------------------------------------------------------------
/design/starburst-icon-macOS_128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-macOS_128x128@2x.png
--------------------------------------------------------------------------------
/design/starburst-icon-macOS_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-macOS_16x16.png
--------------------------------------------------------------------------------
/design/starburst-icon-macOS_16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-macOS_16x16@2x.png
--------------------------------------------------------------------------------
/design/starburst-icon-macOS_256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-macOS_256x256.png
--------------------------------------------------------------------------------
/design/starburst-icon-macOS_256x256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-macOS_256x256@2x.png
--------------------------------------------------------------------------------
/design/starburst-icon-macOS_32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-macOS_32x32.png
--------------------------------------------------------------------------------
/design/starburst-icon-macOS_32x32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-macOS_32x32@2x.png
--------------------------------------------------------------------------------
/design/starburst-icon-macOS_512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-macOS_512x512.png
--------------------------------------------------------------------------------
/design/starburst-icon-macOS_512x512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon-macOS_512x512@2x.png
--------------------------------------------------------------------------------
/design/starburst-icon.fig:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/design/starburst-icon.fig
--------------------------------------------------------------------------------
/design/starburst-icon.md:
--------------------------------------------------------------------------------
1 | The "canonical" starburst used as the app icon is currently taken from the Starburst Sandbox in the UI Storybook. Probably we'll want to tune it by hand at some point, but this'll do for now. The settings:
2 |
3 | * Line count: 18
4 | * Random seed: seed111111111111111111111111
5 | * Line min: 0.25
6 | * Liune max: 0.95
7 | * Size: 120
8 | * Use composition: yes
9 | * Color palette index: 0
10 | * All colors: black
11 | * Extra rotation degrees: 10
12 | * Scale: 1.0
13 | * Translate X/Y: 0
14 | * Thickness: 4
15 |
16 | Then I copy/paste the SVG into Figma, matte it onto "brand red" (#ED3749), and export.
17 |
--------------------------------------------------------------------------------
/packages/.eslintignore:
--------------------------------------------------------------------------------
1 | web-component/build/**/*
2 | web-component/test/**/*
3 | web-component/orbit-web-component-prod.js*
4 | app/index.js
5 | app/expoPlugin/**/*
6 | app/.expo/**/*
7 | app/web-build/**/*
8 | */dist/**/*
9 |
--------------------------------------------------------------------------------
/packages/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | trailingComma: "all",
3 | };
4 |
--------------------------------------------------------------------------------
/packages/anki-import/Readme.md:
--------------------------------------------------------------------------------
1 | # @withorbit/anki-import
2 |
3 | This module implements a non-production-ready import process for Anki `.apkg` files into Orbit. It's implemented as a library; see `cli/importAnkiCollection.ts` for an example usage. A production client of this library should inform the user of potential lossiness during the transformation (and should probably be integrated into `app`).
4 |
5 | ```
6 | Copyright 2020 Andy Matuschak
7 | SPDX-License-Identifier: Apache-2.0
8 | ```
9 |
10 |
--------------------------------------------------------------------------------
/packages/anki-import/babel.config.cjs:
--------------------------------------------------------------------------------
1 | // babel.config.js
2 | module.exports = {
3 | presets: [
4 | [
5 | "@babel/preset-env",
6 | {
7 | targets: {
8 | node: "current",
9 | },
10 | },
11 | ],
12 | "@babel/preset-typescript",
13 | ],
14 | };
15 |
--------------------------------------------------------------------------------
/packages/anki-import/jest.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleNameMapper: {
3 | "^(\\.{1,2}/.*)\\.js$": "$1",
4 | },
5 | testEnvironment: "node",
6 | testMatch: ["**/?(*.)+(spec|test).ts?(x)"],
7 | testPathIgnorePatterns: ["dist", "node_modules"],
8 | transformIgnorePatterns: [],
9 | };
10 |
--------------------------------------------------------------------------------
/packages/anki-import/src/__fixtures__/testCollection.colpkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/anki-import/src/__fixtures__/testCollection.colpkg
--------------------------------------------------------------------------------
/packages/anki-import/src/__fixtures__/withTestAnkiCollection.ts:
--------------------------------------------------------------------------------
1 | import path from "path";
2 | import {
3 | AnkiCollectionDBHandle,
4 | MediaManifest,
5 | readAnkiCollectionPackage,
6 | } from "../ankiPkg/index.js";
7 |
8 | export default function withTestAnkiCollection(
9 | continuation: (
10 | handle: AnkiCollectionDBHandle,
11 | mediaManifest: MediaManifest | null,
12 | attachmentIDsToExtractedPaths: { [key: string]: string },
13 | ) => Promise,
14 | ): Promise {
15 | return readAnkiCollectionPackage(
16 | path.resolve(__dirname, "./testCollection.colpkg"),
17 | continuation,
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/packages/anki-import/src/ankiPkg/ankiAttachmentReference.ts:
--------------------------------------------------------------------------------
1 | export type AnkiAttachmentReference = {
2 | type: "sound" | "image";
3 | name: string;
4 | };
5 |
--------------------------------------------------------------------------------
/packages/anki-import/src/ankiPkg/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./ankiCollection.js";
2 | export * from "./ankiDBTypes.js";
3 | export { default as splitAnkiDBNoteFields } from "./splitAnkiDBNoteFields.js";
4 |
--------------------------------------------------------------------------------
/packages/anki-import/src/ankiPkg/splitAnkiDBNoteFields.test.ts:
--------------------------------------------------------------------------------
1 | import splitAnkiDBNoteFields from "./splitAnkiDBNoteFields.js";
2 |
3 | test("parse Anki DB field with two entries", () => {
4 | // String literal here copied from my database, includes the 0x1f character code.
5 | expect(splitAnkiDBNoteFields("1 lb in kg0.45 kg")).toMatchObject([
6 | "1 lb in kg",
7 | "0.45 kg",
8 | ]);
9 | });
10 |
11 | test("parse Anki DB field with one entry", () => {
12 | expect(splitAnkiDBNoteFields("test")).toMatchObject(["test"]);
13 | });
14 |
--------------------------------------------------------------------------------
/packages/anki-import/src/ankiPkg/splitAnkiDBNoteFields.ts:
--------------------------------------------------------------------------------
1 | // Extracts field contents from an Anki collection DB Note.flds column entry
2 | export default function splitAnkiDBNoteFields(
3 | ankiDBNoteFields: string,
4 | ): string[] {
5 | return ankiDBNoteFields.split(String.fromCharCode(31));
6 | }
7 |
--------------------------------------------------------------------------------
/packages/anki-import/src/convertAnkiID.ts:
--------------------------------------------------------------------------------
1 | import {
2 | encodeUUIDBytesToWebSafeBase64ID,
3 | EntityID,
4 | EventID,
5 | } from "@withorbit/core";
6 | import { parse as uuidParse, v5 as uuidV5 } from "uuid";
7 |
8 | let _orbitAnkiImportNamespaceUUID: ArrayLike | null = null;
9 |
10 | // Generate a consistent Orbit ID (a v5 instead of v4 UUID) from an Anki ID.
11 | export function convertAnkiID(
12 | input: string,
13 | ): ID {
14 | if (!_orbitAnkiImportNamespaceUUID) {
15 | _orbitAnkiImportNamespaceUUID = uuidParse(
16 | "a430c93f-60dc-4799-b2a6-df402ff941a5",
17 | );
18 | }
19 |
20 | const bytes = new Uint8Array(16);
21 | uuidV5(input, _orbitAnkiImportNamespaceUUID, bytes);
22 | return encodeUUIDBytesToWebSafeBase64ID(bytes);
23 | }
24 |
--------------------------------------------------------------------------------
/packages/anki-import/src/index.ts:
--------------------------------------------------------------------------------
1 | export { createImportPlan } from "./importPlan.js";
2 | export { readAnkiCollectionPackage } from "./ankiPkg/ankiCollection.js";
3 |
--------------------------------------------------------------------------------
/packages/anki-import/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "rootDir": "./src",
6 | "types": ["node", "jest", "mdast"]
7 | },
8 | "include": ["./src/**/*.ts"],
9 | "references": [
10 | {
11 | "path": "../core"
12 | },
13 | {
14 | "path": "../sample-data"
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/packages/api-client/Readme.md:
--------------------------------------------------------------------------------
1 | # @withorbit/api-client
2 |
3 | A simple preliminary implementation of an API client for Orbit. See `@withorbit/api` for the main interface definition, which this library wraps.
4 |
5 | ```
6 | Copyright 2020 Andy Matuschak
7 | SPDX-License-Identifier: Apache-2.0
8 | ```
9 |
--------------------------------------------------------------------------------
/packages/api-client/babel.config.cjs:
--------------------------------------------------------------------------------
1 | // babel.config.js
2 | module.exports = {
3 | presets: [
4 | [
5 | "@babel/preset-env",
6 | {
7 | targets: {
8 | node: "current",
9 | },
10 | },
11 | ],
12 | "@babel/preset-typescript",
13 | ],
14 | };
15 |
--------------------------------------------------------------------------------
/packages/api-client/jest.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleNameMapper: {
3 | "^(\\.{1,2}/.*)\\.js$": "$1",
4 | },
5 | testEnvironment: "node",
6 | testMatch: ["**/?(*.)+(spec|test).ts?(x)"],
7 | testPathIgnorePatterns: ["dist", "node_modules"],
8 | transformIgnorePatterns: [],
9 | };
10 |
--------------------------------------------------------------------------------
/packages/api-client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@withorbit/api-client",
3 | "version": "0.0.1",
4 | "license": "Apache-2.0",
5 | "private": true,
6 | "type": "module",
7 | "main": "./dist/index.js",
8 | "types": "./dist/index.d.ts",
9 | "sideEffects": false,
10 | "devDependencies": {
11 | "@babel/core": "^7.14.6",
12 | "@babel/preset-env": "^7.14.7",
13 | "@babel/preset-typescript": "^7.14.5",
14 | "@types/jest": "^29.5.5",
15 | "@types/node": "^20.10.4",
16 | "@withorbit/sample-data": "0.0.1",
17 | "babel-jest": "^29.7.0",
18 | "jest": "^29.7.0",
19 | "typescript": "^5.3.3"
20 | },
21 | "dependencies": {
22 | "@withorbit/api": "0.0.1",
23 | "@withorbit/core": "0.0.1",
24 | "react-native-blob-jsi-helper": "^0.3.1"
25 | },
26 | "scripts": {
27 | "build": "tsc -b",
28 | "watch": "tsc -w",
29 | "test": "jest --runInBand"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/packages/api-client/src/apiConfig.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export interface APIConfig {
4 | baseURL: string; // no trailing slash
5 |
6 | fetch?: typeof fetch;
7 | }
8 |
9 | export const defaultAPIConfig: APIConfig = {
10 | baseURL: "https://withorbit.com/api",
11 | };
12 |
13 | export const emulatorAPIConfig: APIConfig = {
14 | ...defaultAPIConfig,
15 | baseURL: "http://127.0.0.1:5001/metabook-system/us-central1/api",
16 | };
17 |
--------------------------------------------------------------------------------
/packages/api-client/src/index.ts:
--------------------------------------------------------------------------------
1 | export type { APIConfig } from "./apiConfig.js";
2 | export { defaultAPIConfig, emulatorAPIConfig } from "./apiConfig.js";
3 |
4 | export { OrbitAPIClient as default } from "./orbitAPIClient.js";
5 |
--------------------------------------------------------------------------------
/packages/api-client/src/util/fetch.native.ts:
--------------------------------------------------------------------------------
1 | import { API } from "@withorbit/api";
2 | import { getArrayBufferForBlob } from "react-native-blob-jsi-helper";
3 |
4 | export async function getBytesFromBlobLike(
5 | blobLike: API.BlobLike,
6 | ): Promise {
7 | return getArrayBufferForBlob(blobLike as Blob);
8 | }
9 |
10 | export function createBlobFromBuffer(
11 | buffer: Uint8Array,
12 | mimeType: T,
13 | ): API.BlobLike {
14 | return {
15 | type: mimeType,
16 | size: buffer.length,
17 | name: "unknown.txt",
18 | base64: btoa(String.fromCharCode.apply(null, Array.from(buffer))),
19 | } as API.BlobLike;
20 | }
21 |
--------------------------------------------------------------------------------
/packages/api-client/src/util/fetch.ts:
--------------------------------------------------------------------------------
1 | import { API } from "@withorbit/api";
2 |
3 | export async function getBytesFromBlobLike(
4 | blobLike: API.BlobLike,
5 | ): Promise {
6 | if (!blobLike.arrayBuffer) {
7 | throw new Error("Unexpectedly missing implementation of Blob.arrayBuffer");
8 | }
9 | return new Uint8Array(await blobLike.arrayBuffer());
10 | }
11 |
12 | export function createBlobFromBuffer(
13 | buffer: Uint8Array,
14 | mimeType: string,
15 | ): Blob {
16 | return new Blob([buffer], { type: mimeType });
17 | }
18 |
--------------------------------------------------------------------------------
/packages/api-client/src/util/mockAPIValiation.ts:
--------------------------------------------------------------------------------
1 | import { APIValidator } from "@withorbit/api";
2 |
3 | export class MockOrbitAPIValidation implements APIValidator {
4 | validateRequest(): true {
5 | return true;
6 | }
7 |
8 | validateResponse(): true {
9 | return true;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/api-client/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "rootDir": "./src",
6 | "lib": ["es2022", "dom", "dom.iterable"],
7 | "types": ["jest", "node"]
8 | },
9 | "include": ["./src/**/*.ts"],
10 | "references": [
11 | {
12 | "path": "../core"
13 | },
14 | {
15 | "path": "../sample-data"
16 | },
17 | {
18 | "path": "../api"
19 | }
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/packages/api/Readme.md:
--------------------------------------------------------------------------------
1 | # @withorbit/api
2 |
3 | Type-only package specifying Orbit's API surface, used by `api-client` (client-side) and `backend` (to route requests on the server).
4 |
5 | ```
6 | Copyright 2020 Andy Matuschak
7 | SPDX-License-Identifier: Apache-2.0
8 | ```
9 |
--------------------------------------------------------------------------------
/packages/api/babel.config.cjs:
--------------------------------------------------------------------------------
1 | // babel.config.js
2 | module.exports = {
3 | presets: [
4 | [
5 | "@babel/preset-env",
6 | {
7 | targets: {
8 | node: "current",
9 | },
10 | },
11 | ],
12 | "@babel/preset-typescript",
13 | ],
14 | };
15 |
--------------------------------------------------------------------------------
/packages/api/jest.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleNameMapper: {
3 | "^(\\.{1,2}/.*)\\.js$": "$1",
4 | },
5 | testEnvironment: "node",
6 | testMatch: ["**/?(*.)+(spec|test).ts?(x)"],
7 | testPathIgnorePatterns: ["dist", "node_modules"],
8 | transformIgnorePatterns: [],
9 | };
10 |
--------------------------------------------------------------------------------
/packages/api/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@withorbit/api",
3 | "version": "0.0.1",
4 | "type": "module",
5 | "main": "./dist/index.js",
6 | "types": "./dist/index.d.ts",
7 | "files": [
8 | "dist"
9 | ],
10 | "private": true,
11 | "sideEffects": false,
12 | "scripts": {
13 | "build": "tsc -b",
14 | "test": "jest --runInBand",
15 | "generateSchema": "typescript-json-schema src/orbitAPI.ts ValidatableSpec -o src/orbitAPISchema.json --noExtraProps --required --ignoreErrors --strictNullChecks"
16 | },
17 | "dependencies": {
18 | "@withorbit/core": "0.0.1",
19 | "ajv": "^8.6.2"
20 | },
21 | "devDependencies": {
22 | "@types/jest": "^29.5.5",
23 | "@types/node": "^20.10.4",
24 | "babel-jest": "^29.7.0",
25 | "jest": "^29.7.0",
26 | "typescript": "^5.3.3",
27 | "typescript-json-schema": "^0.50.0"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/packages/api/src/index.ts:
--------------------------------------------------------------------------------
1 | export * as OrbitAPI from "./orbitAPI.js";
2 | export * as API from "./genericHTTPAPI.js";
3 | export { OrbitAPIValidator } from "./validation/orbitAPIValidator.js";
4 | export type {
5 | APIValidator,
6 | APIValidatorError,
7 | } from "./validation/apiValidator.js";
8 |
--------------------------------------------------------------------------------
/packages/api/src/util/requiredSpec.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Converts a nested Spec object with optional HTTP methods and routes to be required. For example:
3 | * ```
4 | * type Spec = RequiredSpec<{
5 | * "/hello"?: {
6 | * GET?: {
7 | * query: { name: string };
8 | * response?: string;
9 | * }
10 | * }
11 | * }>
12 | * // is equivalent too
13 | * type Spec = RequiredSpec<{
14 | * "/hello": {
15 | * GET: {
16 | * query: { name: string };
17 | * response: string;
18 | * }
19 | * }
20 | * }>
21 | * ```
22 | */
23 | export type RequiredSpec = Required>;
24 |
25 | type NestedRequired = {
26 | [P in keyof T]: Required>;
27 | };
28 |
29 | type NestedRequiredWithoutRecursion = {
30 | [P in keyof T]: Required;
31 | };
32 |
--------------------------------------------------------------------------------
/packages/api/src/validation/apiValidator.ts:
--------------------------------------------------------------------------------
1 | export type APIValidatorRequest = {
2 | method: string;
3 | path: string;
4 | contentType?: string;
5 | params?: { [key: string]: unknown };
6 | query?: { [key: string]: unknown };
7 | body?: unknown;
8 | };
9 |
10 | export type APIValidatorError = {
11 | errors: { message: string }[];
12 | };
13 |
14 | export interface APIValidator {
15 | validateRequest(request: APIValidatorRequest): APIValidatorError | true;
16 | validateResponse(
17 | request: APIValidatorRequest,
18 | response: unknown,
19 | ): APIValidatorError | true;
20 | }
21 |
--------------------------------------------------------------------------------
/packages/api/src/validation/orbitAPIValidator.ts:
--------------------------------------------------------------------------------
1 | import { ValidatableSpec } from "../orbitAPI.js";
2 | import OrbitAPISchema from "../orbitAPISchema.json" assert { type: "json" };
3 | import { AjvAPIValidator, AjvAPIValidatorConfig } from "./ajvAPIValidator.js";
4 |
5 | export class OrbitAPIValidator extends AjvAPIValidator {
6 | constructor(config: AjvAPIValidatorConfig) {
7 | super(config, OrbitAPISchema);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/packages/api/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "rootDir": "./src",
6 | "types": ["jest", "node"]
7 | },
8 | "include": ["./src/**/*.ts", "./src/**/*.json"],
9 | "references": [
10 | {
11 | "path": "../core"
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/packages/app/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "metabook-system"
4 | },
5 | "targets": {
6 | "metabook-system": {
7 | "hosting": {
8 | "orbit-app": ["orbit-app"],
9 | "orbit-docs": [
10 | "orbit-docs"
11 | ],
12 | "orbit-cdn": ["orbit-cdn"]
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app/.gitignore:
--------------------------------------------------------------------------------
1 | /.expo
2 | /web-build
3 | /public/fonts
4 | /.firebase
5 |
6 | # These native directories should be generated on-demand using expo's Continuous Native Generation feature.
7 | /ios
8 | /android
9 |
10 | # @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb
11 | # The following patterns were generated by expo-cli
12 |
13 | expo-env.d.ts
14 | # @end expo-cli
--------------------------------------------------------------------------------
/packages/app/LICENSE:
--------------------------------------------------------------------------------
1 | AGPL-3.0-or-later OR BUSL-1.1
2 |
--------------------------------------------------------------------------------
/packages/app/app-assets/starburst-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/app/app-assets/starburst-icon.png
--------------------------------------------------------------------------------
/packages/app/assets:
--------------------------------------------------------------------------------
1 | ../ui/assets
--------------------------------------------------------------------------------
/packages/app/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function (api) {
2 | api.cache(true);
3 | return {
4 | presets: ["babel-preset-expo"],
5 | plugins: [
6 | [
7 | "@babel/plugin-syntax-import-attributes",
8 | // TODO remove when we move to Node 22 and update import assert to import with
9 | { deprecatedAssertSyntax: true },
10 | ],
11 | ],
12 | };
13 | };
14 |
--------------------------------------------------------------------------------
/packages/app/expoPlugin/expoPlugin.js:
--------------------------------------------------------------------------------
1 | const { withPlugins } = require("expo/config-plugins");
2 | const serviceConfig = require("../serviceConfig");
3 | const withCatalystSupport = require("./withCatalystSupport");
4 | const withIngestIntent = require("./withIngestIntent");
5 | const withReactNativeKeyEventSupport = require("./withReactNativeKeyEventSupport");
6 | const withSQLImageURLLoader = require("./withSQLImageURLLoader");
7 | const withWidgetPluginFixes = require("./withWidgetPluginFixes");
8 |
9 | module.exports = function withOrbitExpoConfigPlugin(config) {
10 | return withPlugins(config, [
11 | [
12 | withCatalystSupport,
13 | { developmentTeamID: serviceConfig.appleDevelopmentTeamID },
14 | ],
15 | withIngestIntent,
16 | withSQLImageURLLoader,
17 | withReactNativeKeyEventSupport,
18 | withWidgetPluginFixes,
19 | ]);
20 | };
21 |
--------------------------------------------------------------------------------
/packages/app/expoPlugin/ios/AppDelegate+Intents.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate+KeyHandling.m
3 | // Orbit
4 | //
5 | // Created by Andy Matuschak on 2023-12-21.
6 | //
7 |
8 | #import
9 | #import "IngestEventHandler.h"
10 | #import "AppDelegate.h"
11 |
12 | @implementation AppDelegate (Intents)
13 |
14 | - (id)application:(UIApplication *)application handlerForIntent:(INIntent *)intent {
15 | if ([intent isKindOfClass:[ShortcutIngestIntent class]]) {
16 | return [[IngestEventHandler alloc] init];
17 | }
18 | return nil;
19 | }
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/packages/app/expoPlugin/ios/IngestEventEmitter.h:
--------------------------------------------------------------------------------
1 | //
2 | // EventEmitter.h
3 | // Orbit
4 | //
5 | // Created by Ozzie Kirkby on 2022-05-07.
6 | //
7 |
8 | #ifndef EventEmitter_h
9 | #define EventEmitter_h
10 |
11 | #import
12 | #import
13 |
14 | @interface IngestEventEmitter : RCTEventEmitter
15 |
16 | @property(atomic,assign) bool hasListeners;
17 | @property(atomic,copy) void (^completionHandler)(BOOL *result);
18 |
19 | - (void)emitIngestEvent:(NSString *)fileJSON completion:(void (^)(BOOL *result))block;
20 |
21 | @end
22 |
23 | #endif /* EventEmitter_h */
24 |
--------------------------------------------------------------------------------
/packages/app/expoPlugin/ios/IngestEventHandler.h:
--------------------------------------------------------------------------------
1 | //
2 | // IngestEventHandler.h
3 | // Orbit
4 | //
5 | // Created by Ozzie Kirkby on 2022-05-08.
6 | //
7 |
8 | #ifndef IngestEventHandler_h
9 | #define IngestEventHandler_h
10 | // Automatically generated file by SiriKit which codify's
11 | // the intent definitions.
12 | #import "ShortcutIngestIntent.h"
13 |
14 | @interface IngestEventHandler : NSObject
15 |
16 | @end
17 |
18 | #endif /* IngestEventHandler_h */
19 |
--------------------------------------------------------------------------------
/packages/app/expoPlugin/ios/ORSQLImageURLLoader.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORSQLImageURLLoader.h
3 | // Orbit
4 | //
5 | // Created by Andy Matuschak on 10/19/21.
6 | //
7 |
8 | #import
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface ORSQLImageURLLoader : NSObject
14 |
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/packages/app/expoPlugin/ios/ORWidgetReloadBridge.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORWidgetReloadBridge.m
3 | // Orbit
4 | //
5 | // Created by Andy Matuschak on 2024-07-12.
6 | //
7 |
8 | #import
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface RCT_EXTERN_MODULE(WidgetReloadBridge, NSObject)
14 | RCT_EXTERN_METHOD(reloadTimelines)
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/packages/app/expoPlugin/ios/ORWidgetReloadBridge.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ORWidgetReloadBridge.swift
3 | // Orbit
4 | //
5 | // Created by Andy Matuschak on 2024-07-12.
6 | //
7 |
8 | import Foundation
9 | import WidgetKit
10 |
11 | @objc(WidgetReloadBridge) class WidgetReloadBridge: NSObject {
12 | @objc public func reloadTimelines() {
13 | WidgetCenter.shared.reloadAllTimelines()
14 | print("Reloading timelines")
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app/expoPlugin/withReactNativeKeyEventSupport.js:
--------------------------------------------------------------------------------
1 | const { withXcodeProject } = require("expo/config-plugins");
2 | const { addSourceFile, addResourceFile } = require("./util");
3 |
4 | module.exports = function withReactNativeKeyEventSupport(config) {
5 | return withXcodeProject(config, async (config) => {
6 | addSourceFile(config, "AppDelegate+KeyHandling.m");
7 | return config;
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/packages/app/expoPlugin/withSQLImageURLLoader.js:
--------------------------------------------------------------------------------
1 | const { withXcodeProject, IOSConfig } = require("expo/config-plugins");
2 | const { addSourceFile } = require("./util");
3 |
4 | // Attachments are stored as blobs in the Orbit SQLite database. We use a custom URL to specify images to the React Native tag; this resolver provides the data on demand.
5 | module.exports = function withSQLImageURLLoader(config) {
6 | return withXcodeProject(config, async (config) => {
7 | addSourceFile(config, "ORSQLImageURLLoader.h");
8 | addSourceFile(config, "ORSQLImageURLLoader.m");
9 | return config;
10 | });
11 | };
12 |
--------------------------------------------------------------------------------
/packages/app/scripts/deploy_web.sh:
--------------------------------------------------------------------------------
1 | export SENTRY_AUTH_TOKEN=$(firebase functions:config:get sentry.auth_token | sed -e "s/\"//g")
2 | export SENTRY_ORG=$(bun -e "import serviceConfig from './serviceConfig.js'; console.log(serviceConfig.sentryOrg)")
3 | export SENTRY_PROJECT=$(bun -e "import serviceConfig from './serviceConfig.js'; console.log(serviceConfig.sentryProject)")
4 | VERSION=$(sentry-cli releases propose-version)
5 |
6 | sentry-cli releases -o "$SENTRY_ORG" new -p "$SENTRY_PROJECT" "$VERSION"
7 | sentry-cli releases -o "$SENTRY_ORG" set-commits --auto "$VERSION"
8 |
9 | bun run build:web
10 | bunx firebase deploy --only hosting
11 |
12 | sentry-cli releases -o "$SENTRY_ORG" files "$VERSION" upload-sourcemaps --no-rewrite ./web-build/static/js
13 | sentry-cli releases -o "$SENTRY_ORG" finalize "$VERSION"
14 | sentry-cli releases -o "$SENTRY_ORG" deploys "$VERSION" new -e production
15 |
--------------------------------------------------------------------------------
/packages/app/scripts/generate_browser_compatibility_regex.sh:
--------------------------------------------------------------------------------
1 | SUPPORTED_BROWSER_REGEX="$(npx browserslist-useragent-regexp --allowHigherVersions)"
2 | GENERATED_STR=""
3 | GENERATED_STR+="// DO NOT MODIFY THIS CODE MANUALLY\n"
4 | GENERATED_STR+="// eslint-disable-next-line @typescript-eslint/no-unused-vars\n"
5 | GENERATED_STR+="const supportedBrowserRegex = $SUPPORTED_BROWSER_REGEX;"
6 |
7 | echo $GENERATED_STR > web/browserCompatibility.js
--------------------------------------------------------------------------------
/packages/app/serviceConfig.js:
--------------------------------------------------------------------------------
1 | const shouldUseLocalBackend = typeof __DEV__ === "undefined" ? false : __DEV__;
2 | // Uncomment this line (and comment the above) to use the production backend in dev.
3 | // const shouldUseLocalBackend = false;
4 |
5 | module.exports = {
6 | sentryDSN:
7 | "https://7a9cba7e96b54da4bae2c6eb9b8d7b18@o240663.ingest.sentry.io/5306223",
8 | sentryOrg: "andy-matuschak",
9 | sentryProject: "orbit-app",
10 | // Store your auth token securely: firebase functions:config:set sentry.auth_token=SENTRY_AUTH_TOKEN
11 |
12 | httpsAPIBaseURLString: shouldUseLocalBackend
13 | ? "http://127.0.0.1:5001/metabook-system/us-central1/api"
14 | : "https://withorbit.com/api",
15 | shouldUseLocalBackend,
16 |
17 | appleDevelopmentTeamID: "MQ22N839N8",
18 | };
19 |
--------------------------------------------------------------------------------
/packages/app/src/app/(auth)/_layout.tsx:
--------------------------------------------------------------------------------
1 | import { Slot } from "expo-router";
2 | import React, { useState } from "react";
3 | import { AuthenticationClientContext } from "../../authentication/authContext.js";
4 | import * as Authentication from "../../authentication/index.js";
5 | import { getFirebaseAuth } from "../../util/firebaseAuth.js";
6 |
7 | export default function RootLayout() {
8 | const [authenticationClient] = useState(
9 | () => new Authentication.FirebaseAuthenticationClient(getFirebaseAuth()),
10 | );
11 | return (
12 |
13 |
14 |
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app/src/app/(index)/_layout.tsx:
--------------------------------------------------------------------------------
1 | export { default } from "../(auth)/_layout.js";
2 |
--------------------------------------------------------------------------------
/packages/app/src/app/(index)/_layout.web.tsx:
--------------------------------------------------------------------------------
1 | import { Slot } from "expo-router";
2 | import React from "react";
3 |
4 | export default function IndexLayout() {
5 | return ;
6 | }
7 |
--------------------------------------------------------------------------------
/packages/app/src/app/(index)/index.tsx:
--------------------------------------------------------------------------------
1 | export { default } from "../(auth)/review.js";
2 |
--------------------------------------------------------------------------------
/packages/app/src/app/(index)/index.web.tsx:
--------------------------------------------------------------------------------
1 | export { default } from "../learnMore.js";
2 |
--------------------------------------------------------------------------------
/packages/app/src/app/_layout.tsx:
--------------------------------------------------------------------------------
1 | import { Slot } from "expo-router";
2 | import React from "react";
3 | import { initializeReporter } from "../errorReporting";
4 | import { initIntentHandlers } from "../util/intents/IntentHandler.js";
5 | import usePageViewTracking from "../util/usePageViewTracking";
6 |
7 | initIntentHandlers();
8 |
9 | export default function RootLayout() {
10 | usePageViewTracking();
11 | React.useEffect(() => {
12 | initializeReporter();
13 | }, []);
14 |
15 | return ;
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app/src/authentication/index.ts:
--------------------------------------------------------------------------------
1 | export type { AuthenticationClient, UserRecord } from "./authenticationClient.js";
2 | export {
3 | default as FirebaseAuthenticationClient,
4 | FirebaseOpaqueLoginToken,
5 | FirebaseOpaqueIDToken,
6 | } from "./firebaseAuthenticationClient.js";
7 |
--------------------------------------------------------------------------------
/packages/app/src/authentication/isBrowserStorageAvailable.native.ts:
--------------------------------------------------------------------------------
1 | export default function isSessionStorageAvailable() {
2 | throw new Error("Unimplemented");
3 | }
4 |
--------------------------------------------------------------------------------
/packages/app/src/embedded/TestModeBanner.tsx:
--------------------------------------------------------------------------------
1 | import { styles } from "@withorbit/ui";
2 | import React from "react";
3 | import { Text, View } from "react-native";
4 |
5 | export function TestModeBanner(props: {
6 | colorPalette: styles.colors.ColorPalette;
7 | }) {
8 | /* HACK HACK HACK */
9 | return (
10 |
21 |
27 | TEST MODE: Actions will not be saved.
28 |
29 |
30 | );
31 | }
32 |
--------------------------------------------------------------------------------
/packages/app/src/embedded/ipc/sendUpdatedReviewItemToHost.ts:
--------------------------------------------------------------------------------
1 | import { Task } from "@withorbit/core";
2 | import {
3 | EmbeddedScreenEventType,
4 | EmbeddedScreenTaskUpdateEvent,
5 | } from "@withorbit/embedded-support";
6 |
7 | export function sendUpdatedReviewItemToHost(task: Task) {
8 | const event: EmbeddedScreenTaskUpdateEvent = {
9 | type: EmbeddedScreenEventType.TaskUpdate,
10 | task,
11 | };
12 | parent.postMessage(event, "*");
13 | }
14 |
--------------------------------------------------------------------------------
/packages/app/src/embedded/util/getEmbeddedScreenConfigurationFromURL.ts:
--------------------------------------------------------------------------------
1 | import { EmbeddedScreenConfiguration } from "@withorbit/embedded-support";
2 | import { styles } from "@withorbit/ui";
3 |
4 | export default function getEmbeddedScreenConfigurationFromURL(
5 | href: string,
6 | ): EmbeddedScreenConfiguration | null {
7 | const url = new URL(href);
8 | const params = new URLSearchParams(url.search);
9 | const tasksString = params.get("i");
10 | if (tasksString === null) return null;
11 |
12 | const configuration: EmbeddedScreenConfiguration = JSON.parse(tasksString);
13 | // TODO: validate
14 | const colorPaletteName = configuration.embeddedHostMetadata.colorPaletteName;
15 | if (colorPaletteName && !styles.colors.palettes[colorPaletteName]) {
16 | throw new Error(`Unknown color palette name: ${colorPaletteName}`);
17 | }
18 | return configuration;
19 | }
20 |
--------------------------------------------------------------------------------
/packages/app/src/errorReporting.ts:
--------------------------------------------------------------------------------
1 | import * as Sentry from "@sentry/react-native";
2 | import serviceConfig from "../serviceConfig.js";
3 |
4 | const useSentryInDevelopment = false;
5 |
6 | export function initializeReporter() {
7 | Sentry.init({
8 | dsn: serviceConfig.sentryDSN,
9 | enabled: useSentryInDevelopment,
10 | debug: __DEV__,
11 | });
12 | }
13 |
--------------------------------------------------------------------------------
/packages/app/src/homeRedirect/homeRedirect.tsx:
--------------------------------------------------------------------------------
1 | import { useRouter } from "expo-router";
2 |
3 | // Expo Router doesn't support platform extensions in its page-based routing. Instead, we have to support some non-route component which has the extensions.
4 | // https://docs.expo.dev/router/advanced/platform-specific-modules/#platform-specific-extensions
5 | export default function Page() {
6 | const router = useRouter();
7 | router.push("/review");
8 | }
9 |
--------------------------------------------------------------------------------
/packages/app/src/homeRedirect/homeRedirect.web.tsx:
--------------------------------------------------------------------------------
1 | // Expo Router doesn't support platform extensions in its page-based routing. Instead, we have to support some non-route component which has the extensions.
2 | // https://docs.expo.dev/router/advanced/platform-specific-modules/#platform-specific-extensions
3 | export { default } from "../app/learnMore.js";
4 |
--------------------------------------------------------------------------------
/packages/app/src/index.js:
--------------------------------------------------------------------------------
1 | import "./util/shims.js";
2 | import "expo-router/entry";
3 |
--------------------------------------------------------------------------------
/packages/app/src/infoPage/InfoPage.tsx:
--------------------------------------------------------------------------------
1 | import { InfoPageProps } from "./InfoPageShared.js";
2 |
3 | // eslint-disable-next-line @typescript-eslint/no-unused-vars
4 | export function InfoPage(props: InfoPageProps): null {
5 | throw new Error("Only implemented on web.");
6 | }
7 |
--------------------------------------------------------------------------------
/packages/app/src/model2/orbitStoreFactory.ts:
--------------------------------------------------------------------------------
1 | import { OrbitStore } from "@withorbit/store-shared";
2 | import OrbitStoreFS from "@withorbit/store-fs";
3 |
4 | export async function createOrbitStore(
5 | databaseName: string,
6 | ): Promise {
7 | return new OrbitStoreFS(databaseName);
8 | }
9 |
10 | export async function createDefaultOrbitStore(): Promise {
11 | return createOrbitStore("shared.orbitStore");
12 | }
13 |
--------------------------------------------------------------------------------
/packages/app/src/model2/orbitStoreFactory.web.ts:
--------------------------------------------------------------------------------
1 | import { OrbitStore } from "@withorbit/store-shared";
2 | import OrbitStoreWeb from "@withorbit/store-web";
3 |
4 | export async function createOrbitStore(
5 | databaseName: string,
6 | ): Promise {
7 | return new OrbitStoreWeb({ databaseName });
8 | }
9 |
10 | export async function createDefaultOrbitStore(): Promise {
11 | return createOrbitStore("shared.orbitStore");
12 | }
13 |
--------------------------------------------------------------------------------
/packages/app/src/reviewSession/LoadingScreen.tsx:
--------------------------------------------------------------------------------
1 | import { styles } from "@withorbit/ui";
2 | import React from "react";
3 | import { ActivityIndicator, View } from "react-native";
4 |
5 | export function LoadingScreen() {
6 | return (
7 |
14 |
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/packages/app/src/util/firebase.ts:
--------------------------------------------------------------------------------
1 | import { FirebaseApp, initializeApp } from "firebase/app";
2 |
3 | let _app: FirebaseApp | null;
4 | export function getDefaultFirebaseApp(): FirebaseApp {
5 | if (!_app) {
6 | _app = initializeApp({
7 | apiKey: "AIzaSyAwlVFBlx4D3s3eSrwOvUyqOKr_DXFmj0c",
8 | authDomain: "metabook-system.firebaseapp.com",
9 | databaseURL: "https://metabook-system.firebaseio.com",
10 | projectId: "metabook-system",
11 | storageBucket: "metabook-system.appspot.com",
12 | messagingSenderId: "748053153064",
13 | appId: "1:748053153064:web:efc2dfbc9ac11d8512bc1d",
14 | });
15 | }
16 | return _app;
17 | }
18 |
--------------------------------------------------------------------------------
/packages/app/src/util/firebaseAuth.ts:
--------------------------------------------------------------------------------
1 | // @ts-ignore https://github.com/firebase/firebase-js-sdk/issues/7584
2 | import { getReactNativePersistence } from "@firebase/auth/dist/rn/index.js";
3 | import { Auth, connectAuthEmulator, initializeAuth } from "firebase/auth";
4 | import ReactNativeAsyncStorage from "@react-native-async-storage/async-storage";
5 | import serviceConfig from "../../serviceConfig.js";
6 | import { getDefaultFirebaseApp } from "./firebase.js";
7 |
8 | let _auth: Auth | null = null;
9 | export function getFirebaseAuth(): Auth {
10 | if (!_auth) {
11 | _auth = initializeAuth(getDefaultFirebaseApp(), {
12 | persistence: getReactNativePersistence(ReactNativeAsyncStorage),
13 | });
14 | if (__DEV__ && serviceConfig.shouldUseLocalBackend) {
15 | connectAuthEmulator(_auth, "http://localhost:9099/");
16 | }
17 | }
18 | return _auth;
19 | }
20 |
--------------------------------------------------------------------------------
/packages/app/src/util/firebaseAuth.web.ts:
--------------------------------------------------------------------------------
1 | import { Auth, connectAuthEmulator, getAuth } from "firebase/auth";
2 | import serviceConfig from "../../serviceConfig.js";
3 | import { getDefaultFirebaseApp } from "./firebase.js";
4 |
5 | let _auth: Auth | null = null;
6 | export function getFirebaseAuth(): Auth {
7 | if (!_auth) {
8 | _auth = getAuth(getDefaultFirebaseApp());
9 | if (__DEV__ && serviceConfig.shouldUseLocalBackend) {
10 | connectAuthEmulator(_auth, "http://localhost:9099/");
11 | }
12 | }
13 | return _auth;
14 | }
15 |
--------------------------------------------------------------------------------
/packages/app/src/util/intents/IntentHandler.ts:
--------------------------------------------------------------------------------
1 | import { NativeEventEmitter, NativeModules } from "react-native";
2 | import {
3 | handleIngestEventWithDefaultStore,
4 | IngestEventEmitterType,
5 | } from "./handleIngestEvent.js";
6 |
7 | const { IngestEventEmitter } = NativeModules as {
8 | IngestEventEmitter: IngestEventEmitterType;
9 | };
10 |
11 | const eventEmitter = new NativeEventEmitter(IngestEventEmitter);
12 |
13 | export function initIntentHandlers() {
14 | eventEmitter.addListener(
15 | "onIngestEvent",
16 | handleIngestEventWithDefaultStore(IngestEventEmitter),
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/packages/app/src/util/intents/IntentHandler.web.ts:
--------------------------------------------------------------------------------
1 | export function initIntentHandlers() {
2 | // no-op on web
3 | }
4 |
--------------------------------------------------------------------------------
/packages/app/src/util/shims.ts:
--------------------------------------------------------------------------------
1 | import { getRandomValues, randomUUID } from "expo-crypto";
2 | // @ts-ignore
3 | global.crypto ||= {};
4 | // @ts-ignore
5 | global.crypto.getRandomValues = getRandomValues;
6 | // @ts-ignore
7 | global.crypto.randomUUID = randomUUID;
8 |
9 | import { shim as shimBase64 } from "react-native-quick-base64";
10 | shimBase64(); // add btoa to globals for @withorbit/core
11 |
--------------------------------------------------------------------------------
/packages/app/src/util/shims.web.ts:
--------------------------------------------------------------------------------
1 | // no-op
2 |
--------------------------------------------------------------------------------
/packages/app/src/util/useAPIClient.tsx:
--------------------------------------------------------------------------------
1 | import OrbitAPIClient from "@withorbit/api-client";
2 | import React from "react";
3 | import serviceConfig from "../../serviceConfig.js";
4 | import { AuthenticationClient } from "../authentication/index.js";
5 |
6 | export function useAPIClient(
7 | authenticationClient: AuthenticationClient,
8 | ): OrbitAPIClient {
9 | return React.useMemo(
10 | () =>
11 | new OrbitAPIClient(
12 | async () => ({
13 | idToken: (await authenticationClient.getCurrentIDToken()) as string,
14 | }),
15 | { baseURL: serviceConfig.httpsAPIBaseURLString },
16 | ),
17 | [authenticationClient],
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/packages/app/src/util/useAsyncResult.ts:
--------------------------------------------------------------------------------
1 | import { useWeakRef } from "@withorbit/ui";
2 | import React from "react";
3 |
4 | export function useAsyncResult(initializer: () => Promise): T | null {
5 | const [result, setResult] = React.useState(null);
6 | const isCancelled = React.useRef(false);
7 |
8 | // We don't re-run the initializer if it changes.
9 | const weakInitializer = useWeakRef(initializer);
10 | React.useEffect(() => {
11 | weakInitializer.current().then((result) => {
12 | if (!isCancelled.current) {
13 | setResult(result);
14 | }
15 | });
16 |
17 | return () => {
18 | isCancelled.current = true;
19 | };
20 | }, [weakInitializer]);
21 | return result;
22 | }
23 |
--------------------------------------------------------------------------------
/packages/app/src/util/useByrefCallback.ts:
--------------------------------------------------------------------------------
1 | import { useWeakRef } from "@withorbit/ui";
2 | import { useCallback } from "react";
3 |
4 | // Returns a fixed function reference which calls the most recent value of `callback`. Useful for avoiding excess dependencies or recomputations in React hooks around callbacks.
5 | export default function useByrefCallback(
6 | callback: (...args: Args) => Result,
7 | ): (...args: Args) => Result {
8 | const callbackRef = useWeakRef(callback);
9 | return useCallback(
10 | (...args: Args) => {
11 | return callbackRef.current(...args);
12 | },
13 | [callbackRef],
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/packages/app/src/util/usePageViewTracking.ts:
--------------------------------------------------------------------------------
1 | export default function usePageViewTracking() {
2 | // Only implemented for web.
3 | return;
4 | }
5 |
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@1x.png
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@2x.png
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@3x.png
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@1x.png
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@2x.png
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@3x.png
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@1x.png
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@2x.png
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@3x.png
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-60x60@2x.png
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-60x60@3x.png
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-76x76@1x.png
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-76x76@2x.png
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/App-Icon-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/app/targets/widgets/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/WidgetBackground.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/check-center.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "check-center.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "template-rendering-intent" : "template"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/check-center.imageset/check-center.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/cross-center.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "cross-center.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "template-rendering-intent" : "template"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/reveal-accent-center.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "reveal-accent-center.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "template-rendering-intent" : "template"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/reveal-accent-center.imageset/reveal-accent-center.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/reveal-center.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "reveal-center.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "template-rendering-intent" : "template"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/app/targets/widgets/Assets.xcassets/reveal-center.imageset/reveal-center.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/app/targets/widgets/OrbitWidgetBundle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OrbitWidgetBundle.swift
3 | // OrbitWidget
4 | //
5 | // Created by Andy Matuschak on 2024-06-26.
6 | //
7 |
8 | import SwiftUI
9 | import WidgetKit
10 |
11 | @main
12 | struct OrbitWidgetBundle: WidgetBundle {
13 | var body: some Widget {
14 | OrbitHomeScreen()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app/targets/widgets/expo-target.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "widget",
3 | "name": "OrbitWidget",
4 | "icon": "../../app-assets/starburst-icon.png",
5 | "entitlements": {
6 | "com.apple.security.application-groups": ["group.com.withorbit.native"]
7 | },
8 | "deploymentTarget": "18.0"
9 | }
10 |
--------------------------------------------------------------------------------
/packages/app/targets/widgets/generated.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.application-groups
6 |
7 | group.com.withorbit.native
8 |
9 |
10 |
--------------------------------------------------------------------------------
/packages/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | [
4 | "@babel/preset-env",
5 | {
6 | targets: {
7 | node: "current",
8 | },
9 | },
10 | ],
11 | "@babel/preset-typescript",
12 | ],
13 | };
14 |
--------------------------------------------------------------------------------
/packages/backend/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "metabook-system"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/packages/backend/.gitignore:
--------------------------------------------------------------------------------
1 | .runtimeconfig.json
2 |
--------------------------------------------------------------------------------
/packages/backend/LICENSE:
--------------------------------------------------------------------------------
1 | AGPL-3.0-or-later OR BUSL-1.1
2 |
--------------------------------------------------------------------------------
/packages/backend/babel.config.cjs:
--------------------------------------------------------------------------------
1 | // babel.config.js
2 | module.exports = {
3 | presets: [
4 | [
5 | "@babel/preset-env",
6 | {
7 | targets: {
8 | node: "current",
9 | },
10 | },
11 | ],
12 | "@babel/preset-typescript",
13 | ],
14 | plugins: [
15 | [
16 | "@babel/plugin-syntax-import-attributes",
17 | // TODO remove when we move to Node 22 and update import assert to import with
18 | { deprecatedAssertSyntax: true },
19 | ],
20 | ],
21 | };
22 |
--------------------------------------------------------------------------------
/packages/backend/bigQuerySchemas/events.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "mode": "REQUIRED",
4 | "name": "userID",
5 | "type": "STRING"
6 | },
7 | {
8 | "mode": "REQUIRED",
9 | "name": "id",
10 | "type": "STRING"
11 | },
12 | {
13 | "mode": "REQUIRED",
14 | "name": "entityID",
15 | "type": "STRING"
16 | },
17 | {
18 | "mode": "REQUIRED",
19 | "name": "type",
20 | "type": "STRING"
21 | },
22 | {
23 | "mode": "REQUIRED",
24 | "name": "timestamp",
25 | "type": "TIMESTAMP"
26 | },
27 | {
28 | "mode": "REQUIRED",
29 | "name": "dataJSON",
30 | "type": "STRING"
31 | },
32 | {
33 | "mode": "REQUIRED",
34 | "name": "entityJSON",
35 | "type": "STRING"
36 | }
37 | ]
38 |
--------------------------------------------------------------------------------
/packages/backend/bigQuerySchemas/userEvents.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "mode": "REQUIRED",
4 | "name": "timestamp",
5 | "type": "TIMESTAMP"
6 | },
7 | {
8 | "mode": "REQUIRED",
9 | "name": "userID",
10 | "type": "STRING"
11 | },
12 | {
13 | "mode": "REQUIRED",
14 | "name": "eventName",
15 | "type": "STRING"
16 | }
17 | ]
18 |
--------------------------------------------------------------------------------
/packages/backend/emulator-data/auth_export/accounts.json:
--------------------------------------------------------------------------------
1 | {"kind":"identitytoolkit#DownloadAccountResponse","users":[{"localId":"WvLvv9uDtFha1jVTyxObVl00gPFN","createdAt":"1615510792970","lastLoginAt":"1615510792970","displayName":"Test User","photoUrl":"","emailVerified":false,"email":"test@test.com","salt":"fakeSaltUStXd0I6orYCUZTjBL7d","passwordHash":"fakeHash:salt=fakeSaltUStXd0I6orYCUZTjBL7d:password=testtest","passwordUpdatedAt":1615510792970,"validSince":"1615510792","providerUserInfo":[{"providerId":"password","email":"test@test.com","federatedId":"test@test.com","rawId":"test@test.com","displayName":"Test User","photoUrl":""}]}]}
--------------------------------------------------------------------------------
/packages/backend/emulator-data/auth_export/config.json:
--------------------------------------------------------------------------------
1 | {"signIn":{"allowDuplicateEmails":false}}
--------------------------------------------------------------------------------
/packages/backend/emulator-data/firebase-export-metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "9.6.1",
3 | "firestore": {
4 | "version": "1.11.12",
5 | "path": "firestore_export",
6 | "metadata_file": "firestore_export/firestore_export.overall_export_metadata"
7 | },
8 | "auth": {
9 | "version": "9.6.1",
10 | "path": "auth_export"
11 | }
12 | }
--------------------------------------------------------------------------------
/packages/backend/emulator-data/firestore_export/all_namespaces/all_kinds/all_namespaces_all_kinds.export_metadata:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/backend/emulator-data/firestore_export/all_namespaces/all_kinds/all_namespaces_all_kinds.export_metadata
--------------------------------------------------------------------------------
/packages/backend/emulator-data/firestore_export/all_namespaces/all_kinds/output-0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/backend/emulator-data/firestore_export/all_namespaces/all_kinds/output-0
--------------------------------------------------------------------------------
/packages/backend/emulator-data/firestore_export/firestore_export.overall_export_metadata:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/backend/emulator-data/firestore_export/firestore_export.overall_export_metadata
--------------------------------------------------------------------------------
/packages/backend/firebase-storage-cors.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "origin": ["*"],
4 | "method": ["GET"],
5 | "maxAgeSeconds": 3600
6 | }
7 | ]
8 |
--------------------------------------------------------------------------------
/packages/backend/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "firestore": {
3 | "rules": "firestore.rules",
4 | "indexes": "firestore.indexes.json"
5 | },
6 | "functions": {
7 | "source": "."
8 | },
9 | "emulators": {
10 | "firestore": {
11 | "port": 8080
12 | },
13 | "auth": {
14 | "port": 9099
15 | },
16 | "functions": {
17 | "port": 5001
18 | },
19 | "pubsub": {
20 | "port": 8085
21 | },
22 | "storage": {
23 | "port": 9199
24 | },
25 | "ui": {
26 | "enabled": true
27 | }
28 | },
29 | "storage": {
30 | "rules": "storage.rules"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/packages/backend/firestore.indexes.json:
--------------------------------------------------------------------------------
1 | {
2 | "indexes": [
3 | {
4 | "collectionGroup": "taskStates",
5 | "queryScope": "COLLECTION",
6 | "fields": [
7 | {
8 | "fieldPath": "taskMetadata.isDeleted",
9 | "order": "ASCENDING"
10 | },
11 | {
12 | "fieldPath": "dueTimestampMillis",
13 | "order": "ASCENDING"
14 | }
15 | ]
16 | }
17 | ],
18 | "fieldOverrides": []
19 | }
20 |
--------------------------------------------------------------------------------
/packages/backend/firestore.rules:
--------------------------------------------------------------------------------
1 | service cloud.firestore {
2 | match /databases/{database}/documents {
3 | match /data/{document=**} {
4 | allow read;
5 | }
6 | match /users/{user} {
7 | match /{document=**} {
8 | allow read, write: if request.auth != null && (request.auth.uid == user || (request.auth.token != null && "admin" in request.auth.token && request.auth.token.admin == true));
9 | }
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/packages/backend/jest.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | globals: {
3 | Uint8Array: Uint8Array, // use Node's implementation; https://github.com/facebook/jest/issues/4422
4 | },
5 | moduleNameMapper: {
6 | "^(\\.{1,2}/.*)\\.js$": "$1",
7 | },
8 | testEnvironment: "node",
9 | testMatch: ["**/?(*.)+(spec|test).ts?(x)"],
10 | testPathIgnorePatterns: ["dist", "node_modules"],
11 | transformIgnorePatterns: ["is-typedarray"],
12 | };
13 |
--------------------------------------------------------------------------------
/packages/backend/scripts/deployShared.js:
--------------------------------------------------------------------------------
1 | import path from "path";
2 |
3 | export const packageRoot = path.join(import.meta.dir, "..");
4 | export const firebaseJSONPath = path.join(packageRoot, "firebase.json");
5 | export const isolatedFolderName = "isolate";
6 | export const isolatedPath = path.join(packageRoot, isolatedFolderName);
7 |
--------------------------------------------------------------------------------
/packages/backend/scripts/postdeploy.js:
--------------------------------------------------------------------------------
1 | // See predeploy.js for more details.
2 | import fs from "fs";
3 | import { firebaseJSONPath, isolatedPath } from "./deployShared.js";
4 | import { execSync } from "child_process";
5 |
6 | // Restore the firebase configuration file.
7 | fs.renameSync(`${firebaseJSONPath}.bak`, firebaseJSONPath);
8 |
9 | // We also need to remove the isolated package directory.
10 | fs.rmSync(isolatedPath, { recursive: true, force: true });
11 |
12 | // Git status should be clean again.
13 | const gitStatus = execSync("git status --porcelain").toString();
14 | if (gitStatus !== "") {
15 | throw new Error(
16 | "git status is not clean after cleaning up deployment... unexpected!",
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/packages/backend/src/@types/isbot-fast/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module "isbot-fast" {
2 | function isBot(userAgent: string): boolean;
3 | export default isBot;
4 | }
5 |
--------------------------------------------------------------------------------
/packages/backend/src/__tests__/emulators.ts:
--------------------------------------------------------------------------------
1 | import fs from "fs";
2 | import { LocalFileStorageService } from "../fileStorageService/localFileStorageService.js";
3 | import { clearFirestoreData } from "./firebaseTesting.js";
4 |
5 | export async function resetLocalEmulators() {
6 | await clearFirestoreData();
7 | await resetLocalFileServiceData();
8 | }
9 |
10 | export async function resetLocalFileServiceData() {
11 | await fs.promises
12 | .rm(LocalFileStorageService.getTestStorageLocation(), {
13 | recursive: true,
14 | force: true,
15 | })
16 | .catch(() => {
17 | return;
18 | }); // it's OK if this fails: it might not exist yet.
19 | await fs.promises.mkdir(LocalFileStorageService.getTestStorageLocation(), {
20 | recursive: true,
21 | });
22 | }
23 |
--------------------------------------------------------------------------------
/packages/backend/src/api/internal/auth/consumeAccessCode.ts:
--------------------------------------------------------------------------------
1 | import { sharedServerDatabase } from "../../../db/index.js";
2 | import { InternalAPISpec } from "../../internalSpec.js";
3 | import { authenticatedRequestHandler } from "../../util/authenticateRequest.js";
4 | import { CachePolicy, TypedRouteHandler } from "../../util/typedRouter.js";
5 |
6 | export const consumeAccessCode: TypedRouteHandler<
7 | InternalAPISpec,
8 | "/internal/auth/consumeAccessCode",
9 | "GET"
10 | > = authenticatedRequestHandler(async (request, userID) => {
11 | const loginToken =
12 | await sharedServerDatabase().auth.createCustomLoginToken(userID);
13 |
14 | return {
15 | status: 200,
16 | text: loginToken,
17 | cachePolicy: CachePolicy.NoStore,
18 | };
19 | });
20 |
--------------------------------------------------------------------------------
/packages/backend/src/api/internal/auth/personalAccessTokens.ts:
--------------------------------------------------------------------------------
1 | import { sharedServerDatabase } from "../../../db/index.js";
2 | import { InternalAPISpec } from "../../internalSpec.js";
3 | import { authenticatedRequestHandler } from "../../util/authenticateRequest.js";
4 | import { CachePolicy, TypedRouteHandler } from "../../util/typedRouter.js";
5 |
6 | export const personalAccessTokens: TypedRouteHandler<
7 | InternalAPISpec,
8 | "/internal/auth/personalAccessTokens",
9 | "POST"
10 | > = authenticatedRequestHandler(async (request, userID) => {
11 | const token =
12 | await sharedServerDatabase().auth.createPersonalAccessToken(userID);
13 | return {
14 | status: 200,
15 | cachePolicy: CachePolicy.NoStore,
16 | json: {
17 | token,
18 | },
19 | };
20 | });
21 |
--------------------------------------------------------------------------------
/packages/backend/src/api/internal/auth/sessionCookie.ts:
--------------------------------------------------------------------------------
1 | import express from "express";
2 |
3 | export const sessionCookieName = "__session"; // mandated by Firebase hosting, c.f. https://firebase.google.com/docs/hosting/manage-cache#using_cookies
4 | export function getSessionCookieOptions(
5 | expirationDate: Date,
6 | ): express.CookieOptions {
7 | return {
8 | domain: "withorbit.com",
9 | path: "/",
10 | secure: true,
11 | httpOnly: true,
12 | sameSite: "none", // Our use in an embedded context requires a "none" same-site setting, since these are considered "unsafe" requests.
13 | expires: expirationDate,
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/packages/backend/src/api/internalSpec.ts:
--------------------------------------------------------------------------------
1 | export type InternalAPISpec = {
2 | "/internal/auth/consumeAccessCode": {
3 | GET: {
4 | response: string;
5 | };
6 | };
7 | "/internal/auth/personalAccessTokens": {
8 | POST: {
9 | response: { token: string };
10 | };
11 | };
12 | };
13 |
--------------------------------------------------------------------------------
/packages/backend/src/api/util/corsHandler.ts:
--------------------------------------------------------------------------------
1 | import express from "express";
2 | import cors from "cors";
3 |
4 | const corsHandler: express.RequestHandler = cors({
5 | origin: [
6 | /\.withorbit.com$/,
7 | /^https?:\/\/localhost(:\d+)?$/,
8 | // HACK for fall 2022 prototype
9 | "https://orbit-app--fall-2022-yzhqe6jr.web.app",
10 | "https://orbit-mk.vercel.app",
11 | ],
12 | });
13 | export default corsHandler;
14 |
--------------------------------------------------------------------------------
/packages/backend/src/api/util/putAndLogEvents.ts:
--------------------------------------------------------------------------------
1 | import { Event } from "@withorbit/core";
2 | import { sharedServerDatabase } from "../../db/index.js";
3 | import { sharedLoggingService } from "../../logging/index.js";
4 |
5 | export async function putAndLogEvents(
6 | userID: string,
7 | events: Event[],
8 | ): Promise {
9 | const db = sharedServerDatabase().getUserDatabase(userID);
10 | const eventRecords = await db.putEvents(events);
11 |
12 | for (const { event, entity } of eventRecords) {
13 | sharedLoggingService.logEvent({
14 | userID,
15 | event,
16 | entity,
17 | });
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/packages/backend/src/db/firestore.ts:
--------------------------------------------------------------------------------
1 | import { getFirestore } from "firebase-admin/firestore";
2 | import type { Firestore } from "firebase-admin/firestore";
3 | import { getApp } from "../firebaseApp.js";
4 |
5 | let _database: Firestore | null = null;
6 |
7 | export function getDatabase(): Firestore {
8 | if (!_database) {
9 | _database = getFirestore(getApp());
10 | }
11 | return _database;
12 | }
13 |
--------------------------------------------------------------------------------
/packages/backend/src/db/userMetadata.ts:
--------------------------------------------------------------------------------
1 | export interface UserMetadata {
2 | registrationTimestampMillis: number;
3 | activeTaskCount?: number;
4 |
5 | sessionNotificationState?: SessionNotificationState;
6 | isUnsubscribedFromSessionNotifications?: boolean;
7 | snoozeSessionNotificationsUntilTimestampMillis?: number;
8 |
9 | coreMigrationTimestampMillis?: number;
10 | }
11 |
12 | export interface SessionNotificationState {
13 | firstNotificationTimestampMillis: number;
14 | lastNotificationTimestampMillis: number;
15 | sentNotificationCount: number;
16 | }
17 |
--------------------------------------------------------------------------------
/packages/backend/src/db/withFirebaseFields.ts:
--------------------------------------------------------------------------------
1 | import { FieldValue } from "firebase-admin/firestore";
2 |
3 | export type WithFirebaseFields = {
4 | [K in keyof T]:
5 | | T[K]
6 | | (T[K] extends Record
7 | ? WithFirebaseFields
8 | : FieldValue);
9 | };
10 |
--------------------------------------------------------------------------------
/packages/backend/src/email/dummy.ts:
--------------------------------------------------------------------------------
1 | import { EmailService, EmailSpec } from "./types.js";
2 |
3 | export const dummyEmailService: EmailService = {
4 | async sendEmail(
5 | recipientEmailAddress: string,
6 | spec: EmailSpec,
7 | ): Promise {
8 | console.log(`[Email service]:
9 | To: ${recipientEmailAddress}
10 | Subject: ${spec.subject}
11 | Plaintext:
12 | ${spec.text}
13 |
14 | HTML:
15 | ${spec.html}
16 |
17 | =========`);
18 | },
19 | };
20 |
--------------------------------------------------------------------------------
/packages/backend/src/email/index.ts:
--------------------------------------------------------------------------------
1 | import serviceConfig from "../serviceConfig.js";
2 | import { isRunningInEmulator } from "../util/isRunningInEmulator.js";
3 | import { dummyEmailService } from "./dummy.js";
4 | import MailjetEmailService from "./mailjet.js";
5 | import { EmailService } from "./types.js";
6 |
7 | let _sharedEmailService: EmailService | null = null;
8 | export default function getDefaultEmailService(): EmailService {
9 | if (!_sharedEmailService) {
10 | _sharedEmailService = isRunningInEmulator
11 | ? dummyEmailService
12 | : new MailjetEmailService(
13 | serviceConfig.mailjet.apiKey,
14 | serviceConfig.mailjet.secretKey,
15 | );
16 | }
17 | return _sharedEmailService;
18 | }
19 |
--------------------------------------------------------------------------------
/packages/backend/src/email/types.ts:
--------------------------------------------------------------------------------
1 | export interface EmailService {
2 | sendEmail(recipientEmailAddress: string, spec: EmailSpec): Promise;
3 | }
4 |
5 | export interface EmailSpec {
6 | subject: string;
7 | text: string;
8 | html?: string;
9 | }
10 |
--------------------------------------------------------------------------------
/packages/backend/src/fileStorageService/fileStorageService.ts:
--------------------------------------------------------------------------------
1 | export interface FileStorageService {
2 | fileExists(subpath: string): Promise;
3 | storeFile(subpath: string, data: Uint8Array, mimeType: string): Promise;
4 | formatURL(subpath: string): string;
5 | resolveFile(subpath: string): Promise;
6 | getMIMEType(subpath: string): Promise;
7 | copyFile(fromSubpath: string, toSubpath: string): Promise;
8 | }
9 |
10 | export type FileStorageResolution = { data: Uint8Array; mimeType: string };
11 |
--------------------------------------------------------------------------------
/packages/backend/src/fileStorageService/index.ts:
--------------------------------------------------------------------------------
1 | import { FileStorageService } from "./fileStorageService.js";
2 | import { GoogleCloudFileStorageService } from "./googleCloudFileStorageService.js";
3 |
4 | let _sharedFileStorageService: FileStorageService | null;
5 | export function sharedFileStorageService(): FileStorageService {
6 | if (!_sharedFileStorageService) {
7 | _sharedFileStorageService = new GoogleCloudFileStorageService();
8 | }
9 | return _sharedFileStorageService;
10 | }
11 |
--------------------------------------------------------------------------------
/packages/backend/src/firebaseApp.ts:
--------------------------------------------------------------------------------
1 | import { App, initializeApp } from "firebase-admin/app";
2 |
3 | let _app: App | null = null;
4 | export function getApp(): App {
5 | if (!_app) {
6 | _app = initializeApp();
7 | }
8 | return _app;
9 | }
10 |
--------------------------------------------------------------------------------
/packages/backend/src/firebaseFunctions/api.ts:
--------------------------------------------------------------------------------
1 | import functions from "firebase-functions";
2 | import { createAPIApp } from "../api.js";
3 |
4 | export const api = functions
5 | .runWith({ memory: "1GB" })
6 | .https.onRequest(createAPIApp());
7 |
--------------------------------------------------------------------------------
/packages/backend/src/firebaseFunctions/notifier/index.ts:
--------------------------------------------------------------------------------
1 | export { notificationScheduler } from "./notificationScheduler.js";
2 | export { processUserNotificationSubscriber } from "./processUserNotificationSubscriber.js";
3 |
--------------------------------------------------------------------------------
/packages/backend/src/index.ts:
--------------------------------------------------------------------------------
1 | // Each function exported by this module corresponds to a Firebase cloud function. Firebase will provision cloud functions accordingly.
2 | export { default as onUserCreate } from "./firebaseFunctions/onUserCreate.js";
3 | export { updateNotificationSettings } from "./firebaseFunctions/updateNotificationSettings.js";
4 |
5 | export { api } from "./firebaseFunctions/api.js";
6 |
7 | export * from "./firebaseFunctions/notifier/index.js";
8 |
--------------------------------------------------------------------------------
/packages/backend/src/logging/dummy.ts:
--------------------------------------------------------------------------------
1 | import { LoggingService } from "./interface.js";
2 |
3 | function createTracer(name: string) {
4 | return (...args: unknown[]) => {
5 | console.log("[Logging service]: ", name, ...args);
6 | };
7 | }
8 |
9 | export const dummyLoggingService = new Proxy(
10 | {},
11 | {
12 | get: function (_target, prop) {
13 | return createTracer(prop.toString());
14 | },
15 | },
16 | ) as LoggingService;
17 |
--------------------------------------------------------------------------------
/packages/backend/src/logging/index.ts:
--------------------------------------------------------------------------------
1 | import { isRunningInEmulator } from "../util/isRunningInEmulator.js";
2 | import { bigQueryLoggingService } from "./bigQuery.js";
3 | import { dummyLoggingService } from "./dummy.js";
4 | import { LoggingService } from "./interface.js";
5 |
6 | let sharedLoggingService: LoggingService = isRunningInEmulator
7 | ? dummyLoggingService
8 | : bigQueryLoggingService;
9 | export { sharedLoggingService };
10 |
11 | // i.e. for tests
12 | export function _overrideSharedLoggingService(loggingService: LoggingService) {
13 | sharedLoggingService = loggingService;
14 | }
15 |
--------------------------------------------------------------------------------
/packages/backend/src/notifications/__fixtures__/generateDueTasks.ts:
--------------------------------------------------------------------------------
1 | import { generateUniqueID, Task } from "@withorbit/core";
2 | import { createTestTask } from "@withorbit/sample-data";
3 | import * as dateFns from "date-fns";
4 |
5 | export function generateDueTasks(
6 | baseTimestampMillis: number,
7 | count: number,
8 | dueInDays: number,
9 | intervalDays: number,
10 | ): Task[] {
11 | const output: Task[] = [];
12 | for (let i = 0; i < count; i++) {
13 | output.push(
14 | createTestTask({
15 | id: generateUniqueID(),
16 | dueTimestampMillis: dateFns
17 | .addDays(baseTimestampMillis, dueInDays)
18 | .valueOf(),
19 | intervalMillis: intervalDays * 1000 * 60 * 60 * 24,
20 | }),
21 | );
22 | }
23 | return output;
24 | }
25 |
--------------------------------------------------------------------------------
/packages/backend/src/notifications/index.ts:
--------------------------------------------------------------------------------
1 | export { processUserNotification } from "./processUserNotification.js";
2 |
--------------------------------------------------------------------------------
/packages/backend/src/util/isRunningInEmulator.ts:
--------------------------------------------------------------------------------
1 | export const isRunningInEmulator = !!process.env.FUNCTIONS_EMULATOR;
2 |
--------------------------------------------------------------------------------
/packages/backend/src/util/isRunningInTest.ts:
--------------------------------------------------------------------------------
1 | export const isRunningInTest = process.env.JEST_WORKER_ID !== undefined;
2 |
--------------------------------------------------------------------------------
/packages/backend/storage.rules:
--------------------------------------------------------------------------------
1 | rules_version = '2';
2 | service firebase.storage {
3 | match /b/{bucket}/o {
4 | match /{allPaths=**} {
5 | // All access through admin SDK via APIs
6 | allow read, write: if false;
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/packages/backend/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.json",
3 | "compilerOptions": {
4 | "baseUrl": "./src",
5 | "outDir": "./dist",
6 | "rootDir": "./src",
7 | "lib": ["dom", "es2019"],
8 | "types": ["jest", "node"],
9 | "target": "es2019"
10 | },
11 | "include": ["src/**/*"],
12 | "references": [
13 | {
14 | "path": "../core"
15 | },
16 | {
17 | "path": "../sample-data"
18 | },
19 | {
20 | "path": "../api"
21 | },
22 | {
23 | "path": "../store-shared"
24 | }
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/packages/core/Readme.md:
--------------------------------------------------------------------------------
1 | # @withorbit/core
2 |
3 | This package defines Orbit's core data structures, like `Event` and `Task`. It also defines some convenience functionality used by many other components.
4 |
5 | To support offline-first workflows, Orbit is built using an event sourcing model, meaning that events (like "remembered this task") are the source of truth. These events are combined with an "event reducer" to compute the state of an object at any given time.
6 |
7 | This package runs on Node.js, browser, and React Native environments.
8 |
9 | * To build: `bun run build`
10 | * To run tests: `bun run test`
11 |
12 | ```
13 | Copyright 2020 Andy Matuschak
14 | SPDX-License-Identifier: Apache-2.0
15 | ```
16 |
--------------------------------------------------------------------------------
/packages/core/babel.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | [
4 | "@babel/preset-env",
5 | {
6 | targets: {
7 | node: "current",
8 | },
9 | },
10 | ],
11 | "@babel/preset-typescript",
12 | ],
13 | };
14 |
--------------------------------------------------------------------------------
/packages/core/jest.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleNameMapper: {
3 | "^(\\.{1,2}/.*)\\.js$": "$1",
4 | },
5 | testEnvironment: "node",
6 | testMatch: ["**/?(*.)+(spec|test).ts?(x)"],
7 | testPathIgnorePatterns: ["dist", "node_modules"],
8 | };
9 |
--------------------------------------------------------------------------------
/packages/core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@withorbit/core",
3 | "version": "0.0.1",
4 | "license": "Apache-2.0",
5 | "private": true,
6 | "type": "module",
7 | "main": "./dist/index.js",
8 | "types": "./dist/index.d.ts",
9 | "exports": "./dist/index.js",
10 | "files": [
11 | "dist"
12 | ],
13 | "sideEffects": false,
14 | "scripts": {
15 | "build": "tsc -b",
16 | "test": "jest"
17 | },
18 | "devDependencies": {
19 | "@babel/core": "^7.14.6",
20 | "@babel/preset-env": "^7.14.7",
21 | "@babel/preset-typescript": "^7.14.5",
22 | "@types/jest": "^29.5.5",
23 | "@types/node": "^20.10.4",
24 | "babel-jest": "^29.7.0",
25 | "jest": "^29.7.0",
26 | "typescript": "^5.3.3"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/packages/core/src/colorPaletteName.ts:
--------------------------------------------------------------------------------
1 | // A bit awkward: these definitions are "really" in @withorbit/ui, but we don't want @withorbit/core to depend on @withorbit/ui. So we define just the names as a type here, and use a type constraint to make sure that the definitions in @withorbit/ui don't differ from this.
2 | export type ColorPaletteName =
3 | | "red"
4 | | "orange"
5 | | "brown"
6 | | "yellow"
7 | | "lime"
8 | | "green"
9 | | "turquoise"
10 | | "cyan"
11 | | "blue"
12 | | "violet"
13 | | "purple"
14 | | "pink";
15 |
--------------------------------------------------------------------------------
/packages/core/src/eventReducers/attachmentReducers.ts:
--------------------------------------------------------------------------------
1 | import { AttachmentReference } from "../entities/attachmentReference.js";
2 | import { EntityType } from "../entity.js";
3 | import { AttachmentIngestEvent } from "../event.js";
4 |
5 | export function attachmentIngestEventReducer(
6 | oldAttachment: AttachmentReference | null,
7 | event: AttachmentIngestEvent,
8 | ): AttachmentReference {
9 | if (oldAttachment) {
10 | return oldAttachment;
11 | } else {
12 | return {
13 | id: event.entityID,
14 | createdAtTimestampMillis: event.timestampMillis,
15 | type: EntityType.AttachmentReference,
16 | mimeType: event.mimeType,
17 | };
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/packages/core/src/generateUniqueID.test.ts:
--------------------------------------------------------------------------------
1 | import {
2 | encodeUUIDBytesToWebSafeBase64ID,
3 | generateUniqueID,
4 | } from "./generateUniqueID.js";
5 |
6 | test("matches expected pattern", () => {
7 | expect(generateUniqueID().match(/^[0-9a-zA-Z_\-]{22}$/)).toBeTruthy();
8 | });
9 |
10 | test("different each time", () => {
11 | expect(generateUniqueID()).not.toEqual(generateUniqueID());
12 | });
13 |
14 | test("stable output", () => {
15 | const bytes = Uint8Array.from([
16 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
17 | ]);
18 | const id = encodeUUIDBytesToWebSafeBase64ID(bytes);
19 | expect(id).toMatchInlineSnapshot(`"AAECAwQFBgcICQoLDA0ODw"`);
20 | });
21 |
--------------------------------------------------------------------------------
/packages/core/src/index.ts:
--------------------------------------------------------------------------------
1 | export type { ColorPaletteName } from "./colorPaletteName.js";
2 | export * from "./entity.js";
3 | export * from "./event.js";
4 | export * from "./entities/task.js";
5 | export * from "./entities/attachmentReference.js";
6 | export * from "./eventReducer.js";
7 | export * from "./generateUniqueID.js";
8 | export * from "./reviewQueue.js";
9 | export * from "./schedulers/spacedRepetitionScheduler.js";
10 |
--------------------------------------------------------------------------------
/packages/core/src/scheduler.ts:
--------------------------------------------------------------------------------
1 | import { TaskComponentState } from "./entities/task.js";
2 | import { TaskRepetitionOutcome } from "./event.js";
3 |
4 | export interface Scheduler {
5 | computeNextDueIntervalMillisForRepetition(
6 | componentState: TaskComponentState,
7 | timestampMillis: number,
8 | outcome: TaskRepetitionOutcome,
9 | ): SchedulerOutput;
10 | }
11 |
12 | export type SchedulerOutput = {
13 | dueTimestampMillis: number;
14 | intervalMillis: number;
15 | };
16 |
--------------------------------------------------------------------------------
/packages/core/src/util/crypto.native.ts:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line @typescript-eslint/no-namespace, @typescript-eslint/prefer-namespace-keyword
2 | declare module globalThis {
3 | const crypto: WebCrypto;
4 | }
5 | type WebCrypto = typeof import("node:crypto").webcrypto;
6 |
7 | if (!globalThis.crypto?.getRandomValues) {
8 | throw new Error(
9 | "Need to shim crypto.getRandomValues before importing this (e.g. with expo-crypto)",
10 | );
11 | }
12 | if (!globalThis.crypto?.randomUUID) {
13 | throw new Error(
14 | "Need to shim crypto.randomUUID before importing this (e.g. with expo-crypto)",
15 | );
16 | }
17 |
18 | const getRandomValues = globalThis.crypto.getRandomValues;
19 | const randomUUID = globalThis.crypto.randomUUID;
20 | export const crypto = { getRandomValues, randomUUID };
21 |
--------------------------------------------------------------------------------
/packages/core/src/util/crypto.ts:
--------------------------------------------------------------------------------
1 | export { webcrypto as crypto } from "node:crypto";
2 |
--------------------------------------------------------------------------------
/packages/core/src/util/crypto.web.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const crypto = globalThis.crypto;
4 |
--------------------------------------------------------------------------------
/packages/core/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "rootDir": "./src",
6 | "types": ["jest", "node"]
7 | },
8 | "include": ["./src/**/*.ts", "./@types/**/*.d.ts"]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/docs/.firebaserc:
--------------------------------------------------------------------------------
1 | ../app/.firebaserc
--------------------------------------------------------------------------------
/packages/docs/Readme.md:
--------------------------------------------------------------------------------
1 | # @withorbit/docs
2 |
3 | Source for [Orbit's documentation site](https://docs.withorbit.com).
4 |
5 | To deploy, run: `yarn deploy`.
6 |
7 | ```
8 | Copyright 2020 Andy Matuschak
9 | SPDX-License-Identifier: Apache-2.0
10 | ```
11 |
--------------------------------------------------------------------------------
/packages/docs/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "hosting": {
3 | "target": "orbit-docs",
4 | "public": ".",
5 | "ignore": ["firebase.json", "**/.*", "**/node_modules/**"]
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@withorbit/docs",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "deploy": "firebase deploy"
7 | },
8 | "devDependencies": {
9 | "firebase-tools": "^13.0.1"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/docs/test.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/docs/test.html
--------------------------------------------------------------------------------
/packages/docs/toffoli.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/docs/toffoli.png
--------------------------------------------------------------------------------
/packages/embedded-support/Readme.md:
--------------------------------------------------------------------------------
1 | # embedded-support
2 |
3 | This module contains interfaces and constants used by both `@withorbit/app` and `@withorbit/web-component` to orchestrate the embedded experience.
4 |
5 | ```
6 | Copyright 2020 Andy Matuschak
7 | SPDX-License-Identifier: Apache-2.0
8 | ```
9 |
--------------------------------------------------------------------------------
/packages/embedded-support/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@withorbit/embedded-support",
3 | "version": "0.0.1",
4 | "type": "module",
5 | "main": "./dist/index.js",
6 | "types": "./dist/index.d.ts",
7 | "private": true,
8 | "scripts": {
9 | "build": "tsc -b"
10 | },
11 | "dependencies": {
12 | "@withorbit/core": "0.0.1"
13 | },
14 | "devDependencies": {
15 | "typescript": "^5.3.3"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/packages/embedded-support/src/embeddedScreenInterface.ts:
--------------------------------------------------------------------------------
1 | import { ColorPaletteName, ReviewItem } from "@withorbit/core";
2 |
3 | export interface EmbeddedScreenConfiguration {
4 | reviewItems: ReviewItem[];
5 | // Less than ideal: here AttachmentIDs are keys of a plain old object, but we can't express that in the type (TypeScript will only allow strings and numbers to be keys of indexed types). Normally we'd deal with this by using a Map, but this structure needs to be serialized to/from JSON.
6 | attachmentIDsToURLs: { [AttachmentID: string]: string };
7 | embeddedHostMetadata: EmbeddedHostMetadata;
8 | sessionStartTimestampMillis: number;
9 | isDebug?: boolean;
10 | }
11 |
12 | export interface EmbeddedHostMetadata {
13 | url: string;
14 | title: string | null;
15 | siteName: string | null;
16 | colorPaletteName: ColorPaletteName | null;
17 | }
18 |
--------------------------------------------------------------------------------
/packages/embedded-support/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./embeddedScreenInterface.js";
2 | export * from "./ipc.js";
3 |
--------------------------------------------------------------------------------
/packages/embedded-support/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "rootDir": "./src"
6 | },
7 | "include": ["./src/**/*.ts"],
8 | "references": [
9 | {
10 | "path": "../core"
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/ingester/Readme.md:
--------------------------------------------------------------------------------
1 | # @withorbit/ingester
2 |
3 | This package, in conjunction with `@withorbit/interpreter`, lets you import Orbit prompts from some other data source, and to keep your Orbit database in sync with that data source, ingesting missing prompts and deleting deleted ones as necessary.
4 |
5 | `interpreter` is responsible for parsing those data sources and producing a JSON file which describes the prompts embedded within it. This package can then synchronize an Orbit database with the prompts in that file.
6 |
7 | See the documentation in `interpreter` for example and more detail.
8 |
9 | ---
10 |
11 | ```
12 | Copyright 2023 Andy Matuschak
13 | SPDX-License-Identifier: Apache-2.0
14 | ```
15 |
--------------------------------------------------------------------------------
/packages/ingester/babel.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | [
4 | "@babel/preset-env",
5 | {
6 | targets: {
7 | node: "current",
8 | },
9 | },
10 | ],
11 | "@babel/preset-typescript",
12 | ],
13 | plugins: [
14 | [
15 | "@babel/plugin-syntax-import-attributes",
16 | // TODO remove when we move to Node 22 and update import assert to import with
17 | { deprecatedAssertSyntax: true },
18 | ],
19 | ],
20 | };
21 |
--------------------------------------------------------------------------------
/packages/ingester/jest.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleNameMapper: {
3 | "^(\\.{1,2}/.*)\\.js$": "$1",
4 | },
5 | testEnvironment: "node",
6 | testMatch: ["**/?(*.)+(spec|test).ts?(x)"],
7 | testPathIgnorePatterns: ["dist", "node_modules"],
8 | };
9 |
--------------------------------------------------------------------------------
/packages/ingester/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./ingestible.js";
2 | export * from "./ingest.js";
3 | export * from "./validateIngestible.js";
4 |
--------------------------------------------------------------------------------
/packages/ingester/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "rootDir": "./src",
6 | "types": ["jest", "node"]
7 | },
8 | "include": ["./src/**/*.ts", "./src/**/*.json"],
9 | "references": [
10 | {
11 | "path": "../core"
12 | },
13 | {
14 | "path": "../store-shared"
15 | },
16 | {
17 | "path": "../store-fs"
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/packages/interpreter/babel.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | [
4 | "@babel/preset-env",
5 | {
6 | targets: {
7 | node: "current",
8 | },
9 | },
10 | ],
11 | "@babel/preset-typescript",
12 | ],
13 | };
14 |
--------------------------------------------------------------------------------
/packages/interpreter/jest.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleNameMapper: {
3 | "^(\\.{1,2}/.*)\\.js$": "$1",
4 | },
5 | testEnvironment: "node",
6 | testMatch: ["**/?(*.)+(spec|test).ts?(x)"],
7 | testPathIgnorePatterns: ["dist", "node_modules"],
8 | transformIgnorePatterns: [],
9 | transform: {
10 | "\\.[jt]s$": ["babel-jest", { cwd: __dirname }],
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/packages/interpreter/src/hasher/hasher.ts:
--------------------------------------------------------------------------------
1 | import { TaskSpec } from "@withorbit/core";
2 |
3 | export interface Hasher {
4 | hash(spec: TaskSpec): string;
5 | }
6 |
--------------------------------------------------------------------------------
/packages/interpreter/src/interpreter.ts:
--------------------------------------------------------------------------------
1 | import { Ingestible } from "@withorbit/ingester";
2 |
3 | export interface Interpreter {
4 | interpret(files: InterpretableFile[]): Promise;
5 | }
6 |
7 | export type InterpretableFile = {
8 | name: string;
9 | path: string;
10 | content: string;
11 | };
12 |
--------------------------------------------------------------------------------
/packages/interpreter/src/interpreters/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./markdown/MarkdownInterpreter.js";
2 |
--------------------------------------------------------------------------------
/packages/interpreter/src/interpreters/markdown/utils/getNoteTitle.ts:
--------------------------------------------------------------------------------
1 | import mdast from "mdast";
2 | import { processor } from "../markdown.js";
3 |
4 | export function getNoteTitle(noteRoot: mdast.Root): string | null {
5 | if (noteRoot.children.length > 0) {
6 | // filter out yaml frontmatter
7 | const firstNode = noteRoot.children.filter((n) => n.type !== "yaml")[0];
8 | if (firstNode.type === "heading") {
9 | return processor
10 | .stringify({
11 | type: "root",
12 | children: firstNode.children,
13 | })
14 | .trimEnd();
15 | } else {
16 | return processor
17 | .stringify({ type: "root", children: [firstNode] })
18 | .trimEnd();
19 | }
20 | } else {
21 | return null;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/packages/interpreter/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "rootDir": "./src",
6 | "types": ["jest", "node"]
7 | },
8 | "include": ["./src/**/*.ts", "./src/**/*.json"],
9 | "references": [
10 | {
11 | "path": "../core"
12 | },
13 | {
14 | "path": "../store-fs"
15 | },
16 | {
17 | "path": "../ingester"
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/packages/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | testEnvironment: "node",
3 | globals: {
4 | Uint8Array: Uint8Array, // use Node's implementation; https://github.com/facebook/jest/issues/4422
5 | },
6 | testMatch: ["**/?(*.)+(spec|test).ts?(x)"],
7 | testPathIgnorePatterns: ["dist", "node_modules"],
8 | transformIgnorePatterns: [],
9 | transform: {
10 | "\\.[jt]s$": ["babel-jest", { cwd: __dirname }],
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/packages/sample-data/Readme.md:
--------------------------------------------------------------------------------
1 | # @withorbit/sample-data
2 |
3 | Sample data, mostly meant for use by test harnesses.
4 |
5 | ```
6 | Copyright 2020 Andy Matuschak
7 | SPDX-License-Identifier: Apache-2.0
8 | ```
9 |
--------------------------------------------------------------------------------
/packages/sample-data/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@withorbit/sample-data",
3 | "version": "0.0.1",
4 | "private": true,
5 | "license": "Apache-2.0",
6 | "type": "module",
7 | "main": "./dist/index.js",
8 | "types": "./dist/index.d.ts",
9 | "exports": "./dist/index.js",
10 | "files": [
11 | "dist"
12 | ],
13 | "dependencies": {
14 | "@withorbit/core": "0.0.1"
15 | },
16 | "devDependencies": {
17 | "typescript": "^5.3.3"
18 | },
19 | "scripts": {
20 | "build": "tsc -b"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/packages/sample-data/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./testQASpec.js";
2 | export * from "./testTasks.js";
3 | export * from "./testClozeSpec.js";
4 |
--------------------------------------------------------------------------------
/packages/sample-data/src/testClozeSpec.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ClozeTaskContent,
3 | MemoryTaskSpec,
4 | TaskContentType,
5 | TaskSpecType,
6 | } from "@withorbit/core";
7 |
8 | export const testClozeSpec: MemoryTaskSpec = {
9 | type: TaskSpecType.Memory,
10 | content: {
11 | type: TaskContentType.Cloze,
12 | body: {
13 | text: "This is a test cloze prompt.",
14 | attachments: [],
15 | },
16 | components: {
17 | a: {
18 | order: 0,
19 | ranges: [
20 | {
21 | startIndex: 5,
22 | length: 5,
23 | hint: null,
24 | },
25 | ],
26 | },
27 | b: {
28 | order: 1,
29 | ranges: [
30 | {
31 | startIndex: 2,
32 | length: 2,
33 | hint: null,
34 | },
35 | ],
36 | },
37 | },
38 | },
39 | };
40 |
--------------------------------------------------------------------------------
/packages/sample-data/src/testQASpec.ts:
--------------------------------------------------------------------------------
1 | import {
2 | MemoryTaskSpec,
3 | QATaskContent,
4 | TaskContentType,
5 | TaskSpecType,
6 | } from "@withorbit/core";
7 |
8 | export const testQASpec: MemoryTaskSpec = {
9 | type: TaskSpecType.Memory,
10 | content: {
11 | type: TaskContentType.QA,
12 | body: {
13 | text: "Is it possible to use _quantum teleportation_ to transmit information faster than light?\n\nThis is a **second paragraph** with _**bold italic**_.",
14 | attachments: [],
15 | },
16 | answer: {
17 | text: "No.",
18 | attachments: [],
19 | },
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/packages/sample-data/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "rootDir": "./src"
6 | },
7 | "include": ["./src/**/*.ts"],
8 | "references": [
9 | {
10 | "path": "../core"
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/store-fs/Readme.md:
--------------------------------------------------------------------------------
1 | # `@withorbit/store-fs`
2 |
3 | `OrbitStoreFS` implements an on-disk `OrbitStore` in a standard format: a folder containing a SQLite database (for all events and entities) and a folder of attachments. This folder can be backed up and manipulated locally.
4 |
5 | This library is compatible with Node.js and React Native environments.
6 |
7 | ```
8 | Copyright 2021 Andy Matuschak
9 | SPDX-License-Identifier: Apache-2.0
10 | ```
11 |
--------------------------------------------------------------------------------
/packages/store-fs/babel.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | [
4 | "@babel/preset-env",
5 | {
6 | targets: {
7 | node: "current",
8 | },
9 | },
10 | ],
11 | "@babel/preset-typescript",
12 | ],
13 | plugins: [
14 | [
15 | "@babel/plugin-syntax-import-attributes",
16 | // TODO remove when we move to Node 22 and update import assert to import with
17 | { deprecatedAssertSyntax: true },
18 | ],
19 | ],
20 | };
21 |
--------------------------------------------------------------------------------
/packages/store-fs/jest.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleNameMapper: {
3 | "^(\\.{1,2}/.*)\\.js$": "$1",
4 | },
5 | testEnvironment: "node",
6 | testMatch: ["**/?(*.)+(spec|test).ts?(x)"],
7 | testPathIgnorePatterns: ["dist", "node_modules"],
8 | };
9 |
--------------------------------------------------------------------------------
/packages/store-fs/src/database.test.ts:
--------------------------------------------------------------------------------
1 | import { Database, runDatabaseTests } from "@withorbit/store-shared";
2 | import { SQLDatabaseBackend } from "./sqlite.js";
3 |
4 | describe("database tests", () => {
5 | runDatabaseTests("SQLite", async (eventReducer, eventValidator) => {
6 | return new Database(
7 | new SQLDatabaseBackend(SQLDatabaseBackend.inMemoryDBSubpath),
8 | eventReducer,
9 | eventValidator,
10 | );
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/packages/store-fs/src/index.ts:
--------------------------------------------------------------------------------
1 | export { OrbitStoreFS as default } from "./orbitStoreFS.js";
2 | export { OrbitStoreInMemory } from "./orbitStoreInMemory.js";
3 |
--------------------------------------------------------------------------------
/packages/store-fs/src/orbitStoreInMemory.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AttachmentStore,
3 | Database,
4 | EventReducer,
5 | OrbitStore,
6 | } from "@withorbit/store-shared";
7 | import { AttachmentStoreFS } from "./attachmentStoreFS.js";
8 | import { SQLDatabaseBackend } from "./sqlite.js";
9 |
10 | // An in-memory implementation of OrbitStore, compatible with Node.js and React Native.
11 | export class OrbitStoreInMemory implements OrbitStore {
12 | database: Database;
13 | attachmentStore: AttachmentStore;
14 |
15 | constructor(eventReducer?: EventReducer) {
16 | const sqlDatabaseBackend = new SQLDatabaseBackend(
17 | SQLDatabaseBackend.inMemoryDBSubpath,
18 | { enableDebugLogs: false },
19 | );
20 | this.database = new Database(sqlDatabaseBackend, eventReducer);
21 |
22 | this.attachmentStore = new AttachmentStoreFS(sqlDatabaseBackend);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/store-fs/src/sqlite/migrations/20210612111147_createMetadataTable.ts:
--------------------------------------------------------------------------------
1 | import { SQLMigration } from "./migrationType.js";
2 |
3 | const migration: SQLMigration = {
4 | version: 20210612111147,
5 | statements: [`CREATE TABLE metadata (key TEXT PRIMARY KEY, value TEXT)`],
6 | };
7 | export default migration;
8 |
--------------------------------------------------------------------------------
/packages/store-fs/src/sqlite/migrations/20211019170802_createAttachmentsTable.ts:
--------------------------------------------------------------------------------
1 | import { SQLMigration } from "./migrationType.js";
2 |
3 | const migration: SQLMigration = {
4 | version: 20211019170802,
5 | statements: [
6 | `
7 | CREATE TABLE attachments (
8 | id TEXT PRIMARY KEY,
9 | data BLOB NOT NULL,
10 | mimeType TEXT NOT NULL
11 | )
12 | `,
13 | ],
14 | };
15 | export default migration;
16 |
--------------------------------------------------------------------------------
/packages/store-fs/src/sqlite/migrations/index.ts:
--------------------------------------------------------------------------------
1 | import migration_20210612111147_createMetadataTable from "./20210612111147_createMetadataTable.js";
2 | import migration_20210612112129_initialSchema from "./20210612112129_initialSchema.js";
3 | import migration_20211019170802_createAttachmentsTable from "./20211019170802_createAttachmentsTable.js";
4 | import migration_20230726103155_derived_taskComponents_whenNotDeleted from "./20230726103155_derived_taskComponents_whenNotDeleted.js";
5 |
6 | // Should be sorted by version number.
7 | export const migrations = [
8 | migration_20210612111147_createMetadataTable,
9 | migration_20210612112129_initialSchema,
10 | migration_20211019170802_createAttachmentsTable,
11 | migration_20230726103155_derived_taskComponents_whenNotDeleted,
12 | ];
13 | export const latestSchemaVersionNumber =
14 | migrations[migrations.length - 1].version;
15 |
--------------------------------------------------------------------------------
/packages/store-fs/src/sqlite/migrations/migrationType.ts:
--------------------------------------------------------------------------------
1 | export interface SQLMigration {
2 | version: number;
3 | statements: string[];
4 | }
5 |
--------------------------------------------------------------------------------
/packages/store-fs/src/sqlite/tables.ts:
--------------------------------------------------------------------------------
1 | export enum SQLTableName {
2 | Metadata = "metadata",
3 | Events = "events",
4 | Entities = "entities",
5 | Attachments = "attachments",
6 | }
7 |
8 | export enum SQLMetadataTableKey {
9 | Version = "__db_version",
10 | }
11 |
12 | export enum SQLEventTableColumn {
13 | SequenceNumber = "sequenceNumber",
14 | ID = "id",
15 | EntityID = "entityID",
16 | Data = "data",
17 | }
18 |
19 | export enum SQLEntityTableColumn {
20 | ID = "id",
21 | EntityType = "entityType",
22 | LastEventID = "lastEventID",
23 | LastEventTimestampMillis = "lastEventTimestampMillis",
24 | Data = "data",
25 | RowID = "rowID",
26 | }
27 |
28 | export enum SQLAttachmentTableColumn {
29 | ID = "id",
30 | Data = "data",
31 | MimeType = "mimeType",
32 | }
33 |
--------------------------------------------------------------------------------
/packages/store-fs/src/util/getPathForAttachment.ts:
--------------------------------------------------------------------------------
1 | import path from "path";
2 | import {
3 | AttachmentID,
4 | AttachmentMIMEType,
5 | getFileExtensionForAttachmentMIMEType,
6 | } from "@withorbit/core";
7 |
8 | export function getPathForAttachment(
9 | basePath: string,
10 | id: AttachmentID,
11 | type: AttachmentMIMEType,
12 | ) {
13 | return path.join(
14 | basePath,
15 | `${id}.${getFileExtensionForAttachmentMIMEType(type)}`,
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/packages/store-fs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "rootDir": "./src",
6 | "types": ["jest", "node"]
7 | },
8 | "include": ["./src/**/*.ts", "./@types/**/*.d.ts"],
9 | "references": [
10 | {
11 | "path": "../core"
12 | },
13 | {
14 | "path": "../sample-data"
15 | },
16 | {
17 | "path": "../store-shared"
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/packages/store-shared/Readme.md:
--------------------------------------------------------------------------------
1 | # `@withorbit/store-shared`
2 |
3 | `OrbitStore` implements a standard interface for interacting with a database of Orbit user data and an associated blob store for attachments. This package contains types shared by the two main implementations, `@withorbit/store-fs` (for Node.JS and React Native) and `@withorbit/store-web` (for web browsers).
4 |
5 | This library is compatible with Node.js, React Native, and web browser contexts.
6 |
7 | ```
8 | Copyright 2021 Andy Matuschak
9 | SPDX-License-Identifier: Apache-2.0
10 | ```
11 |
--------------------------------------------------------------------------------
/packages/store-shared/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@withorbit/store-shared",
3 | "version": "0.0.1",
4 | "license": "Apache-2.0",
5 | "private": true,
6 | "type": "module",
7 | "main": "./dist/index.js",
8 | "types": "./dist/index.d.ts",
9 | "exports": "./dist/index.js",
10 | "files": [
11 | "dist"
12 | ],
13 | "sideEffects": false,
14 | "scripts": {
15 | "build": "tsc -b",
16 | "generateSchema": "typescript-json-schema src/validation/eventsValidator.ts Events -o src/validation/events.json --noExtraProps --required --ignoreErrors --strictNullChecks"
17 | },
18 | "dependencies": {
19 | "@withorbit/core": "0.0.1",
20 | "ajv": "^8.6.2"
21 | },
22 | "devDependencies": {
23 | "@types/jest": "^29.5.5",
24 | "@withorbit/sample-data": "0.0.1",
25 | "typescript": "^5.3.3",
26 | "typescript-json-schema": "^0.50.1"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/packages/store-shared/src/attachmentStore.ts:
--------------------------------------------------------------------------------
1 | import { AttachmentID, AttachmentMIMEType } from "@withorbit/core";
2 |
3 | export interface AttachmentStore {
4 | storeAttachment(
5 | contents: Uint8Array,
6 | id: AttachmentID,
7 | type: AttachmentMIMEType,
8 | ): Promise;
9 |
10 | // If the attachment has already been stored, resolves to its local URL; otherwise resolves to null.
11 | getURLForStoredAttachment(id: AttachmentID): Promise;
12 |
13 | // Rejects if the attachment is not stored.
14 | getAttachment(
15 | id: AttachmentID,
16 | ): Promise<{ contents: Uint8Array; type: AttachmentMIMEType }>;
17 | }
18 |
--------------------------------------------------------------------------------
/packages/store-shared/src/encodeDataURL.ts:
--------------------------------------------------------------------------------
1 | import { AttachmentMIMEType } from "@withorbit/core";
2 | import base64 from "base64-js";
3 |
4 | export function encodeDataURL(data: ArrayBuffer, type: AttachmentMIMEType) {
5 | const b64String = base64.fromByteArray(new Uint8Array(data));
6 | return `data:${type};base64,${b64String}`;
7 | }
8 |
--------------------------------------------------------------------------------
/packages/store-shared/src/index.ts:
--------------------------------------------------------------------------------
1 | export type { AttachmentStore } from "./attachmentStore.js";
2 |
3 | export { Database } from "./database.js";
4 | export type { EventReducer } from "./database.js";
5 |
6 | export type {
7 | DatabaseBackend,
8 | DatabaseBackendEntityRecord,
9 | } from "./databaseBackend.js";
10 |
11 | export type {
12 | DatabaseEntityQuery,
13 | DatabaseEventQuery,
14 | DatabaseQueryOptions,
15 | DatabaseQueryPredicate,
16 | DatabaseQueryPredicateRelation,
17 | DatabaseTaskQueryPredicate,
18 | } from "./databaseQuery.js";
19 |
20 | export { encodeDataURL } from "./encodeDataURL.js";
21 |
22 | export type { OrbitStore } from "./orbitStore.js";
23 |
24 | export { runDatabaseTests } from "./databaseTests.js";
25 |
--------------------------------------------------------------------------------
/packages/store-shared/src/orbitStore.ts:
--------------------------------------------------------------------------------
1 | import { AttachmentStore } from "./attachmentStore.js";
2 | import { Database } from "./database.js";
3 |
4 | export interface OrbitStore {
5 | database: Database;
6 | attachmentStore: AttachmentStore;
7 | }
8 |
--------------------------------------------------------------------------------
/packages/store-shared/src/validation/eventsValidator.ts:
--------------------------------------------------------------------------------
1 | import { Event } from "@withorbit/core";
2 |
3 | type Events = Event[];
4 |
5 | export type EventsValidatorError = {
6 | errors: { message: string }[];
7 | };
8 |
9 | export interface EventsValidator {
10 | validateEvents(events: Events): EventsValidatorError | true;
11 | }
12 |
--------------------------------------------------------------------------------
/packages/store-shared/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "rootDir": "./src",
6 | "types": ["jest"]
7 | },
8 | "include": ["./src/**/*.ts", "./@types/**/*.d.ts", "./src/**/*.json"],
9 | "references": [
10 | {
11 | "path": "../core"
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/packages/store-web/Readme.md:
--------------------------------------------------------------------------------
1 | # `@withorbit/store-web`
2 |
3 | Implementation of `OrbitStore` for web browser contexts. See `@withorbit/store-shared` for type definitions.
4 |
5 | ```
6 | Copyright 2021 Andy Matuschak
7 | SPDX-License-Identifier: Apache-2.0
8 | ```
9 |
--------------------------------------------------------------------------------
/packages/store-web/babel.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | [
4 | "@babel/preset-env",
5 | {
6 | targets: {
7 | node: "current",
8 | },
9 | },
10 | ],
11 | "@babel/preset-typescript",
12 | ],
13 | plugins: [
14 | [
15 | "@babel/plugin-syntax-import-attributes",
16 | // TODO remove when we move to Node 22 and update import assert to import with
17 | { deprecatedAssertSyntax: true },
18 | ],
19 | ],
20 | };
21 |
--------------------------------------------------------------------------------
/packages/store-web/jest.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleNameMapper: {
3 | "^(\\.{1,2}/.*)\\.js$": "$1",
4 | },
5 | testEnvironment: "node",
6 | testMatch: ["**/?(*.)+(spec|test).ts?(x)"],
7 | testPathIgnorePatterns: ["dist", "node_modules"],
8 | setupFiles: [
9 | "fake-indexeddb/auto",
10 | ],
11 | };
12 |
--------------------------------------------------------------------------------
/packages/store-web/src/database.test.ts:
--------------------------------------------------------------------------------
1 | // @ts-ignore Looks like there is no @types for this library
2 | import FDBFactory from "fake-indexeddb/lib/FDBFactory";
3 | import { Database, runDatabaseTests } from "@withorbit/store-shared";
4 | import { IDBDatabaseBackend } from "./indexedDB.js";
5 |
6 | describe("database tests", () => {
7 | runDatabaseTests(
8 | "IndexedDB",
9 | async (eventReducer, eventValidator) =>
10 | new Database(
11 | new IDBDatabaseBackend("TestDB", new FDBFactory()),
12 | eventReducer,
13 | eventValidator,
14 | ),
15 | );
16 | });
17 |
--------------------------------------------------------------------------------
/packages/store-web/src/index.ts:
--------------------------------------------------------------------------------
1 | export { OrbitStoreWeb as default } from "./orbitStoreWeb.js";
2 |
--------------------------------------------------------------------------------
/packages/store-web/src/orbitStoreWeb.ts:
--------------------------------------------------------------------------------
1 | import { Database, EventReducer, OrbitStore } from "@withorbit/store-shared";
2 | import { AttachmentStoreWeb } from "./attachmentStoreWeb.js";
3 | import { IDBDatabaseBackend } from "./indexedDB.js";
4 |
5 | export class OrbitStoreWeb implements OrbitStore {
6 | database: Database;
7 | attachmentStore: AttachmentStoreWeb;
8 |
9 | constructor({
10 | databaseName,
11 | indexedDB,
12 | eventReducer,
13 | }: {
14 | databaseName?: string;
15 | indexedDB?: IDBFactory;
16 | eventReducer?: EventReducer;
17 | }) {
18 | this.database = new Database(
19 | new IDBDatabaseBackend(databaseName, indexedDB),
20 | eventReducer,
21 | );
22 | this.attachmentStore = new AttachmentStoreWeb(
23 | `${databaseName}-attachments`,
24 | indexedDB,
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/packages/store-web/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "rootDir": "./src",
6 | "lib": ["dom", "es2020"],
7 | "types": ["jest"]
8 | },
9 | "include": ["./src/**/*.ts", "./@types/**/*.d.ts"],
10 | "references": [
11 | {
12 | "path": "../core"
13 | },
14 | {
15 | "path": "../sample-data"
16 | },
17 | {
18 | "path": "../store-shared"
19 | }
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/packages/sync/babel.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | [
4 | "@babel/preset-env",
5 | {
6 | targets: {
7 | node: "current",
8 | },
9 | },
10 | ],
11 | "@babel/preset-typescript",
12 | ],
13 | };
14 |
--------------------------------------------------------------------------------
/packages/sync/jest.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleNameMapper: {
3 | "^(\\.{1,2}/.*)\\.js$": "$1",
4 | },
5 | testEnvironment: "node",
6 | testMatch: ["**/?(*.)+(spec|test).ts?(x)"],
7 | testPathIgnorePatterns: ["dist", "node_modules"],
8 | };
9 |
--------------------------------------------------------------------------------
/packages/sync/src/index.ts:
--------------------------------------------------------------------------------
1 | export { syncOrbitStore } from "./sync.js";
2 | export { APISyncAdapter } from "./APISyncAdapter.js";
3 | export type { SyncAdapter } from "./syncAdapter.js";
4 |
--------------------------------------------------------------------------------
/packages/sync/src/syncAdapter.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AttachmentID,
3 | AttachmentMIMEType,
4 | Event,
5 | EventID,
6 | } from "@withorbit/core";
7 |
8 | export interface SyncAdapter {
9 | // This ID is used to track state associated with the remote destination associated with this interface (e.g. the last event ID sent/received to/from this destination).
10 | // Different destinations (e.g. test servers, production server, local host) should have different IDs.
11 | id: string;
12 |
13 | listEvents(afterEventID: EventID | null, limit: number): Promise;
14 |
15 | putEvents(events: Event[]): Promise;
16 |
17 | putAttachment(
18 | contents: Uint8Array,
19 | id: AttachmentID,
20 | type: AttachmentMIMEType,
21 | ): Promise;
22 |
23 | getAttachmentContents(id: AttachmentID): Promise;
24 | }
25 |
--------------------------------------------------------------------------------
/packages/sync/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "rootDir": "./src",
6 | "types": ["jest", "node"]
7 | },
8 | "include": [
9 | "./src/**/*.ts",
10 | "./@types/**/*.d.ts",
11 | ],
12 | "references": [
13 | {
14 | "path": "../core"
15 | },
16 | {
17 | "path": "../sample-data"
18 | },
19 | {
20 | "path": "../store-fs"
21 | },
22 | {
23 | "path": "../store-shared"
24 | }
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/packages/tsconfig.base.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": true,
4 | "allowSyntheticDefaultImports": true,
5 | "composite": true,
6 | "declaration": true,
7 | "declarationMap": true,
8 | "esModuleInterop": true,
9 | "forceConsistentCasingInFileNames": true,
10 | "isolatedModules": true,
11 | "lib": ["es2023"],
12 | "module": "nodenext",
13 | "moduleResolution": "nodenext",
14 | "resolveJsonModule": true,
15 | "skipLibCheck": true,
16 | "sourceMap": true,
17 | "strict": true,
18 | "target": "ES2022",
19 | "types": []
20 | },
21 | "compileOnSave": true
22 | }
23 |
--------------------------------------------------------------------------------
/packages/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "references": [
3 | { "path": "./anki-import" },
4 | { "path": "./api" },
5 | { "path": "./api-client" },
6 | { "path": "./app" },
7 | { "path": "./backend" },
8 | { "path": "./core" },
9 | { "path": "./embedded-support" },
10 | { "path": "./ingester" },
11 | { "path": "./interpreter" },
12 | { "path": "./ui" },
13 | { "path": "./sample-data" },
14 | { "path": "./store-fs" },
15 | { "path": "./store-shared" },
16 | { "path": "./store-web" },
17 | { "path": "./web-component" }
18 | ],
19 | "files": []
20 | }
21 |
--------------------------------------------------------------------------------
/packages/ui/.gitignore:
--------------------------------------------------------------------------------
1 | storybook-static
2 |
--------------------------------------------------------------------------------
/packages/ui/.storybook/preview.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parameters: {
3 | layout: "fullscreen",
4 | },
5 | };
6 |
--------------------------------------------------------------------------------
/packages/ui/Readme.md:
--------------------------------------------------------------------------------
1 | # @withorbit/ui
2 |
3 | Defines base UI components and styles. Should probably be rolled into `@withorbit/app`.
4 |
5 | ```
6 | Copyright 2020 Andy Matuschak
7 | SPDX-License-Identifier: Apache-2.0
8 | ```
9 |
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/.gitignore:
--------------------------------------------------------------------------------
1 | # These fonts' licenses do not permit them to be included in distributable Git repos.
2 | dr*
3 | raptor*
4 |
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_AMS-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_AMS-Regular.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_AMS-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_AMS-Regular.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_AMS-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_AMS-Regular.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Caligraphic-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Caligraphic-Bold.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Caligraphic-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Caligraphic-Bold.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Caligraphic-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Caligraphic-Bold.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Caligraphic-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Caligraphic-Regular.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Caligraphic-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Caligraphic-Regular.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Caligraphic-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Caligraphic-Regular.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Fraktur-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Fraktur-Bold.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Fraktur-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Fraktur-Bold.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Fraktur-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Fraktur-Bold.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Fraktur-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Fraktur-Regular.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Fraktur-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Fraktur-Regular.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Fraktur-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Fraktur-Regular.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Main-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Main-Bold.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Main-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Main-Bold.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Main-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Main-Bold.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Main-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Main-BoldItalic.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Main-BoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Main-BoldItalic.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Main-BoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Main-BoldItalic.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Main-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Main-Italic.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Main-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Main-Italic.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Main-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Main-Italic.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Main-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Main-Regular.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Main-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Main-Regular.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Main-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Main-Regular.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Math-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Math-BoldItalic.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Math-BoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Math-BoldItalic.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Math-BoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Math-BoldItalic.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Math-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Math-Italic.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Math-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Math-Italic.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Math-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Math-Italic.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_SansSerif-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_SansSerif-Bold.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_SansSerif-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_SansSerif-Bold.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_SansSerif-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_SansSerif-Bold.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_SansSerif-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_SansSerif-Italic.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_SansSerif-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_SansSerif-Italic.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_SansSerif-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_SansSerif-Italic.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_SansSerif-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_SansSerif-Regular.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_SansSerif-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_SansSerif-Regular.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_SansSerif-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_SansSerif-Regular.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Script-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Script-Regular.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Script-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Script-Regular.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Script-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Script-Regular.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Size1-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Size1-Regular.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Size1-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Size1-Regular.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Size1-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Size1-Regular.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Size2-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Size2-Regular.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Size2-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Size2-Regular.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Size2-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Size2-Regular.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Size3-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Size3-Regular.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Size3-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Size3-Regular.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Size3-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Size3-Regular.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Size4-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Size4-Regular.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Size4-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Size4-Regular.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Size4-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Size4-Regular.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Typewriter-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Typewriter-Regular.ttf
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Typewriter-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Typewriter-Regular.woff
--------------------------------------------------------------------------------
/packages/ui/assets/fonts/KaTeX_Typewriter-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/fonts/KaTeX_Typewriter-Regular.woff2
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-BL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/check-BL.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-BL.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-BL@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/check-BL@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-BL@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/check-BL@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-BR.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/check-BR.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-BR.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-BR@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/check-BR@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-BR@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/check-BR@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-TL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/check-TL.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-TL.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-TL@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/check-TL@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-TL@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/check-TL@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-TR.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/check-TR.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-TR.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-TR@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/check-TR@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-TR@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/check-TR@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/check-center.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-center.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-center@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/check-center@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/check-center@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/check-center@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/cross-BL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/cross-BL.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/cross-BL@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/cross-BL@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/cross-BL@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/cross-BL@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/cross-BR.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/cross-BR.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/cross-BR@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/cross-BR@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/cross-BR@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/cross-BR@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/cross-TL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/cross-TL.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/cross-TL@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/cross-TL@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/cross-TL@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/cross-TL@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/cross-TR.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/cross-TR.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/cross-TR@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/cross-TR@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/cross-TR@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/cross-TR@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/cross-center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/cross-center.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/cross-center@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/cross-center@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/cross-center@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/cross-center@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/dots-center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/dots-center.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/dots-center.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/dots-center@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/dots-center@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/dots-center@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/dots-center@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/doubleRight-TL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/doubleRight-TL.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/doubleRight-TL.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/doubleRight-TL@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/doubleRight-TL@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/doubleRight-TL@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/doubleRight-TL@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/doubleRight-center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/doubleRight-center.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/doubleRight-center.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/doubleRight-center@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/doubleRight-center@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/doubleRight-center@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/doubleRight-center@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/left-center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/left-center.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/left-center.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/left-center@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/left-center@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/left-center@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/left-center@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/list-center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/list-center.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/list-center.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/list-center@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/list-center@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/list-center@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/list-center@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-accent-bottom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-accent-bottom.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-accent-bottom.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-accent-bottom@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-accent-bottom@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-accent-bottom@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-accent-bottom@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-accent-center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-accent-center.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-accent-center.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-accent-center@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-accent-center@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-accent-center@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-accent-center@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-accent-top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-accent-top.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-accent-top.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-accent-top@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-accent-top@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-accent-top@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-accent-top@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-bottom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-bottom.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-bottom.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-bottom@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-bottom@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-bottom@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-bottom@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-center.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-center.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-center@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-center@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-center@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-center@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-top.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-top.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-top@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-top@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/reveal-top@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/reveal-top@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-BL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/right-BL.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-BL.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-BL@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/right-BL@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-BL@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/right-BL@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-BR.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/right-BR.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-BR.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-BR@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/right-BR@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-BR@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/right-BR@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-TL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/right-TL.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-TL.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-TL@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/right-TL@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-TL@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/right-TL@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-TR.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/right-TR.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-TR.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-TR@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/right-TR@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-TR@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/right-TR@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/right-center.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-center.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-center@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/right-center@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/icons/right-center@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/icons/right-center@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/logo/16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/logo/16.png
--------------------------------------------------------------------------------
/packages/ui/assets/logo/16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/logo/16@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/logo/16@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/logo/16@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/logo/24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/logo/24.png
--------------------------------------------------------------------------------
/packages/ui/assets/logo/24@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/logo/24@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/logo/24@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/logo/24@3x.png
--------------------------------------------------------------------------------
/packages/ui/assets/logo/32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/logo/32.png
--------------------------------------------------------------------------------
/packages/ui/assets/logo/32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/logo/32@2x.png
--------------------------------------------------------------------------------
/packages/ui/assets/logo/32@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andymatuschak/orbit/ed5a530750b6e96e86ea725ef3990c9209fc0028/packages/ui/assets/logo/32@3x.png
--------------------------------------------------------------------------------
/packages/ui/babel.config.cjs:
--------------------------------------------------------------------------------
1 | // Used just for Storybook.
2 | module.exports = {
3 | sourceType: "unambiguous",
4 | presets: [
5 | [
6 | "@babel/preset-env",
7 | {
8 | targets: {
9 | chrome: 100,
10 | safari: 15,
11 | firefox: 91,
12 | },
13 | },
14 | ],
15 | "@babel/preset-typescript",
16 | "@babel/preset-react",
17 | ],
18 | plugins: [],
19 | };
20 |
--------------------------------------------------------------------------------
/packages/ui/src/@types/markdown-it-texmath/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module "markdown-it-texmath" {
2 | import MarkdownIt from "markdown-it";
3 | import katex from "katex";
4 | export function use(
5 | katexInstance: typeof katex,
6 | ): (md: MarkdownIt, ...params: unknown[]) => void;
7 | }
8 |
--------------------------------------------------------------------------------
/packages/ui/src/components/DebugGrid.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View } from "react-native";
3 | import DebugGrid from "./DebugGrid.js";
4 |
5 | export default {
6 | title: "Style/Grid",
7 | };
8 |
9 | export function Grid() {
10 | return (
11 |
22 |
23 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/packages/ui/src/components/FadeView.stories.tsx:
--------------------------------------------------------------------------------
1 | import { action } from "@storybook/addon-actions";
2 |
3 | import React, { useState } from "react";
4 | import FadeView from "./FadeView.jsx";
5 | import { Button, View } from "react-native";
6 |
7 | export default {
8 | title: "FadeView",
9 | component: FadeView,
10 | };
11 |
12 | export function Basic() {
13 | const initialValue = true;
14 | const [isVisible, setVisible] = useState(initialValue);
15 | return (
16 |
17 |
23 |
24 |
25 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/packages/ui/src/components/IconShared.ts:
--------------------------------------------------------------------------------
1 | import { ImageStyle, StyleProp } from "react-native";
2 |
3 | export enum IconName {
4 | Check = "check",
5 | Cross = "cross",
6 | Reveal = "reveal",
7 | ArrowLeft = "left",
8 | ArrowRight = "right",
9 | DoubleArrowRight = "doubleArrowRight",
10 | List = "list",
11 | Menu = "menu",
12 | }
13 |
14 | export enum IconPosition {
15 | TopLeft = "TL",
16 | TopRight = "TR",
17 | BottomLeft = "BL",
18 | BottomRight = "BR",
19 | Center = "Center",
20 | }
21 |
22 | export interface IconProps {
23 | name: IconName;
24 | position: IconPosition;
25 | tintColor: string;
26 | style?: StyleProp;
27 | accentColor?: string;
28 | }
29 |
30 | export const iconSize = 24;
31 |
--------------------------------------------------------------------------------
/packages/ui/src/components/Logo.stories.tsx:
--------------------------------------------------------------------------------
1 | import { Meta, StoryObj } from "@storybook/react";
2 | import { colors } from "../styles/index.js";
3 | import Logo from "./Logo.jsx";
4 |
5 | const meta = {
6 | title: "Logo",
7 | component: Logo,
8 | args: {
9 | tintColor: colors.productKeyColor,
10 | },
11 | } satisfies Meta;
12 | export default meta;
13 |
14 | type Story = StoryObj;
15 | export const Basic = {
16 | args: { units: 2 },
17 | } satisfies Story;
18 |
--------------------------------------------------------------------------------
/packages/ui/src/components/Logo.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Image } from "react-native";
3 | import unreachableCaseError from "../util/unreachableCaseError.js";
4 | import { getLogoSize, LogoProps } from "./LogoShared.js";
5 |
6 | function getLogoAsset(units: LogoProps["units"]): number {
7 | switch (units) {
8 | case 2:
9 | return require("../../assets/logo/16.png");
10 | case 3:
11 | return require("../../assets/logo/24.png");
12 | case 4:
13 | return require("../../assets/logo/32.png");
14 | default:
15 | throw unreachableCaseError(units);
16 | }
17 | }
18 |
19 | export default React.memo(function Logo(props: LogoProps) {
20 | const { width, height } = getLogoSize(props.units);
21 | return (
22 |
26 | );
27 | });
28 |
--------------------------------------------------------------------------------
/packages/ui/src/components/LogoShared.ts:
--------------------------------------------------------------------------------
1 | import unreachableCaseError from "../util/unreachableCaseError.js";
2 |
3 | export interface LogoProps {
4 | // This prop specifies the rough size of the logo itself. The logo is set inside an 8px (1 grid unit) bounding box on all sides, since some of the curved elements don't fit in the core size. So a size of 16 will give you an element that is actually 32px high.
5 | units: 2 | 3 | 4;
6 | tintColor: string;
7 | }
8 |
9 | export function getLogoSize(units: LogoProps["units"]): {
10 | width: number;
11 | height: number;
12 | } {
13 | switch (units) {
14 | case 2:
15 | return { width: 59, height: 32 };
16 | case 3:
17 | return { width: 80, height: 40 };
18 | case 4:
19 | return { width: 102, height: 48 };
20 | default:
21 | throw unreachableCaseError(units);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/packages/ui/src/components/PromptFieldRenderer/markdown.ts:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import * as MarkdownDisplay from "react-native-markdown-display";
3 | import { clozeHighlightPlugin } from "./clozeHighlightPlugin.js";
4 | import { addLatexSupport } from "./markdownLatexSupport.js";
5 |
6 | export function useMarkdownItInstance(
7 | withLatexSupport: boolean,
8 | ): MarkdownDisplay.MarkdownIt {
9 | const instance = React.useRef(
10 | MarkdownDisplay.MarkdownIt({
11 | typographer: true,
12 | }).use(clozeHighlightPlugin),
13 | );
14 |
15 | const hasRequestedLatex = React.useRef(false);
16 | const [, setLatexLoaded] = React.useState(false);
17 |
18 | if (withLatexSupport && !hasRequestedLatex.current) {
19 | hasRequestedLatex.current = true;
20 | addLatexSupport(instance.current).then(() => setLatexLoaded(true));
21 | }
22 |
23 | return instance.current;
24 | }
25 |
--------------------------------------------------------------------------------
/packages/ui/src/components/Spacer.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View } from "react-native";
3 | import { gridUnit } from "../styles/layout.js";
4 |
5 | export interface SpacerProps {
6 | units: number;
7 | }
8 |
9 | const Spacer = React.memo(function Spacer(props: SpacerProps) {
10 | const size = props.units * gridUnit;
11 | return ;
12 | });
13 | export default Spacer;
14 |
--------------------------------------------------------------------------------
/packages/ui/src/components/__fixtures__/colorPaletteArgType.ts:
--------------------------------------------------------------------------------
1 | import { InputType } from "@storybook/types";
2 | import { colors } from "../../styles/index.js";
3 |
4 | export const colorPaletteArgType = {
5 | options: colors.orderedPaletteNames,
6 | mapping: Object.fromEntries(
7 | colors.orderedPaletteNames.map((name) => [name, colors.palettes[name]]),
8 | ),
9 | } satisfies InputType;
10 |
--------------------------------------------------------------------------------
/packages/ui/src/components/__fixtures__/generateReviewItem.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ColorPaletteName,
3 | generateUniqueID,
4 | mainTaskComponentID,
5 | } from "@withorbit/core";
6 | import { testQASpec } from "@withorbit/sample-data";
7 | import { ReviewAreaItem } from "../../reviewAreaItem.js";
8 | import * as styles from "../../styles/index.js";
9 |
10 | export function generateReviewItem(
11 | questionText: string,
12 | answerText: string,
13 | contextString: string,
14 | colorPaletteName: ColorPaletteName,
15 | ): ReviewAreaItem {
16 | return {
17 | taskID: generateUniqueID(),
18 | colorPalette: styles.colors.palettes[colorPaletteName],
19 | provenance: {
20 | identifier: "Web",
21 | title: contextString,
22 | url: "http://foo.com",
23 | },
24 | componentID: mainTaskComponentID,
25 | spec: {
26 | ...testQASpec,
27 | },
28 | };
29 | }
30 |
--------------------------------------------------------------------------------
/packages/ui/src/components/hooks/usePrevious.ts:
--------------------------------------------------------------------------------
1 | import { useRef } from "react";
2 |
3 | export default function usePrevious(value: T) {
4 | const ref = useRef();
5 | const { current } = ref;
6 | ref.current = value;
7 | return current;
8 | }
9 |
--------------------------------------------------------------------------------
/packages/ui/src/components/hooks/useWeakRef.ts:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | export default function useWeakRef(value: T): React.MutableRefObject {
4 | const ref = React.useRef(value);
5 | React.useEffect(() => {
6 | ref.current = value;
7 | }, [value]);
8 | return ref;
9 | }
10 |
--------------------------------------------------------------------------------
/packages/ui/src/reviewAreaItem.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ComponentIDsOf,
3 | Task,
4 | TaskContent,
5 | TaskID,
6 | TaskProvenance,
7 | } from "@withorbit/core";
8 | import { colors } from "./styles/index.js";
9 |
10 | export interface ReviewAreaItem {
11 | taskID: TaskID;
12 | spec: Task["spec"];
13 | componentID: ComponentIDsOf;
14 |
15 | provenance: TaskProvenance | null;
16 | colorPalette: colors.ColorPalette;
17 | }
18 |
--------------------------------------------------------------------------------
/packages/ui/src/styles/index.ts:
--------------------------------------------------------------------------------
1 | export * as colors from "./colors.js";
2 | export * as layout from "./layout.js";
3 | export * as type from "./type.js";
4 |
--------------------------------------------------------------------------------
/packages/ui/src/styles/layout.ts:
--------------------------------------------------------------------------------
1 | export const borderRadius = 8;
2 | export const gridUnit = 8;
3 |
4 | export const columnMargin = gridUnit;
5 | export const edgeMargin = gridUnit * 2;
6 |
7 | export const maximumContentWidth = 750;
8 | export const maximumContentHeight = 750;
9 |
10 | export function getColumnSpan(columnCount: number, layoutWidth: number) {
11 | if (columnCount < 1 || columnCount > 2) {
12 | throw new Error(`Can't get column span for column count of ${columnCount}`);
13 | }
14 |
15 | // Assumes a two-column layout
16 | const columnWidth = (layoutWidth - edgeMargin * 2 - columnMargin) / 2.0;
17 | return Math.round(
18 | columnCount * columnWidth + (columnCount - 1) * columnMargin,
19 | );
20 | }
21 |
22 | export type SizeClass = "compact" | "regular";
23 | export function getWidthSizeClass(width: number): SizeClass {
24 | return width > 414 ? "regular" : "compact";
25 | }
26 |
--------------------------------------------------------------------------------
/packages/ui/src/util/Size.ts:
--------------------------------------------------------------------------------
1 | export type Size = { width: number; height: number };
2 |
--------------------------------------------------------------------------------
/packages/ui/src/util/clamp.ts:
--------------------------------------------------------------------------------
1 | export default function clamp(value: number, min: number, max: number): number {
2 | return Math.max(Math.min(value, max), min);
3 | }
4 |
--------------------------------------------------------------------------------
/packages/ui/src/util/lerp.ts:
--------------------------------------------------------------------------------
1 | import clamp from "./clamp.js";
2 |
3 | export default function lerp(
4 | value: number,
5 | fromMin: number,
6 | fromMax: number,
7 | toMin: number,
8 | toMax: number,
9 | ) {
10 | const output =
11 | ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin) + toMin;
12 | return clamp(output, toMin, toMax);
13 | }
14 |
--------------------------------------------------------------------------------
/packages/ui/src/util/unreachableCaseError.ts:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line @typescript-eslint/no-unused-vars
2 | export default function unreachableCaseError(witness: never): Error {
3 | return new Error("unreachable");
4 | }
5 |
--------------------------------------------------------------------------------
/packages/ui/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base",
3 | "compilerOptions": {
4 | "jsx": "react-native",
5 | "outDir": "./dist",
6 | "rootDir": "./src",
7 | "target": "esnext",
8 | "baseUrl": ".",
9 | "paths": {
10 | "react-native-markdown-display": [
11 | "./src/@types/react-native-markdown-display",
12 | "react-native-markdown-display"
13 | ]
14 | },
15 | "lib": ["es2023", "dom"]
16 | },
17 | "include": ["./src/**/*.ts", "./src/**/*.tsx"],
18 | "references": [
19 | {
20 | "path": "../sample-data"
21 | },
22 | {
23 | "path": "../core"
24 | }
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/packages/web-component/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "metabook-system"
4 | },
5 | "targets": {
6 | "metabook-system": {
7 | "hosting": {
8 | "orbit-js": ["orbit-js"]
9 | }
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/web-component/.gitignore:
--------------------------------------------------------------------------------
1 | .firebase
2 | /build/
3 |
--------------------------------------------------------------------------------
/packages/web-component/babel.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | [
4 | "@babel/preset-env",
5 | {
6 | targets: {
7 | node: "current",
8 | },
9 | },
10 | ],
11 | "@babel/preset-typescript",
12 | ],
13 | };
14 |
--------------------------------------------------------------------------------
/packages/web-component/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "hosting": {
3 | "target": "orbit-js",
4 | "public": "build",
5 | "headers": [
6 | {
7 | "source": "*",
8 | "headers": [
9 | {
10 | "key": "Access-Control-Allow-Origin",
11 | "value": "*"
12 | },
13 | {
14 | "key": "Cache-Control",
15 | "value": "public, max-age=300, s-maxage=31536000"
16 | }
17 | ]
18 | }
19 | ]
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/packages/web-component/jest.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleNameMapper: {
3 | "^(\\.{1,2}/.*)\\.js$": "$1",
4 | },
5 | testEnvironment: "jsdom",
6 | testMatch: ["**/?(*.)+(spec|test).ts?(x)"],
7 | testPathIgnorePatterns: ["build", "public", "node_modules"],
8 | transformIgnorePatterns: [],
9 | };
10 |
--------------------------------------------------------------------------------
/packages/web-component/scripts/bundleProd.ts:
--------------------------------------------------------------------------------
1 | import { bundle, makeBundleConfig } from "./bundleShared.js";
2 |
3 | const bundleConfig = makeBundleConfig({ isDevelopment: false });
4 | await bundle(bundleConfig);
5 |
--------------------------------------------------------------------------------
/packages/web-component/scripts/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "noEmit": true,
5 | "types": ["bun-types", "node"]
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/web-component/src/index.ts:
--------------------------------------------------------------------------------
1 | import { OrbitPromptElement } from "./OrbitPromptElement.js";
2 | import { OrbitReviewAreaElement } from "./OrbitReviewAreaElement.js";
3 |
4 | export { OrbitPromptElement };
5 | export { OrbitReviewAreaElement };
6 |
7 | window.customElements.define("orbit-reviewarea", OrbitReviewAreaElement);
8 | window.customElements.define("orbit-prompt", OrbitPromptElement);
9 |
--------------------------------------------------------------------------------
/packages/web-component/test/orbit-web-component.js:
--------------------------------------------------------------------------------
1 | ../build/orbit-web-component-dev.js
--------------------------------------------------------------------------------
/packages/web-component/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.json",
3 | "compilerOptions": {
4 | "lib": ["es2023", "dom"],
5 | "types": ["jest"],
6 | "outDir": "./dist",
7 | "rootDir": "./src"
8 | },
9 | "include": ["./src/**/*.ts"],
10 | "references": [
11 | {
12 | "path": "../core"
13 | },
14 | {
15 | "path": "../embedded-support"
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------