Compare commits

..

16 Commits

Author SHA1 Message Date
Dan Abramov 5ddf2f5b31 Clarify what this is 2024-07-06 13:19:33 +01:00
Dan Abramov 5df7f4b113 Polyfill for native 2024-07-06 07:28:07 +01:00
Dan Abramov d7d2189a42 Add to settings 2024-07-06 06:35:30 +01:00
Dan Abramov 8ad46bfd61 POC 2024-07-06 06:29:37 +01:00
Dan Abramov ec9db8470d Hook up components 2024-07-06 06:18:32 +01:00
Dan Abramov 0c4cae0148 Hello world 2024-07-06 06:10:42 +01:00
Dan Abramov 98dc900cc5 Patch __webpack__ to __bsky__ 2024-07-06 05:47:26 +01:00
Dan Abramov 742cfe6238 Revert "Patch module system"
This reverts commit 5ed88bd43e.
2024-07-06 05:46:25 +01:00
Dan Abramov 5ed88bd43e Patch module system 2024-07-06 05:22:09 +01:00
Dan Abramov d6d50818ee Hook up requests 2024-07-06 05:16:47 +01:00
Dan Abramov 3349174bbd Start moving code around 2024-07-06 04:58:12 +01:00
Dan Abramov e212a3f441 Add server 2024-07-06 04:46:21 +01:00
Paul Frazee 21123dab43 Add ActorLabel 2024-07-06 03:07:04 +01:00
Paul Frazee e1d71bdbd6 Add ATProto Avatar 2024-07-06 03:07:04 +01:00
Paul Frazee 5e14462a23 Add error boundary and ATProto Embed 2024-07-06 03:07:04 +01:00
Paul Frazee 18b7c466cf Appcom: initial commit 2024-07-06 03:07:04 +01:00
555 changed files with 32766 additions and 48436 deletions
-2
View File
@@ -1,2 +0,0 @@
[*.{kt,kts}]
indent_size=2
-13
View File
@@ -71,19 +71,6 @@ module.exports = {
'simple-import-sort/exports': 'warn',
// TODO: Reenable when we figure out why it gets stuck on CI.
// 'react-compiler/react-compiler': 'error',
'no-restricted-imports': [
'error',
{
paths: [
{
name: '@atproto/api',
importNames: ['moderatePost'],
message:
'Please use `moderatePost_wrapped` from `#/lib/moderatePost_wrapped` instead.',
},
],
},
],
},
ignorePatterns: [
'**/__mocks__/*.ts',
+4 -4
View File
@@ -10,7 +10,7 @@ Get the app itself:
## Development Resources
This is a [React Native](https://reactnative.dev/) application, written in the TypeScript programming language. It builds on the `atproto` TypeScript packages (like [`@atproto/api`](https://www.npmjs.com/package/@atproto/api)), code for which is also open source, but in [a different git repository](https://github.com/bluesky-social/atproto).
This is a [React Native](https://reactnative.dev/) application, written in the TypeScript programming language. It builds on the `atproto` TypeScript packages (like [`@atproto/api`](https://www.npmjs.com/package/@atproto/api)), code for which is also on open source, but in [a different git repository](https://github.com/bluesky-social/atproto).
There is a small amount of Go language source code (in `./bskyweb/`), for a web service that returns the React Native Web application.
@@ -42,10 +42,10 @@ The Bluesky Social application encompasses a set of schemas and APIs built in th
- Open an issue and give some time for discussion before submitting a PR.
- Stay away from PRs like...
- Changing "Post" to "Skeet."
- Refactoring the codebase, e.g., to replace MobX with Redux or something.
- Refactoring the codebase, eg to replace mobx with redux or something.
- Adding entirely new features without prior discussion.
Remember, we serve a wide community of users. Our day-to-day involves us constantly asking "which top priority is our top priority." If you submit well-written PRs that solve problems concisely, that's an awesome contribution. Otherwise, as much as we'd love to accept your ideas and contributions, we really don't have the bandwidth. That's what forking is for!
Remember, we serve a wide community of users. Our day to day involves us constantly asking "which top priority is our top priority." If you submit well-written PRs that solve problems concisely, that's an awesome contribution. Otherwise, as much as we'd love to accept your ideas and contributions, we really don't have the bandwidth. That's what forking is for!
## Forking guidelines
@@ -63,7 +63,7 @@ If you discover any security issues, please send an email to security@bsky.app.
## Are you a developer interested in building on atproto?
Bluesky is an open social network built on the AT Protocol, a flexible technology that will never lock developers out of the ecosystems that they help build. With atproto, third-party integration can be as seamless as first-party through custom feeds, federated services, clients, and more.
Bluesky is an open social network built on the AT Protocol, a flexible technology that will never lock developers out of the ecosystems that they help build. With atproto, third-party can be as seamless as first-party through custom feeds, federated services, clients, and more.
## License (MIT)
+2 -3
View File
@@ -132,8 +132,7 @@ appId: xyz.blueskyweb.app
id: "feedItem-by-bob.test"
- tapOn:
id: "e2eGotoFeeds"
- tapOn:
id: "saved-feed-Good Ppl"
- tapOn: "Good Ppl"
- assertVisible:
id: "feedItem-by-bob.test"
- tapOn:
@@ -169,7 +168,7 @@ appId: xyz.blueskyweb.app
id: "profilePager-selector"
direction: LEFT
- tapOn:
id: "profilePager-selector-6"
id: "profilePager-selector-5"
- tapOn: "Good Ppl"
- tapOn:
-31
View File
@@ -1,31 +0,0 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users&posts&feeds"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- tapOn: "/sys/debug"
- tapOn:
id: "sharedPrefsTestOpenBtn"
- tapOn:
id: "setStringBtn"
- assertVisible: "Hello"
- tapOn:
id: "removeStringBtn"
- assertVisible: "null"
- tapOn:
id: "setBoolBtn"
- assertVisible: "true"
- tapOn:
id: "setNumberBtn"
- assertVisible: "123"
- tapOn:
id: "addToSetBtn"
- assertVisible: "true"
- tapOn:
id: "removeFromSetBtn"
- assertVisible: "false"
-8
View File
@@ -340,14 +340,12 @@ describe('parseEmbedPlayerFromUrl', () => {
'https://youtube.com/watch?v=videoId',
'https://youtube.com/watch?v=videoId&feature=share',
'https://youtube.com/shorts/videoId',
'https://youtube.com/live/videoId',
'https://m.youtube.com/watch?v=videoId',
'https://music.youtube.com/watch?v=videoId',
'https://youtube.com/shorts/',
'https://youtube.com/',
'https://youtube.com/random',
'https://youtube.com/live/',
'https://twitch.tv/channelName',
'https://www.twitch.tv/channelName',
@@ -477,16 +475,10 @@ describe('parseEmbedPlayerFromUrl', () => {
source: 'youtube',
playerUri: 'https://bsky.app/iframe/youtube.html?videoId=videoId&start=0',
},
{
type: 'youtube_video',
source: 'youtube',
playerUri: 'https://bsky.app/iframe/youtube.html?videoId=videoId&start=0',
},
undefined,
undefined,
undefined,
undefined,
{
type: 'twitch_video',
+1 -2
View File
@@ -191,7 +191,7 @@ module.exports = function (config) {
'expo-build-properties',
{
ios: {
deploymentTarget: '15.1',
deploymentTarget: '14.0',
newArchEnabled: false,
},
android: {
@@ -221,7 +221,6 @@ module.exports = function (config) {
'./plugins/withAndroidSplashScreenStatusBarTranslucentPlugin.js',
'./plugins/shareExtension/withShareExtensions.js',
'./plugins/notificationsExtension/withNotificationsExtension.js',
'./plugins/withAppDelegateReferrer.js',
].filter(Boolean),
extra: {
eas: {
@@ -1 +0,0 @@
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M20.957 3.043a1 1 0 0 1 0 1.414L16.414 9H20a1 1 0 1 1 0 2h-6a1 1 0 0 1-1-1V4a1 1 0 1 1 2 0v3.586l4.543-4.543a1 1 0 0 1 1.414 0ZM3 14a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 1 1-2 0v-3.586l-4.543 4.543a1 1 0 0 1-1.414-1.414L7.586 15H4a1 1 0 0 1-1-1Z" fill="#000"/></svg>

Before

Width:  |  Height:  |  Size: 391 B

@@ -1 +0,0 @@
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M20.957 3.043a1 1 0 0 1 0 1.414L16.414 9H20a1 1 0 1 1 0 2h-5a2 2 0 0 1-2-2V4a1 1 0 1 1 2 0v3.586l4.543-4.543a1 1 0 0 1 1.414 0ZM3 14a1 1 0 0 1 1-1h5a2 2 0 0 1 2 2v5a1 1 0 1 1-2 0v-3.586l-4.543 4.543a1 1 0 0 1-1.414-1.414L7.586 15H4a1 1 0 0 1-1-1Z" fill="#000"/></svg>

Before

Width:  |  Height:  |  Size: 392 B

@@ -1 +0,0 @@
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M14 5a1 1 0 1 1 0-2h6a1 1 0 0 1 1 1v6a1 1 0 1 1-2 0V6.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L17.586 5H14ZM4 13a1 1 0 0 1 1 1v3.586l4.293-4.293a1 1 0 0 1 1.414 1.414L6.414 19H10a1 1 0 1 1 0 2H4a1 1 0 0 1-1-1v-6a1 1 0 0 1 1-1Z" fill="#000"/></svg>

Before

Width:  |  Height:  |  Size: 369 B

@@ -1 +0,0 @@
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M13 4a1 1 0 0 1 1-1h5a2 2 0 0 1 2 2v5a1 1 0 1 1-2 0V6.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L17.586 5H14a1 1 0 0 1-1-1Zm-9 9a1 1 0 0 1 1 1v3.586l4.293-4.293a1 1 0 0 1 1.414 1.414L6.414 19H10a1 1 0 1 1 0 2H5a2 2 0 0 1-2-2v-5a1 1 0 0 1 1-1Z" fill="#000"/></svg>

Before

Width:  |  Height:  |  Size: 384 B

@@ -1 +0,0 @@
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M3 4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4Zm11.543 7.293a1 1 0 0 1 1.414 0 1 1 0 0 0 1.414-1.414 3 3 0 1 0 0 4.242 1 1 0 0 0-1.414-1.414 1 1 0 0 1-1.414-1.414Zm-6 0a1 1 0 0 1 1.414 0 1 1 0 0 0 1.414-1.414 3 3 0 1 0 0 4.243 1 1 0 0 0-1.414-1.415 1 1 0 0 1-1.414-1.414Z" fill="#000"/></svg>

Before

Width:  |  Height:  |  Size: 440 B

@@ -1 +0,0 @@
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M3 4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4Zm2 1v14h14V5H5Zm10.957 6.293a1 1 0 1 0 0 1.414 1 1 0 0 1 1.414 1.414 3 3 0 1 1 0-4.242 1 1 0 0 1-1.414 1.414Zm-6.331-.22a1 1 0 1 0 .331 1.634 1 1 0 0 1 1.414 1.414 3 3 0 1 1 0-4.242 1 1 0 0 1-1.414 1.414.994.994 0 0 0-.331-.22Z" fill="#000"/></svg>

Before

Width:  |  Height:  |  Size: 443 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M6 2a1 1 0 0 1 1 1v2h11a1 1 0 0 1 1 1v11h2a1 1 0 1 1 0 2h-2v2a1 1 0 1 1-2 0v-2H6a1 1 0 0 1-1-1V7H3a1 1 0 0 1 0-2h2V3a1 1 0 0 1 1-1Zm1 5v10h10V7H7Z" clip-rule="evenodd"/></svg>

Before

Width:  |  Height:  |  Size: 289 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M3.135 12C5.413 16.088 8.77 18 12 18s6.587-1.912 8.865-6C18.587 7.912 15.23 6 12 6c-3.228 0-6.587 1.912-8.865 6ZM12 4c4.24 0 8.339 2.611 10.888 7.54a1 1 0 0 1 0 .92C20.338 17.388 16.24 20 12 20c-4.24 0-8.339-2.611-10.888-7.54a1 1 0 0 1 0-.92C3.662 6.612 7.76 4 12 4Zm0 6a2 2 0 1 0 0 4 2 2 0 0 0 0-4Zm-4 2a4 4 0 1 1 8 0 4 4 0 0 1-8 0Z" clip-rule="evenodd"/></svg>

Before

Width:  |  Height:  |  Size: 476 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M12.097 2.53a1 1 0 0 1-.041 1.07 6 6 0 0 0 8.345 8.344 1 1 0 0 1 1.563.908c-.434 5.122-4.728 9.144-9.962 9.144-5.522 0-9.998-4.476-9.998-9.998 0-5.234 4.021-9.528 9.144-9.962a1 1 0 0 1 .949.494ZM9.424 4.424a7.998 7.998 0 1 0 10.152 10.152A8 8 0 0 1 9.424 4.424Z" clip-rule="evenodd"/></svg>

Before

Width:  |  Height:  |  Size: 403 B

@@ -1 +0,0 @@
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M4 4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V4ZM14 4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1V4Z" fill="#000"/></svg>

Before

Width:  |  Height:  |  Size: 247 B

@@ -1 +0,0 @@
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M4 6a3 3 0 0 1 6 0v12a3 3 0 1 1-6 0V6ZM14 6a3 3 0 1 1 6 0v12a3 3 0 1 1-6 0V6Z" fill="#000"/></svg>

Before

Width:  |  Height:  |  Size: 183 B

@@ -1 +0,0 @@
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M4 4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V4Zm2 1v14h2V5H6Zm8-1a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1V4Zm2 1v14h2V5h-2Z" fill="#000"/></svg>

Before

Width:  |  Height:  |  Size: 315 B

@@ -1 +0,0 @@
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M4 6a3 3 0 0 1 6 0v12a3 3 0 1 1-6 0V6Zm3-1a1 1 0 0 0-1 1v12a1 1 0 1 0 2 0V6a1 1 0 0 0-1-1Zm7 1a3 3 0 1 1 6 0v12a3 3 0 1 1-6 0V6Zm3-1a1 1 0 0 0-1 1v12a1 1 0 1 0 2 0V6a1 1 0 0 0-1-1Z" fill="#000"/></svg>

Before

Width:  |  Height:  |  Size: 326 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M5 4a3 3 0 0 1 3-3h8a3 3 0 0 1 3 3v16a3 3 0 0 1-3 3H8a3 3 0 0 1-3-3V4Zm3-1a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H8Zm2 2a1 1 0 0 1 1-1h2a1 1 0 1 1 0 2h-2a1 1 0 0 1-1-1Z" clip-rule="evenodd"/></svg>

Before

Width:  |  Height:  |  Size: 334 B

@@ -1 +0,0 @@
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M6.514 2.143A1 1 0 0 0 5 3v18a1 1 0 0 0 1.514.858l15-9a1 1 0 0 0 0-1.716l-15-9Z" fill="#000"/></svg>

Before

Width:  |  Height:  |  Size: 184 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" d="M9.576 2.534C7.578 1.299 5 2.737 5 5.086v13.828c0 2.35 2.578 3.787 4.576 2.552l11.194-6.914c1.899-1.172 1.899-3.932 0-5.104L9.576 2.534Z"/></svg>

Before

Width:  |  Height:  |  Size: 239 B

@@ -1 +0,0 @@
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M5.507 2.13a1 1 0 0 1 1.008.013l15 9a1 1 0 0 1 0 1.714l-15 9A1 1 0 0 1 5 21V3a1 1 0 0 1 .507-.87ZM7 4.766v14.468L19.056 12 7 4.766Z" fill="#000"/></svg>

Before

Width:  |  Height:  |  Size: 276 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M5 5.086C5 2.736 7.578 1.3 9.576 2.534L20.77 9.448c1.899 1.172 1.899 3.932 0 5.104L9.576 21.466C7.578 22.701 5 21.263 5 18.914V5.086Zm3.525-.85A1 1 0 0 0 7 5.085v13.828a1 1 0 0 0 1.525.85l11.194-6.913a1 1 0 0 0 0-1.702L8.525 4.235Z" clip-rule="evenodd"/></svg>

Before

Width:  |  Height:  |  Size: 374 B

+2 -3
View File
@@ -10,12 +10,11 @@
],
"rules": {
"simple-import-sort/imports": "warn",
"simple-import-sort/exports": "warn",
'no-else-return': 'off'
"simple-import-sort/exports": "warn"
},
"parserOptions": {
"sourceType": "module",
"ecmaVersion": "latest",
"project": "./bskyembed/tsconfig.json"
}
}
}
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#fff" d="M9.576 2.534C7.578 1.299 5 2.737 5 5.086v13.828c0 2.35 2.578 3.787 4.576 2.552l11.194-6.914c1.899-1.172 1.899-3.932 0-5.104L9.576 2.534Z"/></svg>

Before

Width:  |  Height:  |  Size: 239 B

-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><defs><linearGradient x1="0" y1="0" x2="100%" y2="0" gradientTransform="rotate(45)" id="sky_V5w1FF_xb91wVQ_1euhBX"><stop offset="0" stop-color="#0A7AFF"></stop><stop offset="1" stop-color="#59B9FF"></stop></linearGradient></defs><path fill="url(#sky_V5w1FF_xb91wVQ_1euhBX)" fill-rule="evenodd" clip-rule="evenodd" d="M11.26 5.227 5.02 6.899c-.734.197-1.17.95-.973 1.685l1.672 6.24c.197.734.951 1.17 1.685.973l6.24-1.672c.734-.197 1.17-.951.973-1.685L12.945 6.2a1.375 1.375 0 0 0-1.685-.973Zm-6.566.459a2.632 2.632 0 0 0-1.86 3.223l1.672 6.24a2.632 2.632 0 0 0 3.223 1.861l6.24-1.672a2.631 2.631 0 0 0 1.861-3.223l-1.672-6.24a2.632 2.632 0 0 0-3.223-1.861l-6.24 1.672Z"></path><path fill="url(#sky_V5w1FF_xb91wVQ_1euhBX)" fill-rule="evenodd" clip-rule="evenodd" d="M15.138 18.411a4.606 4.606 0 1 0 0-9.211 4.606 4.606 0 0 0 0 9.211Zm0 1.257a5.862 5.862 0 1 0 0-11.724 5.862 5.862 0 0 0 0 11.724Z"></path></svg>

Before

Width:  |  Height:  |  Size: 982 B

+2 -2
View File
@@ -9,7 +9,7 @@
"lint": "eslint --cache --ext .js,.jsx,.ts,.tsx src"
},
"dependencies": {
"@atproto/api": "0.13.6",
"@atproto/api": "^0.12.2",
"@preact/preset-vite": "^2.8.2",
"@vitejs/plugin-legacy": "^5.3.2",
"preact": "^10.4.8",
@@ -22,7 +22,7 @@
"eslint-plugin-simple-import-sort": "^12.0.0",
"postcss": "^8.4.38",
"tailwindcss": "^3.4.3",
"typescript": "^5.5.4",
"typescript": "^4.0.5",
"vite": "^5.2.8",
"vite-tsconfig-paths": "^4.3.2"
}
+17 -113
View File
@@ -3,20 +3,15 @@ import {
AppBskyEmbedImages,
AppBskyEmbedRecord,
AppBskyEmbedRecordWithMedia,
AppBskyEmbedVideo,
AppBskyFeedDefs,
AppBskyFeedPost,
AppBskyGraphDefs,
AppBskyGraphStarterpack,
AppBskyLabelerDefs,
AtUri,
} from '@atproto/api'
import {ComponentChildren, h} from 'preact'
import {useMemo} from 'preact/hooks'
import infoIcon from '../../assets/circleInfo_stroke2_corner0_rounded.svg'
import playIcon from '../../assets/play_filled_corner2_rounded.svg'
import starterPackIcon from '../../assets/starterPack.svg'
import {CONTENT_LABELS, labelsToInfo} from '../labels'
import {getRkey} from '../utils'
import {Link} from './link'
@@ -110,7 +105,7 @@ export function Embed({
// Case 3.2: List
if (AppBskyGraphDefs.isListView(record)) {
return (
<GenericWithImageEmbed
<GenericWithImage
image={record.avatar}
title={record.name}
href={`/profile/${record.creator.did}/lists/${getRkey(record)}`}
@@ -127,7 +122,7 @@ export function Embed({
// Case 3.3: Feed
if (AppBskyFeedDefs.isGeneratorView(record)) {
return (
<GenericWithImageEmbed
<GenericWithImage
image={record.avatar}
title={record.displayName}
href={`/profile/${record.creator.did}/feed/${getRkey(record)}`}
@@ -139,35 +134,31 @@ export function Embed({
// Case 3.4: Labeler
if (AppBskyLabelerDefs.isLabelerView(record)) {
// Embed type does not exist in the app, so show nothing
return null
return (
<GenericWithImage
image={record.creator.avatar}
title={record.creator.displayName || record.creator.handle}
href={`/profile/${record.creator.did}`}
subtitle="Labeler"
description={`Liked by ${record.likeCount ?? 0} users`}
/>
)
}
// Case 3.5: Starter pack
if (AppBskyGraphDefs.isStarterPackViewBasic(record)) {
return <StarterPackEmbed content={record} />
}
// Case 3.6: Post not found
// Case 3.5: Post not found
if (AppBskyEmbedRecord.isViewNotFound(record)) {
return <Info>Quoted post not found, it may have been deleted.</Info>
}
// Case 3.7: Post blocked
// Case 3.6: Post blocked
if (AppBskyEmbedRecord.isViewBlocked(record)) {
return <Info>The quoted post is blocked.</Info>
}
// Unknown embed type
return null
throw new Error('Unknown embed type')
}
// Case 4: Video
if (AppBskyEmbedVideo.isView(content)) {
return <VideoEmbed content={content} />
}
// Case 5: Record with media
// Case 4: Record with media
if (
AppBskyEmbedRecordWithMedia.isView(content) &&
AppBskyEmbedRecord.isViewRecord(content.record.record)
@@ -191,8 +182,7 @@ export function Embed({
)
}
// Unknown embed type
return null
throw new Error('Unsupported embed type')
} catch (err) {
return (
<Info>{err instanceof Error ? err.message : 'An error occurred'}</Info>
@@ -324,7 +314,7 @@ function ExternalEmbed({
)
}
function GenericWithImageEmbed({
function GenericWithImage({
title,
subtitle,
href,
@@ -360,89 +350,3 @@ function GenericWithImageEmbed({
</Link>
)
}
// just the thumbnail and a play button
function VideoEmbed({content}: {content: AppBskyEmbedVideo.View}) {
let aspectRatio = 1
if (content.aspectRatio) {
const {width, height} = content.aspectRatio
aspectRatio = clamp(width / height, 1 / 1, 3 / 1)
}
return (
<div
className="w-full overflow-hidden rounded-lg aspect-square"
style={{aspectRatio: `${aspectRatio} / 1`}}>
<img
src={content.thumbnail}
alt={content.alt}
className="object-cover size-full"
/>
<div className="size-24 absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-black/50 flex items-center justify-center">
<img src={playIcon} className="object-cover size-3/5" />
</div>
</div>
)
}
function StarterPackEmbed({
content,
}: {
content: AppBskyGraphDefs.StarterPackViewBasic
}) {
if (!AppBskyGraphStarterpack.isRecord(content.record)) {
return null
}
const starterPackHref = getStarterPackHref(content)
const imageUri = getStarterPackImage(content)
return (
<Link
href={starterPackHref}
className="w-full rounded-lg overflow-hidden border flex flex-col items-stretch">
<img src={imageUri} className="aspect-[1.91/1] object-cover" />
<div className="py-3 px-4">
<div className="flex space-x-2 items-center">
<img src={starterPackIcon} className="w-10 h-10" />
<div>
<p className="font-semibold leading-[21px]">
{content.record.name}
</p>
<p className="text-sm text-textLight line-clamp-2 leading-[18px]">
Starter pack by{' '}
{content.creator.displayName || `@${content.creator.handle}`}
</p>
</div>
</div>
{content.record.description && (
<p className="text-sm mt-1">{content.record.description}</p>
)}
{!!content.joinedAllTimeCount && content.joinedAllTimeCount > 50 && (
<p className="text-sm font-semibold text-textLight mt-1">
{content.joinedAllTimeCount} users have joined!
</p>
)}
</div>
</Link>
)
}
// from #/lib/strings/starter-pack.ts
function getStarterPackImage(starterPack: AppBskyGraphDefs.StarterPackView) {
const rkey = new AtUri(starterPack.uri).rkey
return `https://ogcard.cdn.bsky.app/start/${starterPack.creator.did}/${rkey}`
}
function getStarterPackHref(
starterPack: AppBskyGraphDefs.StarterPackViewBasic,
) {
const rkey = new AtUri(starterPack.uri).rkey
const handleOrDid = starterPack.creator.handle || starterPack.creator.did
return `/starter-pack/${handleOrDid}/${rkey}`
}
function clamp(num: number, min: number, max: number) {
return Math.max(min, Math.min(num, max))
}
+5 -8
View File
@@ -11,7 +11,7 @@ import likeIcon from '../../assets/heart2_filled_stroke2_corner0_rounded.svg'
import logo from '../../assets/logo.svg'
import repostIcon from '../../assets/repost_stroke2_corner2_rounded.svg'
import {CONTENT_LABELS} from '../labels'
import {getRkey, niceDate, prettyNumber} from '../utils'
import {getRkey, niceDate} from '../utils'
import {Container} from './container'
import {Embed} from './embed'
import {Link} from './link'
@@ -78,7 +78,7 @@ export function Post({thread}: Props) {
<div className="flex items-center gap-2 cursor-pointer">
<img src={likeIcon} className="w-5 h-5" />
<p className="font-bold text-neutral-500 mb-px">
{prettyNumber(post.likeCount)}
{post.likeCount}
</p>
</div>
)}
@@ -86,7 +86,7 @@ export function Post({thread}: Props) {
<div className="flex items-center gap-2 cursor-pointer">
<img src={repostIcon} className="w-5 h-5" />
<p className="font-bold text-neutral-500 mb-px">
{prettyNumber(post.repostCount)}
{post.repostCount}
</p>
</div>
)}
@@ -97,7 +97,7 @@ export function Post({thread}: Props) {
<div className="flex-1" />
<p className="cursor-pointer text-brand font-bold hover:underline hidden min-[450px]:inline">
{post.replyCount
? `Read ${prettyNumber(post.replyCount)} ${
? `Read ${post.replyCount} ${
post.replyCount > 1 ? 'replies' : 'reply'
} on Bluesky`
: `View on Bluesky`}
@@ -132,10 +132,7 @@ function PostContent({record}: {record: AppBskyFeedPost.Record | null}) {
key={counter}
href={segment.link.uri}
className="text-blue-400 hover:underline"
disableTracking={
!segment.link.uri.startsWith('https://bsky.app') &&
!segment.link.uri.startsWith('https://go.bsky.app')
}>
disableTracking={!segment.link.uri.startsWith('https://bsky.app')}>
{segment.text}
</Link>,
)
+2 -2
View File
@@ -1,6 +1,6 @@
import '../index.css'
import {AppBskyFeedDefs, AtpAgent} from '@atproto/api'
import {AppBskyFeedDefs, BskyAgent} from '@atproto/api'
import {h, render} from 'preact'
import logo from '../../assets/logo.svg'
@@ -12,7 +12,7 @@ import {getRkey} from '../utils'
const root = document.getElementById('app')
if (!root) throw new Error('No root element')
const agent = new AtpAgent({
const agent = new BskyAgent({
service: 'https://public.api.bsky.app',
})
-10
View File
@@ -16,13 +16,3 @@ export function getRkey({uri}: {uri: string}): string {
const at = new AtUri(uri)
return at.rkey
}
const formatter = new Intl.NumberFormat('en-US', {
notation: 'compact',
maximumFractionDigits: 1,
roundingMode: 'trunc',
})
export function prettyNumber(number: number) {
return formatter.format(number)
}
+1 -1
View File
@@ -20,5 +20,5 @@
"jsxFragmentFactory": "Fragment",
"downlevelIteration": true
},
"include": ["src", "vite.config.ts"]
"include": ["src"]
}
+1 -1
View File
@@ -6,5 +6,5 @@
"strict": true,
"outDir": "dist"
},
"include": ["snippet"]
"include": ["snippet"],
}
+24 -50
View File
@@ -20,16 +20,15 @@
"@jridgewell/gen-mapping" "^0.3.5"
"@jridgewell/trace-mapping" "^0.3.24"
"@atproto/api@0.13.6":
version "0.13.6"
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.13.6.tgz#2500e9d7143e6718089632300c42ce50149f8cd5"
integrity sha512-58emFFZhqY8nVWD3xFWK0yYqAmJ2un+NaTtZxBbRo00mGq1rz9VXTpVmfoHFcuXL1hoDQN3WyJfsub8r6xGOgg==
"@atproto/api@^0.12.2":
version "0.12.2"
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.12.2.tgz#5df6d4f60dea0395c84fdebd9e81a7e853edf130"
integrity sha512-UVzCiDZH2j0wrr/O8nb1edD5cYLVqB5iujueXUCbHS3rAwIxgmyLtA3Hzm2QYsGPo/+xsIg1fNvpq9rNT6KWUA==
dependencies:
"@atproto/common-web" "^0.3.0"
"@atproto/lexicon" "^0.4.1"
"@atproto/lexicon" "^0.4.0"
"@atproto/syntax" "^0.3.0"
"@atproto/xrpc" "^0.6.1"
await-lock "^2.2.2"
"@atproto/xrpc" "^0.5.0"
multiformats "^9.9.0"
tlds "^1.234.0"
@@ -43,29 +42,29 @@
uint8arrays "3.0.0"
zod "^3.21.4"
"@atproto/lexicon@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.4.1.tgz#19155210570a2fafbcc7d4f655d9b813948e72a0"
integrity sha512-bzyr+/VHXLQWbumViX5L7h1NKQObfs8Z+XZJl43OUK8nYFUI4e/sW1IZKRNfw7Wvi5YVNK+J+yP3DWIBZhkCYA==
"@atproto/lexicon@^0.4.0":
version "0.4.0"
resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.4.0.tgz#63e8829945d80c25524882caa8ed27b1151cc576"
integrity sha512-RvCBKdSI4M8qWm5uTNz1z3R2yIvIhmOsMuleOj8YR6BwRD+QbtUBy3l+xQ7iXf4M5fdfJFxaUNa6Ty0iRwdKqQ==
dependencies:
"@atproto/common-web" "^0.3.0"
"@atproto/syntax" "^0.3.0"
iso-datestring-validator "^2.2.2"
multiformats "^9.9.0"
zod "^3.23.8"
zod "^3.21.4"
"@atproto/syntax@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@atproto/syntax/-/syntax-0.3.0.tgz#fafa2dbea9add37253005cb663e7373e05e618b3"
integrity sha512-Weq0ZBxffGHDXHl9U7BQc2BFJi/e23AL+k+i5+D9hUq/bzT4yjGsrCejkjq0xt82xXDjmhhvQSZ0LqxyZ5woxA==
"@atproto/xrpc@^0.6.1":
version "0.6.1"
resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.6.1.tgz#dcd1315c8c60eef5af2db7fa4e35a38ebc6d79d5"
integrity sha512-Zy5ydXEdk6sY7FDUZcEVfCL1jvbL4tXu5CcdPqbEaW6LQtk9GLds/DK1bCX9kswTGaBC88EMuqQMfkxOhp2t4A==
"@atproto/xrpc@^0.5.0":
version "0.5.0"
resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.5.0.tgz#dacbfd8f7b13f0ab5bd56f8fdd4b460e132a6032"
integrity sha512-swu+wyOLvYW4l3n+VAuJbHcPcES+tin2Lsrp8Bw5aIXIICiuFn1YMFlwK9JwVUzTH21Py1s1nHEjr4CJeElJog==
dependencies:
"@atproto/lexicon" "^0.4.1"
zod "^3.23.8"
"@atproto/lexicon" "^0.4.0"
zod "^3.21.4"
"@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1", "@babel/code-frame@^7.24.2":
version "7.24.2"
@@ -1711,11 +1710,6 @@ available-typed-arrays@^1.0.7:
dependencies:
possible-typed-array-names "^1.0.0"
await-lock@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/await-lock/-/await-lock-2.2.2.tgz#a95a9b269bfd2f69d22b17a321686f551152bcef"
integrity sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==
babel-plugin-polyfill-corejs2@^0.4.10:
version "0.4.10"
resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz#276f41710b03a64f6467433cab72cbc2653c38b1"
@@ -3736,16 +3730,8 @@ stack-trace@^1.0.0-pre2:
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-1.0.0-pre2.tgz#46a83a79f1b287807e9aaafc6a5dd8bcde626f9c"
integrity sha512-2ztBJRek8IVofG9DBJqdy2N5kulaacX30Nz7xmkYF6ale9WBVmIy6mFBchvGX7Vx/MyjBhx+Rcxqrj+dbOnQ6A==
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
string-width@^4.1.0:
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
name string-width-cjs
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -3809,14 +3795,7 @@ string.prototype.trimstart@^1.0.8:
define-properties "^1.2.1"
es-object-atoms "^1.0.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -4024,10 +4003,10 @@ typed-array-length@^1.0.6:
is-typed-array "^1.1.13"
possible-typed-array-names "^1.0.0"
typescript@^5.5.4:
version "5.5.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba"
integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==
typescript@^4.0.5:
version "4.9.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
uint8arrays@3.0.0:
version "3.0.0"
@@ -4213,8 +4192,3 @@ zod@^3.21.4:
version "3.22.4"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff"
integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==
zod@^3.23.8:
version "3.23.8"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d"
integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==
+3 -16
View File
@@ -41,10 +41,10 @@ func run(args []string) {
EnvVars: []string{"ATP_APPVIEW_HOST", "ATP_PDS_HOST"},
},
&cli.StringFlag{
Name: "ogcard-host",
Usage: "scheme, hostname, and port of ogcard service",
Name: "ogcard-host",
Usage: "scheme, hostname, and port of ogcard service",
Required: false,
EnvVars: []string{"OGCARD_HOST"},
EnvVars: []string{"OGCARD_HOST"},
},
&cli.StringFlag{
Name: "http-address",
@@ -60,12 +60,6 @@ func run(args []string) {
Value: "",
EnvVars: []string{"LINK_HOST"},
},
&cli.StringFlag{
Name: "ipcc-host",
Usage: "scheme, hostname, and port of ipcc service",
Value: "https://localhost:8730",
EnvVars: []string{"IPCC_HOST"},
},
&cli.BoolFlag{
Name: "debug",
Usage: "Enable debug mode",
@@ -73,13 +67,6 @@ func run(args []string) {
Required: false,
EnvVars: []string{"DEBUG"},
},
&cli.StringFlag{
Name: "basic-auth-password",
Usage: "optional password to restrict access to web interface",
Required: false,
Value: "",
EnvVars: []string{"BASIC_AUTH_PASSWORD"},
},
},
},
}
-86
View File
@@ -1,17 +1,11 @@
package main
import (
"bytes"
"context"
"crypto/subtle"
"crypto/tls"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io/fs"
"net/http"
"net/netip"
"net/url"
"os"
"os/signal"
@@ -46,7 +40,6 @@ type Config struct {
appviewHost string
ogcardHost string
linkHost string
ipccHost string
}
func serve(cctx *cli.Context) error {
@@ -55,8 +48,6 @@ func serve(cctx *cli.Context) error {
appviewHost := cctx.String("appview-host")
ogcardHost := cctx.String("ogcard-host")
linkHost := cctx.String("link-host")
ipccHost := cctx.String("ipcc-host")
basicAuthPassword := cctx.String("basic-auth-password")
// Echo
e := echo.New()
@@ -98,7 +89,6 @@ func serve(cctx *cli.Context) error {
appviewHost: appviewHost,
ogcardHost: ogcardHost,
linkHost: linkHost,
ipccHost: ipccHost,
},
}
@@ -150,18 +140,6 @@ func serve(cctx *cli.Context) error {
},
}))
// optional password gating of entire web interface
if basicAuthPassword != "" {
e.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) {
// Be careful to use constant time comparison to prevent timing attacks
if subtle.ConstantTimeCompare([]byte(username), []byte("admin")) == 1 &&
subtle.ConstantTimeCompare([]byte(password), []byte(basicAuthPassword)) == 1 {
return true, nil
}
return false, nil
}))
}
// redirect trailing slash to non-trailing slash.
// all of our current endpoints have no trailing slash.
e.Use(middleware.RemoveTrailingSlashWithConfig(middleware.TrailingSlashConfig{
@@ -219,7 +197,6 @@ func serve(cctx *cli.Context) error {
e.GET("/search", server.WebGeneric)
e.GET("/feeds", server.WebGeneric)
e.GET("/notifications", server.WebGeneric)
e.GET("/notifications/settings", server.WebGeneric)
e.GET("/lists", server.WebGeneric)
e.GET("/moderation", server.WebGeneric)
e.GET("/moderation/modlists", server.WebGeneric)
@@ -233,7 +210,6 @@ func serve(cctx *cli.Context) error {
e.GET("/settings/threads", server.WebGeneric)
e.GET("/settings/external-embeds", server.WebGeneric)
e.GET("/settings/accessibility", server.WebGeneric)
e.GET("/settings/appearance", server.WebGeneric)
e.GET("/sys/debug", server.WebGeneric)
e.GET("/sys/debug-mod", server.WebGeneric)
e.GET("/sys/log", server.WebGeneric)
@@ -263,15 +239,11 @@ func serve(cctx *cli.Context) error {
e.GET("/profile/:handleOrDID/post/:rkey", server.WebPost)
e.GET("/profile/:handleOrDID/post/:rkey/liked-by", server.WebGeneric)
e.GET("/profile/:handleOrDID/post/:rkey/reposted-by", server.WebGeneric)
e.GET("/profile/:handleOrDID/post/:rkey/quotes", server.WebGeneric)
// starter packs
e.GET("/starter-pack/:handleOrDID/:rkey", server.WebStarterPack)
e.GET("/start/:handleOrDID/:rkey", server.WebStarterPack)
// ipcc
e.GET("/ipcc", server.WebIpCC)
if linkHost != "" {
linkUrl, err := url.Parse(linkHost)
if err != nil {
@@ -531,61 +503,3 @@ func (srv *Server) WebProfile(c echo.Context) error {
data["requestHost"] = req.Host
return c.Render(http.StatusOK, "profile.html", data)
}
type IPCCRequest struct {
IP string `json:"ip"`
}
type IPCCResponse struct {
CC string `json:"countryCode"`
}
func (srv *Server) WebIpCC(c echo.Context) error {
realIP := c.RealIP()
addr, err := netip.ParseAddr(realIP)
if err != nil {
log.Warnf("could not parse IP %q %s", realIP, err)
return c.JSON(400, IPCCResponse{})
}
var request []byte
if addr.Is4() {
ip4 := addr.As4()
var dest [8]byte
base64.StdEncoding.Encode(dest[:], ip4[:])
request, _ = json.Marshal(IPCCRequest{IP: string(dest[:])})
} else if addr.Is6() {
ip6 := addr.As16()
var dest [24]byte
base64.StdEncoding.Encode(dest[:], ip6[:])
request, _ = json.Marshal(IPCCRequest{IP: string(dest[:])})
}
ipccUrlBuilder, err := url.Parse(srv.cfg.ipccHost)
if err != nil {
log.Errorf("ipcc misconfigured bad url %s", err)
return c.JSON(500, IPCCResponse{})
}
ipccUrlBuilder.Path = "ipccdata.IpCcService/Lookup"
ipccUrl := ipccUrlBuilder.String()
cl := http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
},
}
postBodyReader := bytes.NewReader(request)
response, err := cl.Post(ipccUrl, "application/json", postBodyReader)
if err != nil {
log.Warnf("ipcc backend error %s", err)
return c.JSON(500, IPCCResponse{})
}
defer response.Body.Close()
dec := json.NewDecoder(response.Body)
var outResponse IPCCResponse
err = dec.Decode(&outResponse)
if err != nil {
log.Warnf("ipcc bad response %s", err)
return c.JSON(500, IPCCResponse{})
}
return c.JSON(200, outResponse)
}
-5
View File
@@ -253,11 +253,6 @@
from { opacity: 1; }
to { opacity: 0; }
}
.force-no-clicks > *,
.force-no-clicks * {
pointer-events: none !important;
}
</style>
</style>
{% include "scripts.html" %}
+6 -3
View File
@@ -1,11 +1,14 @@
import 'react-native-gesture-handler' // must be first
import '#/platform/polyfills'
import {LogBox} from 'react-native'
import '#/platform/polyfills'
import {IS_TEST} from '#/env'
import {registerRootComponent} from 'expo'
import {doPolyfill} from '#/lib/api/api-polyfill'
import App from '#/App'
import {IS_TEST} from '#/env'
doPolyfill()
if (IS_TEST) {
LogBox.ignoreAllLogs() // suppress all logs in tests
+3 -2
View File
@@ -1,8 +1,9 @@
import '#/platform/markBundleStartTime'
import '#/platform/polyfills'
import {registerRootComponent} from 'expo'
import {doPolyfill} from '#/lib/api/api-polyfill'
import App from '#/App'
doPolyfill()
registerRootComponent(App)
-13
View File
@@ -95,16 +95,3 @@ jest.mock('expo-application', () => ({
nativeApplicationVersion: '1.0.0',
nativeBuildVersion: '1',
}))
jest.mock('expo-modules-core', () => ({
requireNativeModule: jest.fn().mockImplementation(moduleName => {
if (moduleName === 'ExpoPlatformInfo') {
return {
getIsReducedMotionEnabled: () => false,
}
}
}),
requireNativeViewManager: jest.fn().mockImplementation(moduleName => {
return () => null
}),
}))
+26 -27
View File
@@ -79,33 +79,32 @@ export async function createServer(
plc: {port: port2},
})
// DISABLED - looks like dev-env added this and now it conflicts
// add the test mod authority
// const agent = new BskyAgent({service: pdsUrl})
// const res = await agent.api.com.atproto.server.createAccount({
// email: 'mod-authority@test.com',
// handle: 'mod-authority.test',
// password: 'hunter2',
// })
// agent.api.setHeader('Authorization', `Bearer ${res.data.accessJwt}`)
// await agent.api.app.bsky.actor.profile.create(
// {repo: res.data.did},
// {
// displayName: 'Dev-env Moderation',
// description: `The pretend version of mod.bsky.app`,
// },
// )
const agent = new BskyAgent({service: pdsUrl})
const res = await agent.api.com.atproto.server.createAccount({
email: 'mod-authority@test.com',
handle: 'mod-authority.test',
password: 'hunter2',
})
agent.api.setHeader('Authorization', `Bearer ${res.data.accessJwt}`)
await agent.api.app.bsky.actor.profile.create(
{repo: res.data.did},
{
displayName: 'Dev-env Moderation',
description: `The pretend version of mod.bsky.app`,
},
)
// await agent.api.app.bsky.labeler.service.create(
// {repo: res.data.did, rkey: 'self'},
// {
// policies: {
// labelValues: ['!hide', '!warn'],
// labelValueDefinitions: [],
// },
// createdAt: new Date().toISOString(),
// },
// )
await agent.api.app.bsky.labeler.service.create(
{repo: res.data.did, rkey: 'self'},
{
policies: {
labelValues: ['!hide', '!warn'],
labelValueDefinitions: [],
},
createdAt: new Date().toISOString(),
},
)
const pic = fs.readFileSync(
path.join(__dirname, '..', 'assets', 'default-avatar.png'),
@@ -157,7 +156,7 @@ class Mocker {
}
async createUser(name: string) {
const agent = new BskyAgent({service: this.service})
const agent = new BskyAgent({service: this.agent.service})
const inviteRes = await agent.api.com.atproto.server.createInviteCode(
{useCount: 1},
@@ -333,7 +332,7 @@ class Mocker {
}
async createInvite(forAccount: string) {
const agent = new BskyAgent({service: this.service})
const agent = new BskyAgent({service: this.agent.service})
await agent.api.com.atproto.server.createInviteCode(
{useCount: 1, forAccount},
{
+9 -9
View File
@@ -13,43 +13,43 @@ class NotificationService: UNNotificationServiceExtension {
contentHandler(request.content)
return
}
if reason == "chat-message" {
mutateWithChatMessage(bestAttempt)
} else {
mutateWithBadge(bestAttempt)
}
contentHandler(bestAttempt)
}
override func serviceExtensionTimeWillExpire() {
// If for some reason the alloted time expires, we don't actually want to display a notification
}
func createCopy(_ content: UNNotificationContent) -> UNMutableNotificationContent? {
return content.mutableCopy() as? UNMutableNotificationContent
}
func mutateWithBadge(_ content: UNMutableNotificationContent) {
var count = prefs?.integer(forKey: "badgeCount") ?? 0
count += 1
// Set the new badge number for the notification, then store that value for using later
content.badge = NSNumber(value: count)
prefs?.setValue(count, forKey: "badgeCount")
}
func mutateWithChatMessage(_ content: UNMutableNotificationContent) {
if self.prefs?.bool(forKey: "playSoundChat") == true {
mutateWithDmSound(content)
}
}
func mutateWithDefaultSound(_ content: UNMutableNotificationContent) {
content.sound = UNNotificationSound.default
}
func mutateWithDmSound(_ content: UNMutableNotificationContent) {
content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "dm.aiff"))
}
@@ -30,11 +30,12 @@ class ShareViewController: UIViewController {
}
}
private func handleText(item: NSItemProvider) async {
private func handleText(item: NSItemProvider) async -> Void {
do {
if let data = try await item.loadItem(forTypeIdentifier: "public.text") as? String {
if let encoded = data.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed),
let url = URL(string: "\(self.appScheme)://intent/compose?text=\(encoded)") {
let url = URL(string: "\(self.appScheme)://intent/compose?text=\(encoded)")
{
_ = self.openURL(url)
}
}
@@ -44,11 +45,12 @@ class ShareViewController: UIViewController {
}
}
private func handleUrl(item: NSItemProvider) async {
private func handleUrl(item: NSItemProvider) async -> Void {
do {
if let data = try await item.loadItem(forTypeIdentifier: "public.url") as? URL {
if let encoded = data.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed),
let url = URL(string: "\(self.appScheme)://intent/compose?text=\(encoded)") {
let url = URL(string: "\(self.appScheme)://intent/compose?text=\(encoded)")
{
_ = self.openURL(url)
}
}
@@ -58,7 +60,7 @@ class ShareViewController: UIViewController {
}
}
private func handleImages(items: [NSItemProvider]) async {
private func handleImages(items: [NSItemProvider]) async -> Void {
let firstFourItems: [NSItemProvider]
if items.count < 4 {
firstFourItems = items
@@ -70,7 +72,7 @@ class ShareViewController: UIViewController {
var imageUris = ""
for (index, item) in firstFourItems.enumerated() {
var imageUriInfo: String?
var imageUriInfo: String? = nil
do {
if let dataUri = try await item.loadItem(forTypeIdentifier: "public.image") as? URL {
@@ -98,7 +100,8 @@ class ShareViewController: UIViewController {
if valid,
let encoded = imageUris.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed),
let url = URL(string: "\(self.appScheme)://intent/compose?imageUris=\(encoded)") {
let url = URL(string: "\(self.appScheme)://intent/compose?imageUris=\(encoded)")
{
_ = self.openURL(url)
}
@@ -116,11 +119,13 @@ class ShareViewController: UIViewController {
// extension does.
if let dir = FileManager()
.containerURL(
forSecurityApplicationGroupIdentifier: "group.app.bsky") {
forSecurityApplicationGroupIdentifier: "group.app.bsky")
{
let filePath = "\(dir.absoluteString)\(ProcessInfo.processInfo.globallyUniqueString).jpeg"
if let newUri = URL(string: filePath),
let jpegData = image.jpegData(compressionQuality: 1) {
let jpegData = image.jpegData(compressionQuality: 1)
{
try jpegData.write(to: newUri)
return "\(newUri.absoluteString)|\(image.size.width)|\(image.size.height)"
}
@@ -131,7 +136,7 @@ class ShareViewController: UIViewController {
}
}
private func completeRequest() {
private func completeRequest() -> Void {
self.extensionContext?.completeRequest(returningItems: nil)
}
@@ -5,7 +5,7 @@ import com.google.firebase.messaging.RemoteMessage
class BackgroundNotificationHandler(
private val context: Context,
private val notifInterface: BackgroundNotificationHandlerInterface,
private val notifInterface: BackgroundNotificationHandlerInterface
) {
fun handleMessage(remoteMessage: RemoteMessage) {
if (ExpoBackgroundNotificationHandlerModule.isForegrounded) {
@@ -8,68 +8,67 @@ class ExpoBackgroundNotificationHandlerModule : Module() {
var isForegrounded = false
}
override fun definition() =
ModuleDefinition {
Name("ExpoBackgroundNotificationHandler")
override fun definition() = ModuleDefinition {
Name("ExpoBackgroundNotificationHandler")
OnCreate {
NotificationPrefs(appContext.reactContext).initialize()
}
OnActivityEntersForeground {
isForegrounded = true
}
OnActivityEntersBackground {
isForegrounded = false
}
AsyncFunction("getAllPrefsAsync") {
return@AsyncFunction NotificationPrefs(appContext.reactContext).getAllPrefs()
}
AsyncFunction("getBoolAsync") { forKey: String ->
return@AsyncFunction NotificationPrefs(appContext.reactContext).getBoolean(forKey)
}
AsyncFunction("getStringAsync") { forKey: String ->
return@AsyncFunction NotificationPrefs(appContext.reactContext).getString(forKey)
}
AsyncFunction("getStringArrayAsync") { forKey: String ->
return@AsyncFunction NotificationPrefs(appContext.reactContext).getStringArray(forKey)
}
AsyncFunction("setBoolAsync") { forKey: String, value: Boolean ->
NotificationPrefs(appContext.reactContext).setBoolean(forKey, value)
}
AsyncFunction("setStringAsync") { forKey: String, value: String ->
NotificationPrefs(appContext.reactContext).setString(forKey, value)
}
AsyncFunction("setStringArrayAsync") { forKey: String, value: Array<String> ->
NotificationPrefs(appContext.reactContext).setStringArray(forKey, value)
}
AsyncFunction("addToStringArrayAsync") { forKey: String, string: String ->
NotificationPrefs(appContext.reactContext).addToStringArray(forKey, string)
}
AsyncFunction("removeFromStringArrayAsync") { forKey: String, string: String ->
NotificationPrefs(appContext.reactContext).removeFromStringArray(forKey, string)
}
AsyncFunction("addManyToStringArrayAsync") { forKey: String, strings: Array<String> ->
NotificationPrefs(appContext.reactContext).addManyToStringArray(forKey, strings)
}
AsyncFunction("removeManyFromStringArrayAsync") { forKey: String, strings: Array<String> ->
NotificationPrefs(appContext.reactContext).removeManyFromStringArray(forKey, strings)
}
AsyncFunction("setBadgeCountAsync") { _: Int ->
// This does nothing on Android
}
OnCreate {
NotificationPrefs(appContext.reactContext).initialize()
}
OnActivityEntersForeground {
isForegrounded = true
}
OnActivityEntersBackground {
isForegrounded = false
}
AsyncFunction("getAllPrefsAsync") {
return@AsyncFunction NotificationPrefs(appContext.reactContext).getAllPrefs()
}
AsyncFunction("getBoolAsync") { forKey: String ->
return@AsyncFunction NotificationPrefs(appContext.reactContext).getBoolean(forKey)
}
AsyncFunction("getStringAsync") { forKey: String ->
return@AsyncFunction NotificationPrefs(appContext.reactContext).getString(forKey)
}
AsyncFunction("getStringArrayAsync") { forKey: String ->
return@AsyncFunction NotificationPrefs(appContext.reactContext).getStringArray(forKey)
}
AsyncFunction("setBoolAsync") { forKey: String, value: Boolean ->
NotificationPrefs(appContext.reactContext).setBoolean(forKey, value)
}
AsyncFunction("setStringAsync") { forKey: String, value: String ->
NotificationPrefs(appContext.reactContext).setString(forKey, value)
}
AsyncFunction("setStringArrayAsync") { forKey: String, value: Array<String> ->
NotificationPrefs(appContext.reactContext).setStringArray(forKey, value)
}
AsyncFunction("addToStringArrayAsync") { forKey: String, string: String ->
NotificationPrefs(appContext.reactContext).addToStringArray(forKey, string)
}
AsyncFunction("removeFromStringArrayAsync") { forKey: String, string: String ->
NotificationPrefs(appContext.reactContext).removeFromStringArray(forKey, string)
}
AsyncFunction("addManyToStringArrayAsync") { forKey: String, strings: Array<String> ->
NotificationPrefs(appContext.reactContext).addManyToStringArray(forKey, strings)
}
AsyncFunction("removeManyFromStringArrayAsync") { forKey: String, strings: Array<String> ->
NotificationPrefs(appContext.reactContext).removeManyFromStringArray(forKey, strings)
}
AsyncFunction("setBadgeCountAsync") { _: Int ->
// This does nothing on Android
}
}
}
@@ -2,24 +2,20 @@ package expo.modules.backgroundnotificationhandler
import android.content.Context
val DEFAULTS =
mapOf<String, Any>(
"playSoundChat" to true,
"playSoundFollow" to false,
"playSoundLike" to false,
"playSoundMention" to false,
"playSoundQuote" to false,
"playSoundReply" to false,
"playSoundRepost" to false,
"mutedThreads" to mapOf<String, List<String>>(),
)
val DEFAULTS = mapOf<String, Any>(
"playSoundChat" to true,
"playSoundFollow" to false,
"playSoundLike" to false,
"playSoundMention" to false,
"playSoundQuote" to false,
"playSoundReply" to false,
"playSoundRepost" to false,
"mutedThreads" to mapOf<String, List<String>>()
)
class NotificationPrefs(
private val context: Context?,
) {
private val prefs =
context?.getSharedPreferences("xyz.blueskyweb.app", Context.MODE_PRIVATE)
?: throw Error("Context is null")
class NotificationPrefs (private val context: Context?) {
private val prefs = context?.getSharedPreferences("xyz.blueskyweb.app", Context.MODE_PRIVATE)
?: throw Error("Context is null")
fun initialize() {
prefs
@@ -45,99 +41,94 @@ class NotificationPrefs(
}
}
}
}.apply()
}
.apply()
}
fun getAllPrefs(): MutableMap<String, *> = prefs.all
fun getAllPrefs(): MutableMap<String, *> {
return prefs.all
}
fun getBoolean(key: String): Boolean = prefs.getBoolean(key, false)
fun getBoolean(key: String): Boolean {
return prefs.getBoolean(key, false)
}
fun getString(key: String): String? = prefs.getString(key, null)
fun getString(key: String): String? {
return prefs.getString(key, null)
}
fun getStringArray(key: String): Array<String>? = prefs.getStringSet(key, null)?.toTypedArray()
fun getStringArray(key: String): Array<String>? {
return prefs.getStringSet(key, null)?.toTypedArray()
}
fun setBoolean(
key: String,
value: Boolean,
) {
fun setBoolean(key: String, value: Boolean) {
prefs
.edit()
.apply {
putBoolean(key, value)
}.apply()
}
.apply()
}
fun setString(
key: String,
value: String,
) {
fun setString(key: String, value: String) {
prefs
.edit()
.apply {
putString(key, value)
}.apply()
}
.apply()
}
fun setStringArray(
key: String,
value: Array<String>,
) {
fun setStringArray(key: String, value: Array<String>) {
prefs
.edit()
.apply {
putStringSet(key, value.toSet())
}.apply()
}
.apply()
}
fun addToStringArray(
key: String,
string: String,
) {
fun addToStringArray(key: String, string: String) {
prefs
.edit()
.apply {
val set = prefs.getStringSet(key, null)?.toMutableSet() ?: mutableSetOf()
set.add(string)
putStringSet(key, set)
}.apply()
}
.apply()
}
fun removeFromStringArray(
key: String,
string: String,
) {
fun removeFromStringArray(key: String, string: String) {
prefs
.edit()
.apply {
val set = prefs.getStringSet(key, null)?.toMutableSet() ?: mutableSetOf()
set.remove(string)
putStringSet(key, set)
}.apply()
}
.apply()
}
fun addManyToStringArray(
key: String,
strings: Array<String>,
) {
fun addManyToStringArray(key: String, strings: Array<String>) {
prefs
.edit()
.apply {
val set = prefs.getStringSet(key, null)?.toMutableSet() ?: mutableSetOf()
set.addAll(strings.toSet())
putStringSet(key, set)
}.apply()
}
.apply()
}
fun removeManyFromStringArray(
key: String,
strings: Array<String>,
) {
fun removeManyFromStringArray(key: String, strings: Array<String>) {
prefs
.edit()
.apply {
val set = prefs.getStringSet(key, null)?.toMutableSet() ?: mutableSetOf()
set.removeAll(strings.toSet())
putStringSet(key, set)
}.apply()
}
.apply()
}
}
}
@@ -2,16 +2,16 @@ import ExpoModulesCore
let APP_GROUP = "group.app.bsky"
let DEFAULTS: [String: Any] = [
"playSoundChat": true,
let DEFAULTS: [String:Any] = [
"playSoundChat" : true,
"playSoundFollow": false,
"playSoundLike": false,
"playSoundMention": false,
"playSoundQuote": false,
"playSoundReply": false,
"playSoundRepost": false,
"mutedThreads": [:] as! [String: [String]],
"badgeCount": 0
"mutedThreads": [:] as! [String:[String]],
"badgeCount": 0,
]
/*
@@ -23,10 +23,10 @@ let DEFAULTS: [String: Any] = [
*/
public class ExpoBackgroundNotificationHandlerModule: Module {
let userDefaults = UserDefaults(suiteName: APP_GROUP)
public func definition() -> ModuleDefinition {
Name("ExpoBackgroundNotificationHandler")
OnCreate {
DEFAULTS.forEach { p in
if userDefaults?.value(forKey: p.key) == nil {
@@ -34,56 +34,57 @@ public class ExpoBackgroundNotificationHandlerModule: Module {
}
}
}
AsyncFunction("getAllPrefsAsync") { () -> [String: Any]? in
AsyncFunction("getAllPrefsAsync") { () -> [String:Any]? in
var keys: [String] = []
DEFAULTS.forEach { p in
keys.append(p.key)
}
return userDefaults?.dictionaryWithValues(forKeys: keys)
}
AsyncFunction("getBoolAsync") { (forKey: String) -> Bool in
if let pref = userDefaults?.bool(forKey: forKey) {
return pref
}
return false
}
AsyncFunction("getStringAsync") { (forKey: String) -> String? in
if let pref = userDefaults?.string(forKey: forKey) {
return pref
}
return nil
}
AsyncFunction("getStringArrayAsync") { (forKey: String) -> [String]? in
if let pref = userDefaults?.stringArray(forKey: forKey) {
return pref
}
return nil
}
AsyncFunction("setBoolAsync") { (forKey: String, value: Bool) in
AsyncFunction("setBoolAsync") { (forKey: String, value: Bool) -> Void in
userDefaults?.setValue(value, forKey: forKey)
}
AsyncFunction("setStringAsync") { (forKey: String, value: String) in
AsyncFunction("setStringAsync") { (forKey: String, value: String) -> Void in
userDefaults?.setValue(value, forKey: forKey)
}
AsyncFunction("setStringArrayAsync") { (forKey: String, value: [String]) in
AsyncFunction("setStringArrayAsync") { (forKey: String, value: [String]) -> Void in
userDefaults?.setValue(value, forKey: forKey)
}
AsyncFunction("addToStringArrayAsync") { (forKey: String, string: String) in
if var curr = userDefaults?.stringArray(forKey: forKey),
!curr.contains(string) {
!curr.contains(string)
{
curr.append(string)
userDefaults?.setValue(curr, forKey: forKey)
}
}
AsyncFunction("removeFromStringArrayAsync") { (forKey: String, string: String) in
if var curr = userDefaults?.stringArray(forKey: forKey) {
curr.removeAll { s in
@@ -92,7 +93,7 @@ public class ExpoBackgroundNotificationHandlerModule: Module {
userDefaults?.setValue(curr, forKey: forKey)
}
}
AsyncFunction("addManyToStringArrayAsync") { (forKey: String, strings: [String]) in
if var curr = userDefaults?.stringArray(forKey: forKey) {
strings.forEach { s in
@@ -103,7 +104,7 @@ public class ExpoBackgroundNotificationHandlerModule: Module {
userDefaults?.setValue(curr, forKey: forKey)
}
}
AsyncFunction("removeManyFromStringArrayAsync") { (forKey: String, strings: [String]) in
if var curr = userDefaults?.stringArray(forKey: forKey) {
strings.forEach { s in
@@ -112,7 +113,7 @@ public class ExpoBackgroundNotificationHandlerModule: Module {
userDefaults?.setValue(curr, forKey: forKey)
}
}
AsyncFunction("setBadgeCountAsync") { (count: Int) in
userDefaults?.setValue(count, forKey: "badgeCount")
}
@@ -5,10 +5,7 @@ import android.graphics.Canvas
import android.graphics.drawable.Animatable
import androidx.appcompat.widget.AppCompatImageView
class AppCompatImageViewExtended(
context: Context,
private val parent: GifView,
) : AppCompatImageView(context) {
class AppCompatImageViewExtended(context: Context, private val parent: GifView): AppCompatImageView(context) {
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
@@ -37,4 +34,4 @@ class AppCompatImageViewExtended(
drawable.start()
}
}
}
}
@@ -6,50 +6,49 @@ import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
class ExpoBlueskyGifViewModule : Module() {
override fun definition() =
ModuleDefinition {
Name("ExpoBlueskyGifView")
override fun definition() = ModuleDefinition {
Name("ExpoBlueskyGifView")
AsyncFunction("prefetchAsync") { sources: List<String> ->
val activity = appContext.currentActivity ?: return@AsyncFunction
val glide = Glide.with(activity)
AsyncFunction("prefetchAsync") { sources: List<String> ->
val activity = appContext.currentActivity ?: return@AsyncFunction
val glide = Glide.with(activity)
sources.forEach { source ->
glide
.download(source)
.diskCacheStrategy(DiskCacheStrategy.DATA)
.submit()
}
}
View(GifView::class) {
Events(
"onPlayerStateChange",
)
Prop("source") { view: GifView, source: String ->
view.source = source
}
Prop("placeholderSource") { view: GifView, source: String ->
view.placeholderSource = source
}
Prop("autoplay") { view: GifView, autoplay: Boolean ->
view.autoplay = autoplay
}
AsyncFunction("playAsync") { view: GifView ->
view.play()
}
AsyncFunction("pauseAsync") { view: GifView ->
view.pause()
}
AsyncFunction("toggleAsync") { view: GifView ->
view.toggle()
}
sources.forEach { source ->
glide
.download(source)
.diskCacheStrategy(DiskCacheStrategy.DATA)
.submit()
}
}
View(GifView::class) {
Events(
"onPlayerStateChange"
)
Prop("source") { view: GifView, source: String ->
view.source = source
}
Prop("placeholderSource") { view: GifView, source: String ->
view.placeholderSource = source
}
Prop("autoplay") { view: GifView, autoplay: Boolean ->
view.autoplay = autoplay
}
AsyncFunction("playAsync") { view: GifView ->
view.play()
}
AsyncFunction("pauseAsync") { view: GifView ->
view.pause()
}
AsyncFunction("toggleAsync") { view: GifView ->
view.toggle()
}
}
}
}
@@ -1,5 +1,6 @@
package expo.modules.blueskygifview
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.Animatable
@@ -14,10 +15,7 @@ import expo.modules.kotlin.exception.Exceptions
import expo.modules.kotlin.viewevent.EventDispatcher
import expo.modules.kotlin.views.ExpoView
class GifView(
context: Context,
appContext: AppContext,
) : ExpoView(context, appContext) {
class GifView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
// Events
private val onPlayerStateChange by EventDispatcher()
@@ -46,7 +44,8 @@ class GifView(
}
}
// <editor-fold desc="Lifecycle">
//<editor-fold desc="Lifecycle">
init {
this.setBackgroundColor(Color.TRANSPARENT)
@@ -71,82 +70,80 @@ class GifView(
super.onDetachedFromWindow()
}
// </editor-fold>
//</editor-fold>
// <editor-fold desc="Loading">
//<editor-fold desc="Loading">
private fun load() {
if (placeholderSource == null || source == null) {
return
}
this.webpRequest =
glide
.load(source)
.diskCacheStrategy(DiskCacheStrategy.DATA)
.skipMemoryCache(false)
.listener(
object : RequestListener<Drawable> {
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: com.bumptech.glide.load.DataSource?,
isFirstResource: Boolean,
): Boolean {
if (placeholderRequest != null) {
glide.clear(placeholderRequest)
}
return false
}
this.webpRequest = glide.load(source)
.diskCacheStrategy(DiskCacheStrategy.DATA)
.skipMemoryCache(false)
.listener(object: RequestListener<Drawable> {
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: com.bumptech.glide.load.DataSource?,
isFirstResource: Boolean
): Boolean {
if (placeholderRequest != null) {
glide.clear(placeholderRequest)
}
return false
}
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean,
): Boolean = true
},
).into(this.imageView)
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
return true
}
})
.into(this.imageView)
if (this.imageView.drawable == null || this.imageView.drawable !is Animatable) {
this.placeholderRequest =
glide
.load(placeholderSource)
.diskCacheStrategy(DiskCacheStrategy.DATA)
// Let's not bloat the memory cache with placeholders
.skipMemoryCache(true)
.listener(
object : RequestListener<Drawable> {
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: com.bumptech.glide.load.DataSource?,
isFirstResource: Boolean,
): Boolean {
// Incase this request finishes after the webp, let's just not set
// the drawable. This shouldn't happen because the request should get cancelled
if (imageView.drawable == null) {
imageView.setImageDrawable(resource)
}
return true
}
this.placeholderRequest = glide.load(placeholderSource)
.diskCacheStrategy(DiskCacheStrategy.DATA)
// Let's not bloat the memory cache with placeholders
.skipMemoryCache(true)
.listener(object: RequestListener<Drawable> {
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: com.bumptech.glide.load.DataSource?,
isFirstResource: Boolean
): Boolean {
// Incase this request finishes after the webp, let's just not set
// the drawable. This shouldn't happen because the request should get cancelled
if (imageView.drawable == null) {
imageView.setImageDrawable(resource)
}
return true
}
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean,
): Boolean = true
},
).submit()
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
return true
}
})
.submit()
}
}
// </editor-fold>
//</editor-fold>
// <editor-fold desc="Controls">
//<editor-fold desc="Controls">
fun play() {
this.imageView.play()
@@ -168,18 +165,16 @@ class GifView(
}
}
// </editor-fold>
//</editor-fold>
// <editor-fold desc="Util">
//<editor-fold desc="Util">
fun firePlayerStateChange() {
onPlayerStateChange(
mapOf(
"isPlaying" to this.isPlaying,
"isLoaded" to this.isLoaded,
),
)
onPlayerStateChange(mapOf(
"isPlaying" to this.isPlaying,
"isLoaded" to this.isLoaded,
))
}
// </editor-fold>
//</editor-fold>
}
@@ -5,11 +5,11 @@ import SDWebImageWebPCoder
public class ExpoBlueskyGifViewModule: Module {
public func definition() -> ModuleDefinition {
Name("ExpoBlueskyGifView")
OnCreate {
SDImageCodersManager.shared.addCoder(SDImageGIFCoder.shared)
}
AsyncFunction("prefetchAsync") { (sources: [URL]) in
SDWebImagePrefetcher.shared.prefetchURLs(sources, context: Util.createContext(), progress: nil)
}
@@ -18,27 +18,27 @@ public class ExpoBlueskyGifViewModule: Module {
Events(
"onPlayerStateChange"
)
Prop("source") { (view: GifView, prop: String) in
view.source = prop
}
Prop("placeholderSource") { (view: GifView, prop: String) in
view.placeholderSource = prop
}
Prop("autoplay") { (view: GifView, prop: Bool) in
view.autoplay = prop
}
AsyncFunction("toggleAsync") { (view: GifView) in
view.toggle()
}
AsyncFunction("playAsync") { (view: GifView) in
view.play()
}
AsyncFunction("pauseAsync") { (view: GifView) in
view.pause()
}
@@ -16,14 +16,14 @@ public class GifView: ExpoView, AVPlayerViewControllerDelegate {
)
private var isPlaying = true
private var isLoaded = false
// Requests
private var webpOperation: SDWebImageCombinedOperation?
private var placeholderOperation: SDWebImageCombinedOperation?
// Props
var source: String?
var placeholderSource: String?
var source: String? = nil
var placeholderSource: String? = nil
var autoplay = true {
didSet {
if !autoplay {
@@ -78,7 +78,8 @@ public class GifView: ExpoView, AVPlayerViewControllerDelegate {
// See:
// https://github.com/SDWebImage/SDWebImage/blob/master/Docs/HowToUse.md#using-asynchronous-image-caching-independently
if !SDImageCache.shared.diskImageDataExists(withKey: source),
let url = URL(string: placeholderSource) {
let url = URL(string: placeholderSource)
{
self.placeholderOperation = imageManager.loadImage(
with: url,
options: [.retryFailed],
@@ -131,7 +132,8 @@ public class GifView: ExpoView, AVPlayerViewControllerDelegate {
if let placeholderSource = self.placeholderSource,
imageUrl?.absoluteString == placeholderSource,
self.imageView.image == nil,
let image = image {
let image = image
{
self.setImage(image)
return
}
@@ -140,7 +142,8 @@ public class GifView: ExpoView, AVPlayerViewControllerDelegate {
imageUrl?.absoluteString == source,
// UIImage perf suckssss if the image is animated
let data = data,
let animatedImage = SDAnimatedImage(data: data) {
let animatedImage = SDAnimatedImage(data: data)
{
self.placeholderOperation?.cancel()
self.isPlaying = self.autoplay
self.isLoaded = true
@@ -0,0 +1,10 @@
package expo.modules.blueskyswissarmy.deviceprefs
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
class ExpoBlueskyDevicePrefsModule : Module() {
override fun definition() = ModuleDefinition {
Name("ExpoBlueskyDevicePrefs")
}
}
@@ -1,24 +0,0 @@
package expo.modules.blueskyswissarmy.platforminfo
import android.provider.Settings
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
class ExpoPlatformInfoModule : Module() {
override fun definition() =
ModuleDefinition {
Name("ExpoPlatformInfo")
// See https://github.com/software-mansion/react-native-reanimated/blob/7df5fd57d608fe25724608835461cd925ff5151d/packages/react-native-reanimated/android/src/main/java/com/swmansion/reanimated/nativeProxy/NativeProxyCommon.java#L242
Function("getIsReducedMotionEnabled") {
val resolver = appContext.reactContext?.contentResolver ?: return@Function false
val scale = Settings.Global.getString(resolver, Settings.Global.TRANSITION_ANIMATION_SCALE) ?: return@Function false
try {
return@Function scale.toFloat() == 0f
} catch (_: Error) {
return@Function false
}
}
}
}
@@ -1,103 +1,54 @@
package expo.modules.blueskyswissarmy.referrer
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.util.Log
import com.android.installreferrer.api.InstallReferrerClient
import com.android.installreferrer.api.InstallReferrerStateListener
import expo.modules.kotlin.Promise
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
import expo.modules.kotlin.Promise
class ExpoBlueskyReferrerModule : Module() {
private var intent: Intent? = null
private var activityReferrer: Uri? = null
override fun definition() = ModuleDefinition {
Name("ExpoBlueskyReferrer")
override fun definition() =
ModuleDefinition {
Name("ExpoBlueskyReferrer")
AsyncFunction("getGooglePlayReferrerInfoAsync") { promise: Promise ->
val referrerClient = InstallReferrerClient.newBuilder(appContext.reactContext).build()
referrerClient.startConnection(object : InstallReferrerStateListener {
override fun onInstallReferrerSetupFinished(responseCode: Int) {
if (responseCode == InstallReferrerClient.InstallReferrerResponse.OK) {
Log.d("ExpoGooglePlayReferrer", "Successfully retrieved referrer info.")
OnNewIntent {
intent = it
activityReferrer = appContext.currentActivity?.referrer
}
val response = referrerClient.installReferrer
Log.d("ExpoGooglePlayReferrer", "Install referrer: ${response.installReferrer}")
Function("getReferrerInfo") {
val intentReferrer =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent?.getParcelableExtra(Intent.EXTRA_REFERRER, Uri::class.java)
} else {
intent?.getParcelableExtra(Intent.EXTRA_REFERRER)
}
// Some apps explicitly set a referrer, like Chrome. In these cases, we prefer this since
// it's the actual website that the user came from rather than the app.
if (intentReferrer is Uri) {
val res =
mapOf(
"referrer" to intentReferrer.toString(),
"hostname" to intentReferrer.host,
)
intent = null
return@Function res
}
// In all other cases, we'll just record the app that sent the intent.
if (activityReferrer != null) {
// referrer could become null here. `.toString()` though can be called on null
val res =
mapOf(
"referrer" to activityReferrer.toString(),
"hostname" to (activityReferrer?.host ?: ""),
)
activityReferrer = null
return@Function res
}
return@Function null
}
AsyncFunction("getGooglePlayReferrerInfoAsync") { promise: Promise ->
val referrerClient = InstallReferrerClient.newBuilder(appContext.reactContext).build()
referrerClient.startConnection(
object : InstallReferrerStateListener {
override fun onInstallReferrerSetupFinished(responseCode: Int) {
if (responseCode == InstallReferrerClient.InstallReferrerResponse.OK) {
Log.d("ExpoGooglePlayReferrer", "Successfully retrieved referrer info.")
val response = referrerClient.installReferrer
Log.d("ExpoGooglePlayReferrer", "Install referrer: ${response.installReferrer}")
promise.resolve(
mapOf(
"installReferrer" to response.installReferrer,
"clickTimestamp" to response.referrerClickTimestampSeconds,
"installTimestamp" to response.installBeginTimestampSeconds,
),
)
} else {
Log.d("ExpoGooglePlayReferrer", "Failed to get referrer info. Unknown error.")
promise.reject(
"ERR_GOOGLE_PLAY_REFERRER_UNKNOWN",
"Failed to get referrer info",
Exception("Failed to get referrer info"),
)
}
referrerClient.endConnection()
}
override fun onInstallReferrerServiceDisconnected() {
Log.d("ExpoGooglePlayReferrer", "Failed to get referrer info. Service disconnected.")
referrerClient.endConnection()
promise.reject(
"ERR_GOOGLE_PLAY_REFERRER_DISCONNECTED",
"Failed to get referrer info",
Exception("Failed to get referrer info"),
promise.resolve(
mapOf(
"installReferrer" to response.installReferrer,
"clickTimestamp" to response.referrerClickTimestampSeconds,
"installTimestamp" to response.installBeginTimestampSeconds
)
}
},
)
}
)
} else {
Log.d("ExpoGooglePlayReferrer", "Failed to get referrer info. Unknown error.")
promise.reject(
"ERR_GOOGLE_PLAY_REFERRER_UNKNOWN",
"Failed to get referrer info",
Exception("Failed to get referrer info")
)
}
referrerClient.endConnection()
}
override fun onInstallReferrerServiceDisconnected() {
Log.d("ExpoGooglePlayReferrer", "Failed to get referrer info. Service disconnected.")
referrerClient.endConnection()
promise.reject(
"ERR_GOOGLE_PLAY_REFERRER_DISCONNECTED",
"Failed to get referrer info",
Exception("Failed to get referrer info")
)
}
})
}
}
}
}
@@ -1,69 +0,0 @@
package expo.modules.blueskyswissarmy.sharedprefs
import android.content.Context
import android.util.Log
import expo.modules.kotlin.jni.JavaScriptValue
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
class ExpoBlueskySharedPrefsModule : Module() {
private fun getContext(): Context {
val context = appContext.reactContext ?: throw Error("Context is null")
return context
}
override fun definition() =
ModuleDefinition {
Name("ExpoBlueskySharedPrefs")
Function("setString") { key: String, value: String ->
return@Function SharedPrefs(getContext()).setValue(key, value)
}
Function("setValue") { key: String, value: JavaScriptValue ->
val context = getContext()
Log.d("ExpoBlueskySharedPrefs", "Setting value for key: $key")
try {
if (value.isNumber()) {
SharedPrefs(context).setValue(key, value.getFloat())
} else if (value.isBool()) {
SharedPrefs(context).setValue(key, value.getBool())
} else if (value.isNull() || value.isUndefined()) {
SharedPrefs(context).removeValue(key)
} else {
Log.d(NAME, "Unsupported type: ${value.kind()}")
}
} catch (e: Error) {
Log.d(NAME, "Error setting value: $e")
}
}
Function("removeValue") { key: String ->
return@Function SharedPrefs(getContext()).removeValue(key)
}
Function("getString") { key: String ->
return@Function SharedPrefs(getContext()).getString(key)
}
Function("getNumber") { key: String ->
return@Function SharedPrefs(getContext()).getFloat(key)
}
Function("getBool") { key: String ->
return@Function SharedPrefs(getContext()).getBoolean(key)
}
Function("addToSet") { key: String, value: String ->
return@Function SharedPrefs(getContext()).addToSet(key, value)
}
Function("removeFromSet") { key: String, value: String ->
return@Function SharedPrefs(getContext()).removeFromSet(key, value)
}
Function("setContains") { key: String, value: String ->
return@Function SharedPrefs(getContext()).setContains(key, value)
}
}
}
@@ -1,241 +0,0 @@
package expo.modules.blueskyswissarmy.sharedprefs
import android.content.Context
import android.content.SharedPreferences
import android.util.Log
val DEFAULTS =
mapOf<String, Any>(
"playSoundChat" to true,
"playSoundFollow" to false,
"playSoundLike" to false,
"playSoundMention" to false,
"playSoundQuote" to false,
"playSoundReply" to false,
"playSoundRepost" to false,
"badgeCount" to 0,
)
const val NAME = "SharedPrefs"
class SharedPrefs(
private val context: Context,
) {
companion object {
private var hasInitialized = false
private var instance: SharedPreferences? = null
fun getInstance(
context: Context,
info: String? = "(no info)",
): SharedPreferences {
if (instance == null) {
Log.d(NAME, "No preferences instance found, creating one.")
instance = context.getSharedPreferences("xyz.blueskyweb.app", Context.MODE_PRIVATE)
}
val safeInstance = instance ?: throw Error("Preferences is null: $info")
if (!hasInitialized) {
Log.d(NAME, "Preferences instance has not been initialized yet.")
initialize(safeInstance)
hasInitialized = true
Log.d(NAME, "Preferences instance has been initialized.")
}
return safeInstance
}
private fun initialize(instance: SharedPreferences) {
instance
.edit()
.apply {
DEFAULTS.forEach { (key, value) ->
if (instance.contains(key)) {
return@forEach
}
when (value) {
is Boolean -> {
putBoolean(key, value)
}
is String -> {
putString(key, value)
}
is Array<*> -> {
putStringSet(key, value.map { it.toString() }.toSet())
}
is Map<*, *> -> {
putStringSet(key, value.map { it.toString() }.toSet())
}
}
}
}.apply()
}
}
fun setValue(
key: String,
value: String,
) {
val safeInstance = getInstance(context)
safeInstance
.edit()
.apply {
putString(key, value)
}.apply()
}
fun setValue(
key: String,
value: Float,
) {
val safeInstance = getInstance(context)
safeInstance
.edit()
.apply {
putFloat(key, value)
}.apply()
}
fun setValue(
key: String,
value: Boolean,
) {
val safeInstance = getInstance(context)
safeInstance
.edit()
.apply {
putBoolean(key, value)
}.apply()
}
fun setValue(
key: String,
value: Set<String>,
) {
val safeInstance = getInstance(context)
safeInstance
.edit()
.apply {
putStringSet(key, value)
}.apply()
}
fun removeValue(key: String) {
val safeInstance = getInstance(context)
safeInstance
.edit()
.apply {
remove(key)
}.apply()
}
fun getString(key: String): String? {
val safeInstance = getInstance(context)
return safeInstance.getString(key, null)
}
fun getFloat(key: String): Float? {
val safeInstance = getInstance(context)
if (!safeInstance.contains(key)) {
return null
}
return safeInstance.getFloat(key, 0.0f)
}
@Suppress("ktlint:standard:function-naming")
fun _setAnyValue(
key: String,
value: Any,
) {
val safeInstance = getInstance(context)
safeInstance
.edit()
.apply {
when (value) {
is String -> putString(key, value)
is Float -> putFloat(key, value)
is Boolean -> putBoolean(key, value)
is Set<*> -> putStringSet(key, value.map { it.toString() }.toSet())
else -> throw Error("Unsupported type: ${value::class.java}")
}
}.apply()
}
fun getBoolean(key: String): Boolean? {
val safeInstance = getInstance(context)
if (!safeInstance.contains(key)) {
return null
}
Log.d(NAME, "Getting boolean for key: $key")
val res = safeInstance.getBoolean(key, false)
Log.d(NAME, "Got boolean for key: $key, value: $res")
return res
}
fun addToSet(
key: String,
value: String,
) {
val safeInstance = getInstance(context)
val set = safeInstance.getStringSet(key, setOf()) ?: setOf()
val newSet =
set.toMutableSet().apply {
add(value)
}
safeInstance
.edit()
.apply {
putStringSet(key, newSet)
}.apply()
}
fun removeFromSet(
key: String,
value: String,
) {
val safeInstance = getInstance(context)
val set = safeInstance.getStringSet(key, setOf()) ?: setOf()
val newSet =
set.toMutableSet().apply {
remove(value)
}
safeInstance
.edit()
.apply {
putStringSet(key, newSet)
}.apply()
}
fun setContains(
key: String,
value: String,
): Boolean {
val safeInstance = getInstance(context)
val set = safeInstance.getStringSet(key, setOf()) ?: setOf()
return set.contains(value)
}
fun hasValue(key: String): Boolean {
val safeInstance = getInstance(context)
return safeInstance.contains(key)
}
fun getValues(keys: Set<String>): Map<String, Any?> {
val safeInstance = getInstance(context)
return keys.associateWith { key ->
when (val value = safeInstance.all[key]) {
is String -> value
is Float -> value
is Boolean -> value
is Set<*> -> value
else -> null
}
}
}
}
@@ -1,23 +0,0 @@
package expo.modules.blueskyswissarmy.visibilityview
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
class ExpoBlueskyVisibilityViewModule : Module() {
override fun definition() =
ModuleDefinition {
Name("ExpoBlueskyVisibilityView")
AsyncFunction("updateActiveViewAsync") {
VisibilityViewManager.updateActiveView()
}
View(VisibilityView::class) {
Events(arrayOf("onChangeStatus"))
Prop("enabled") { view: VisibilityView, prop: Boolean ->
view.isViewEnabled = prop
}
}
}
}
@@ -1,63 +0,0 @@
package expo.modules.blueskyswissarmy.visibilityview
import android.content.Context
import android.graphics.Rect
import expo.modules.kotlin.AppContext
import expo.modules.kotlin.viewevent.EventDispatcher
import expo.modules.kotlin.views.ExpoView
class VisibilityView(
context: Context,
appContext: AppContext,
) : ExpoView(context, appContext) {
var isViewEnabled: Boolean = false
private val onChangeStatus by EventDispatcher()
private var isCurrentlyActive = false
override fun onAttachedToWindow() {
super.onAttachedToWindow()
VisibilityViewManager.addView(this)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
VisibilityViewManager.removeView(this)
}
fun setIsCurrentlyActive(isActive: Boolean) {
if (isCurrentlyActive == isActive) {
return
}
this.isCurrentlyActive = isActive
this.onChangeStatus(
mapOf(
"isActive" to isActive,
),
)
}
fun getPositionOnScreen(): Rect? {
if (!this.isShown) {
return null
}
val screenPosition = intArrayOf(0, 0)
this.getLocationInWindow(screenPosition)
return Rect(
screenPosition[0],
screenPosition[1],
screenPosition[0] + this.width,
screenPosition[1] + this.height,
)
}
fun isViewableEnough(): Boolean {
val positionOnScreen = this.getPositionOnScreen() ?: return false
val visibleArea = positionOnScreen.width() * positionOnScreen.height()
val totalArea = this.width * this.height
return visibleArea >= 0.5 * totalArea
}
}
@@ -1,82 +0,0 @@
package expo.modules.blueskyswissarmy.visibilityview
import android.graphics.Rect
class VisibilityViewManager {
companion object {
private val views = HashMap<Int, VisibilityView>()
private var currentlyActiveView: VisibilityView? = null
private var prevCount = 0
fun addView(view: VisibilityView) {
this.views[view.id] = view
if (this.prevCount == 0) {
this.updateActiveView()
}
this.prevCount = this.views.count()
}
fun removeView(view: VisibilityView) {
this.views.remove(view.id)
this.prevCount = this.views.count()
}
fun updateActiveView() {
var activeView: VisibilityView? = null
val count = this.views.count()
if (count == 1) {
val view = this.views.values.first()
if (view.isViewableEnough()) {
activeView = view
}
} else if (count > 1) {
val views = this.views.values
var mostVisibleView: VisibilityView? = null
var mostVisiblePosition: Rect? = null
views.forEach { view ->
if (!view.isViewableEnough()) {
return
}
val position = view.getPositionOnScreen() ?: return@forEach
val topY = position.centerY() - (position.height() / 2)
if (topY >= 150) {
if (mostVisiblePosition == null) {
mostVisiblePosition = position
}
if (position.centerY() <= mostVisiblePosition!!.centerY()) {
mostVisibleView = view
mostVisiblePosition = position
}
}
}
activeView = mostVisibleView
}
if (activeView == this.currentlyActiveView) {
return
}
this.clearActiveView()
if (activeView != null) {
this.setActiveView(activeView)
}
}
private fun clearActiveView() {
this.currentlyActiveView?.setIsCurrentlyActive(false)
this.currentlyActiveView = null
}
private fun setActiveView(view: VisibilityView) {
view.setIsCurrentlyActive(true)
this.currentlyActiveView = view
}
}
}
@@ -1,19 +1,12 @@
{
"platforms": ["ios", "tvos", "android", "web"],
"ios": {
"modules": [
"ExpoBlueskySharedPrefsModule",
"ExpoBlueskyReferrerModule",
"ExpoBlueskyVisibilityViewModule",
"ExpoPlatformInfoModule"
]
"modules": ["ExpoBlueskyDevicePrefsModule", "ExpoBlueskyReferrerModule"]
},
"android": {
"modules": [
"expo.modules.blueskyswissarmy.sharedprefs.ExpoBlueskySharedPrefsModule",
"expo.modules.blueskyswissarmy.referrer.ExpoBlueskyReferrerModule",
"expo.modules.blueskyswissarmy.visibilityview.ExpoBlueskyVisibilityViewModule",
"expo.modules.blueskyswissarmy.platforminfo.ExpoPlatformInfoModule"
"expo.modules.blueskyswissarmy.deviceprefs.ExpoBlueskyDevicePrefsModule",
"expo.modules.blueskyswissarmy.referrer.ExpoBlueskyReferrerModule"
]
}
}
+2 -5
View File
@@ -1,7 +1,4 @@
import * as PlatformInfo from './src/PlatformInfo'
import {AudioCategory} from './src/PlatformInfo/types'
import * as DevicePrefs from './src/DevicePrefs'
import * as Referrer from './src/Referrer'
import * as SharedPrefs from './src/SharedPrefs'
import VisibilityView from './src/VisibilityView'
export {AudioCategory, PlatformInfo, Referrer, SharedPrefs, VisibilityView}
export {DevicePrefs, Referrer}
@@ -0,0 +1,23 @@
import ExpoModulesCore
public class ExpoBlueskyDevicePrefsModule: Module {
func getDefaults(_ useAppGroup: Bool) -> UserDefaults? {
if useAppGroup {
return UserDefaults(suiteName: "group.app.bsky")
} else {
return UserDefaults.standard
}
}
public func definition() -> ModuleDefinition {
Name("ExpoBlueskyDevicePrefs")
AsyncFunction("getStringValueAsync") { (key: String, useAppGroup: Bool) in
return self.getDefaults(useAppGroup)?.string(forKey: key)
}
AsyncFunction("setStringValueAsync") { (key: String, value: String?, useAppGroup: Bool) in
self.getDefaults(useAppGroup)?.setValue(value, forKey: key)
}
}
}
@@ -1,46 +0,0 @@
import ExpoModulesCore
public class ExpoPlatformInfoModule: Module {
private var prevAudioActive: Bool?
private var prevAudioCategory: AVAudioSession.Category?
public func definition() -> ModuleDefinition {
Name("ExpoPlatformInfo")
Function("getIsReducedMotionEnabled") {
return UIAccessibility.isReduceMotionEnabled
}
Function("setAudioCategory") { (audioCategoryString: String) in
let audioCategory = AVAudioSession.Category(rawValue: audioCategoryString)
if audioCategory == self.prevAudioCategory {
return
}
self.prevAudioCategory = audioCategory
DispatchQueue.global(qos: .background).async {
try? AVAudioSession.sharedInstance().setCategory(audioCategory)
}
}
Function("setAudioActive") { (active: Bool) in
if active == self.prevAudioActive {
return
}
self.prevAudioActive = active
if active {
DispatchQueue.global(qos: .background).async {
try? AVAudioSession.sharedInstance().setActive(true)
}
} else {
DispatchQueue.global(qos: .background).async {
try? AVAudioSession
.sharedInstance()
.setActive(
false,
options: [.notifyOthersOnDeactivation]
)
}
}
}
}
}
@@ -1,62 +0,0 @@
import Foundation
import ExpoModulesCore
public class ExpoBlueskySharedPrefsModule: Module {
let defaults = UserDefaults(suiteName: "group.app.bsky")
func getDefaults(_ info: String = "(no info)") -> UserDefaults? {
guard let defaults = self.defaults else {
NSLog("Failed to get defaults for app group: \(info)")
return nil
}
return defaults
}
public func definition() -> ModuleDefinition {
Name("ExpoBlueskySharedPrefs")
// JavaScripValue causes a crash when trying to check `isString()`. Let's
// explicitly define setString instead.
Function("setString") { (key: String, value: String?) in
SharedPrefs.shared.setValue(key, value)
}
Function("setValue") { (key: String, value: JavaScriptValue) in
if value.isNumber() {
SharedPrefs.shared.setValue(key, value.getDouble())
} else if value.isBool() {
SharedPrefs.shared.setValue(key, value.getBool())
} else if value.isNull() || value.isUndefined() {
SharedPrefs.shared.removeValue(key)
}
}
Function("removeValue") { (key: String) in
SharedPrefs.shared.removeValue(key)
}
Function("getString") { (key: String) in
return SharedPrefs.shared.getString(key)
}
Function("getBool") { (key: String) in
return SharedPrefs.shared.getBool(key)
}
Function("getNumber") { (key: String) in
return SharedPrefs.shared.getNumber(key)
}
Function("addToSet") { (key: String, value: String) in
SharedPrefs.shared.addToSet(key, value)
}
Function("removeFromSet") { (key: String, value: String) in
SharedPrefs.shared.removeFromSet(key, value)
}
Function("setContains") { (key: String, value: String) in
return SharedPrefs.shared.setContains(key, value)
}
}
}
@@ -1,89 +0,0 @@
import Foundation
public class SharedPrefs {
public static let shared = SharedPrefs()
private let defaults = UserDefaults(suiteName: "group.app.bsky")
init() {
if defaults == nil {
NSLog("Failed to get user defaults for app group.")
}
}
private func getDefaults(_ info: String = "(no info)") -> UserDefaults? {
guard let defaults = self.defaults else {
NSLog("Failed to get defaults for app group: \(info)")
return nil
}
return defaults
}
public func setValue(_ key: String, _ value: String?) {
getDefaults(key)?.setValue(value, forKey: key)
}
public func setValue(_ key: String, _ value: Double?) {
getDefaults(key)?.setValue(value, forKey: key)
}
public func setValue(_ key: String, _ value: Bool?) {
getDefaults(key)?.setValue(value, forKey: key)
}
public func _setAnyValue(_ key: String, _ value: Any?) {
getDefaults(key)?.setValue(value, forKey: key)
}
public func removeValue(_ key: String) {
getDefaults(key)?.removeObject(forKey: key)
}
public func getString(_ key: String) -> String? {
return getDefaults(key)?.string(forKey: key)
}
public func getNumber(_ key: String) -> Double? {
return getDefaults(key)?.double(forKey: key)
}
public func getBool(_ key: String) -> Bool? {
return getDefaults(key)?.bool(forKey: key)
}
public func addToSet(_ key: String, _ value: String) {
var dict: [String: Bool]?
if var currDict = getDefaults(key)?.dictionary(forKey: key) as? [String: Bool] {
currDict[value] = true
dict = currDict
} else {
dict = [
value: true
]
}
getDefaults(key)?.setValue(dict, forKey: key)
}
public func removeFromSet(_ key: String, _ value: String) {
guard var dict = getDefaults(key)?.dictionary(forKey: key) as? [String: Bool] else {
return
}
dict.removeValue(forKey: value)
getDefaults(key)?.setValue(dict, forKey: key)
}
public func setContains(_ key: String, _ value: String) -> Bool {
guard let dict = getDefaults(key)?.dictionary(forKey: key) as? [String: Bool] else {
return false
}
return dict[value] == true
}
public func hasValue(_ key: String) -> Bool {
return getDefaults(key)?.value(forKey: key) != nil
}
public func getValues(_ keys: [String]) -> [String: Any?]? {
return getDefaults("keys:\(keys)")?.dictionaryWithValues(forKeys: keys)
}
}
@@ -1,21 +0,0 @@
import ExpoModulesCore
public class ExpoBlueskyVisibilityViewModule: Module {
public func definition() -> ModuleDefinition {
Name("ExpoBlueskyVisibilityView")
AsyncFunction("updateActiveViewAsync") {
VisibilityViewManager.shared.updateActiveView()
}
View(VisibilityView.self) {
Events([
"onChangeStatus"
])
Prop("enabled") { (view: VisibilityView, prop: Bool) in
view.enabled = prop
}
}
}
}
@@ -1,86 +0,0 @@
import Foundation
class VisibilityViewManager {
static let shared = VisibilityViewManager()
private let views = NSHashTable<VisibilityView>(options: .weakMemory)
private var currentlyActiveView: VisibilityView?
private var screenHeight: CGFloat = UIScreen.main.bounds.height
private var prevCount = 0
func addView(_ view: VisibilityView) {
self.views.add(view)
if self.prevCount == 0 {
self.updateActiveView()
}
self.prevCount = self.views.count
}
func removeView(_ view: VisibilityView) {
self.views.remove(view)
self.prevCount = self.views.count
}
func updateActiveView() {
DispatchQueue.main.async {
var activeView: VisibilityView?
if self.views.count == 1 {
let view = self.views.allObjects[0]
if view.isViewableEnough() {
activeView = view
}
} else if self.views.count > 1 {
let views = self.views.allObjects
var mostVisibleView: VisibilityView?
var mostVisiblePosition: CGRect?
views.forEach { view in
if !view.isViewableEnough() {
return
}
guard let position = view.getPositionOnScreen() else {
return
}
if position.minY >= 150 {
if mostVisiblePosition == nil {
mostVisiblePosition = position
}
if let unwrapped = mostVisiblePosition,
position.minY <= unwrapped.minY {
mostVisibleView = view
mostVisiblePosition = position
}
}
}
activeView = mostVisibleView
}
if activeView == self.currentlyActiveView {
return
}
self.clearActiveView()
if let view = activeView {
self.setActiveView(view)
}
}
}
private func clearActiveView() {
if let currentlyActiveView = self.currentlyActiveView {
currentlyActiveView.setIsCurrentlyActive(isActive: false)
self.currentlyActiveView = nil
}
}
private func setActiveView(_ view: VisibilityView) {
view.setIsCurrentlyActive(isActive: true)
self.currentlyActiveView = view
}
}
@@ -1,69 +0,0 @@
import ExpoModulesCore
class VisibilityView: ExpoView {
var enabled = false {
didSet {
if enabled {
VisibilityViewManager.shared.removeView(self)
}
}
}
private let onChangeStatus = EventDispatcher()
private var isCurrentlyActiveView = false
required init(appContext: AppContext? = nil) {
super.init(appContext: appContext)
}
public override func willMove(toWindow newWindow: UIWindow?) {
super.willMove(toWindow: newWindow)
if !self.enabled {
return
}
if newWindow == nil {
VisibilityViewManager.shared.removeView(self)
} else {
VisibilityViewManager.shared.addView(self)
}
}
func setIsCurrentlyActive(isActive: Bool) {
if isCurrentlyActiveView == isActive {
return
}
self.isCurrentlyActiveView = isActive
self.onChangeStatus([
"isActive": isActive
])
}
}
// 🚨 DANGER 🚨
// These functions need to be called from the main thread. Xcode will warn you if you call one of them
// off the main thread, so pay attention!
extension UIView {
func getPositionOnScreen() -> CGRect? {
if let window = self.window {
return self.convert(self.bounds, to: window)
}
return nil
}
func isViewableEnough() -> Bool {
guard let window = self.window else {
return false
}
let viewFrameOnScreen = self.convert(self.bounds, to: window)
let screenBounds = window.bounds
let intersection = viewFrameOnScreen.intersection(screenBounds)
let viewHeight = viewFrameOnScreen.height
let intersectionHeight = intersection.height
return intersectionHeight >= 0.5 * viewHeight
}
}
@@ -0,0 +1,18 @@
import {requireNativeModule} from 'expo-modules-core'
const NativeModule = requireNativeModule('ExpoBlueskyDevicePrefs')
export function getStringValueAsync(
key: string,
useAppGroup?: boolean,
): Promise<string | null> {
return NativeModule.getStringValueAsync(key, useAppGroup)
}
export function setStringValueAsync(
key: string,
value: string | null,
useAppGroup?: boolean,
): Promise<void> {
return NativeModule.setStringValueAsync(key, value, useAppGroup)
}
@@ -0,0 +1,16 @@
import {NotImplementedError} from '../NotImplemented'
export function getStringValueAsync(
key: string,
useAppGroup?: boolean,
): Promise<string | null> {
throw new NotImplementedError({key, useAppGroup})
}
export function setStringValueAsync(
key: string,
value: string | null,
useAppGroup?: boolean,
): Promise<string | null> {
throw new NotImplementedError({key, value, useAppGroup})
}
@@ -1,20 +0,0 @@
import {Platform} from 'react-native'
import {requireNativeModule} from 'expo-modules-core'
import {AudioCategory} from './types'
const NativeModule = requireNativeModule('ExpoPlatformInfo')
export function getIsReducedMotionEnabled(): boolean {
return NativeModule.getIsReducedMotionEnabled()
}
export function setAudioActive(active: boolean): void {
if (Platform.OS !== 'ios') return
NativeModule.setAudioActive(active)
}
export function setAudioCategory(audioCategory: AudioCategory): void {
if (Platform.OS !== 'ios') return
NativeModule.setAudioCategory(audioCategory)
}
@@ -1,25 +0,0 @@
import {NotImplementedError} from '../NotImplemented'
import {AudioCategory} from './types'
export function getIsReducedMotionEnabled(): boolean {
throw new NotImplementedError()
}
/**
* Set whether the app's audio should mix with other apps' audio. Will also resume background music playback when `false`
* if it was previously playing.
* @param mixWithOthers
* @see https://developer.apple.com/documentation/avfaudio/avaudiosession/setactiveoptions/1616603-notifyothersondeactivation
*/
export function setAudioActive(active: boolean): void {
throw new NotImplementedError({active})
}
/**
* Set the audio category for the app.
* @param audioCategory
* @platform ios
*/
export function setAudioCategory(audioCategory: AudioCategory): void {
throw new NotImplementedError({audioCategory})
}
@@ -1,17 +0,0 @@
import {NotImplementedError} from '../NotImplemented'
import {AudioCategory} from './types'
export function getIsReducedMotionEnabled(): boolean {
if (typeof window === 'undefined') {
return false
}
return window.matchMedia('(prefers-reduced-motion: reduce)').matches
}
export function setAudioActive(active: boolean): void {
throw new NotImplementedError({active})
}
export function setAudioCategory(audioCategory: AudioCategory): void {
throw new NotImplementedError({audioCategory})
}
@@ -1,15 +0,0 @@
/**
* Sets the audio session category on iOS. In general, we should only need to use this for the `playback` and `ambient`
* categories. This enum however includes other categories that are available in the native API for clarity and
* potential future use.
* @see https://developer.apple.com/documentation/avfoundation/avaudiosession/category
* @platform ios
*/
export enum AudioCategory {
Ambient = 'AVAudioSessionCategoryAmbient',
Playback = 'AVAudioSessionCategoryPlayback',
_SoloAmbient = 'AVAudioSessionCategorySoloAmbient',
_Record = 'AVAudioSessionCategoryRecord',
_PlayAndRecord = 'AVAudioSessionCategoryPlayAndRecord',
_MultiRoute = 'AVAudioSessionCategoryMultiRoute',
}
@@ -1,13 +1,9 @@
import {requireNativeModule} from 'expo'
import {GooglePlayReferrerInfo, ReferrerInfo} from './types'
import {GooglePlayReferrerInfo} from './types'
export const NativeModule = requireNativeModule('ExpoBlueskyReferrer')
export function getGooglePlayReferrerInfoAsync(): Promise<GooglePlayReferrerInfo | null> {
export function getGooglePlayReferrerInfoAsync(): Promise<GooglePlayReferrerInfo> {
return NativeModule.getGooglePlayReferrerInfoAsync()
}
export function getReferrerInfo(): Promise<ReferrerInfo | null> {
return NativeModule.getReferrerInfo()
}
@@ -1,37 +0,0 @@
import {SharedPrefs} from '../../index'
import {NotImplementedError} from '../NotImplemented'
import {GooglePlayReferrerInfo, ReferrerInfo} from './types'
export function getGooglePlayReferrerInfoAsync(): Promise<GooglePlayReferrerInfo> {
throw new NotImplementedError()
}
export function getReferrerInfo(): ReferrerInfo | null {
const referrer = SharedPrefs.getString('referrer')
if (referrer) {
SharedPrefs.removeValue('referrer')
try {
const url = new URL(referrer)
return {
referrer,
hostname: url.hostname,
}
} catch (e) {
return {
referrer,
hostname: referrer,
}
}
}
const referrerApp = SharedPrefs.getString('referrerApp')
if (referrerApp) {
SharedPrefs.removeValue('referrerApp')
return {
referrer: referrerApp,
hostname: referrerApp,
}
}
return null
}
@@ -1,10 +1,7 @@
import {NotImplementedError} from '../NotImplemented'
import {GooglePlayReferrerInfo, ReferrerInfo} from './types'
import {GooglePlayReferrerInfo} from './types'
// @ts-ignore throws
export function getGooglePlayReferrerInfoAsync(): Promise<GooglePlayReferrerInfo> {
throw new NotImplementedError()
}
export function getReferrerInfo(): ReferrerInfo | null {
throw new NotImplementedError()
}
@@ -1,33 +0,0 @@
import {Platform} from 'react-native'
import {NotImplementedError} from '../NotImplemented'
import {GooglePlayReferrerInfo, ReferrerInfo} from './types'
export function getGooglePlayReferrerInfoAsync(): Promise<GooglePlayReferrerInfo> {
throw new NotImplementedError()
}
export function getReferrerInfo(): ReferrerInfo | null {
if (
Platform.OS === 'web' &&
// for ssr
typeof document !== 'undefined' &&
document != null &&
document.referrer
) {
try {
const url = new URL(document.referrer)
if (url.hostname !== 'bsky.app') {
return {
referrer: url.href,
hostname: url.hostname,
}
}
} catch {
// If something happens to the URL parsing, we don't want to actually cause any problems for the user. Just
// log the error so we might catch it
console.error('Failed to parse referrer URL')
}
}
return null
}
@@ -1,10 +1,7 @@
export type GooglePlayReferrerInfo = {
installReferrer?: string
clickTimestamp?: number
installTimestamp?: number
}
export type ReferrerInfo = {
referrer: string
hostname: string
}
export type GooglePlayReferrerInfo =
| {
installReferrer?: string
clickTimestamp?: number
installTimestamp?: number
}
| undefined
@@ -1,51 +0,0 @@
import {requireNativeModule} from 'expo-modules-core'
const NativeModule = requireNativeModule('ExpoBlueskySharedPrefs')
export function setValue(
key: string,
value: string | number | boolean | null | undefined,
): void {
// A bug on Android causes `JavaScripValue.isString()` to cause a crash on some occasions, seemingly because of a
// memory violation. Instead, we will use a specific function to set strings on this platform.
if (typeof value === 'string') {
return NativeModule.setString(key, value)
}
return NativeModule.setValue(key, value)
}
export function removeValue(key: string): void {
return NativeModule.removeValue(key)
}
export function getString(key: string): string | undefined {
return nullToUndefined(NativeModule.getString(key))
}
export function getNumber(key: string): number | undefined {
return nullToUndefined(NativeModule.getNumber(key))
}
export function getBool(key: string): boolean | undefined {
return nullToUndefined(NativeModule.getBool(key))
}
export function addToSet(key: string, value: string): void {
return NativeModule.addToSet(key, value)
}
export function removeFromSet(key: string, value: string): void {
return NativeModule.removeFromSet(key, value)
}
export function setContains(key: string, value: string): boolean {
return NativeModule.setContains(key, value)
}
// iOS returns `null` if a value does not exist, and Android returns `undefined. Normalize these here for JS types
function nullToUndefined(value: any) {
if (value == null) {
return undefined
}
return value
}
@@ -1,36 +0,0 @@
import {NotImplementedError} from '../NotImplemented'
export function setValue(
key: string,
value: string | number | boolean | null | undefined,
): void {
throw new NotImplementedError({key, value})
}
export function removeValue(key: string): void {
throw new NotImplementedError({key})
}
export function getString(key: string): string | null {
throw new NotImplementedError({key})
}
export function getNumber(key: string): number | null {
throw new NotImplementedError({key})
}
export function getBool(key: string): boolean | null {
throw new NotImplementedError({key})
}
export function addToSet(key: string, value: string): void {
throw new NotImplementedError({key, value})
}
export function removeFromSet(key: string, value: string): void {
throw new NotImplementedError({key, value})
}
export function setContains(key: string, value: string): boolean {
throw new NotImplementedError({key, value})
}
@@ -1,39 +0,0 @@
import React from 'react'
import {StyleProp, ViewStyle} from 'react-native'
import {requireNativeModule, requireNativeViewManager} from 'expo-modules-core'
import {VisibilityViewProps} from './types'
const NativeView: React.ComponentType<{
onChangeStatus: (e: {nativeEvent: {isActive: boolean}}) => void
children: React.ReactNode
enabled: Boolean
style: StyleProp<ViewStyle>
}> = requireNativeViewManager('ExpoBlueskyVisibilityView')
const NativeModule = requireNativeModule('ExpoBlueskyVisibilityView')
export async function updateActiveViewAsync() {
await NativeModule.updateActiveViewAsync()
}
export default function VisibilityView({
children,
onChangeStatus: onChangeStatusOuter,
enabled,
}: VisibilityViewProps) {
const onChangeStatus = React.useCallback(
(e: {nativeEvent: {isActive: boolean}}) => {
onChangeStatusOuter(e.nativeEvent.isActive)
},
[onChangeStatusOuter],
)
return (
<NativeView
onChangeStatus={onChangeStatus}
enabled={enabled}
style={{flex: 1}}>
{children}
</NativeView>
)
}
@@ -1,10 +0,0 @@
import {NotImplementedError} from '../NotImplemented'
import {VisibilityViewProps} from './types'
export async function updateActiveViewAsync() {
throw new NotImplementedError()
}
export default function VisibilityView({children}: VisibilityViewProps) {
return children
}
@@ -1,6 +0,0 @@
import React from 'react'
export interface VisibilityViewProps {
children: React.ReactNode
onChangeStatus: (isActive: boolean) => void
enabled: boolean
}
@@ -13,17 +13,16 @@ import java.io.FileOutputStream
import java.net.URLEncoder
class ExpoReceiveAndroidIntentsModule : Module() {
override fun definition() =
ModuleDefinition {
Name("ExpoReceiveAndroidIntents")
override fun definition() = ModuleDefinition {
Name("ExpoReceiveAndroidIntents")
OnNewIntent {
handleIntent(it)
}
OnNewIntent {
handleIntent(it)
}
}
private fun handleIntent(intent: Intent?) {
if (appContext.currentActivity == null || intent == null) return
if(appContext.currentActivity == null || intent == null) return
if (intent.action == Intent.ACTION_SEND) {
if (intent.type == "text/plain") {
@@ -41,7 +40,7 @@ class ExpoReceiveAndroidIntentsModule : Module() {
private fun handleTextIntent(intent: Intent) {
intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
val encoded = URLEncoder.encode(it, "UTF-8")
"bluesky://intent/compose?text=$encoded".toUri().let { uri ->
"bluesky://intent/compose?text=${encoded}".toUri().let { uri ->
val newIntent = Intent(Intent.ACTION_VIEW, uri)
appContext.currentActivity?.startActivity(newIntent)
}
@@ -49,12 +48,11 @@ class ExpoReceiveAndroidIntentsModule : Module() {
}
private fun handleImageIntent(intent: Intent) {
val uri =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
} else {
intent.getParcelableExtra(Intent.EXTRA_STREAM)
}
val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
} else {
intent.getParcelableExtra(Intent.EXTRA_STREAM)
}
if (uri == null) return
handleImageIntents(listOf(uri))
@@ -78,16 +76,16 @@ class ExpoReceiveAndroidIntentsModule : Module() {
uris.forEachIndexed { index, uri ->
val info = getImageInfo(uri)
val params = buildUriData(info)
allParams = "${allParams}$params"
allParams = "${allParams}${params}"
if (index < uris.count() - 1) {
allParams = "$allParams,"
allParams = "${allParams},"
}
}
val encoded = URLEncoder.encode(allParams, "UTF-8")
"bluesky://intent/compose?imageUris=$encoded".toUri().let {
"bluesky://intent/compose?imageUris=${encoded}".toUri().let {
val newIntent = Intent(Intent.ACTION_VIEW, it)
appContext.currentActivity?.startActivity(newIntent)
}
@@ -106,7 +104,7 @@ class ExpoReceiveAndroidIntentsModule : Module() {
return mapOf(
"width" to bitmap.width,
"height" to bitmap.height,
"path" to file.path.toString(),
"path" to file.path.toString()
)
}
@@ -116,6 +114,6 @@ class ExpoReceiveAndroidIntentsModule : Module() {
val path = info.getValue("path")
val width = info.getValue("width")
val height = info.getValue("height")
return "file://$path|$width|$height"
return "file://${path}|${width}|${height}"
}
}
@@ -3,7 +3,7 @@ import ExpoModulesCore
public class ExpoScrollForwarderModule: Module {
public func definition() -> ModuleDefinition {
Name("ExpoScrollForwarder")
View(ExpoScrollForwarderView.self) {
Prop("scrollViewTag") { (view: ExpoScrollForwarderView, prop: Int) in
view.scrollViewTag = prop
@@ -8,17 +8,17 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
self.tryFindScrollView()
}
}
private var rctScrollView: RCTScrollView?
private var rctRefreshCtrl: RCTRefreshControl?
private var cancelGestureRecognizers: [UIGestureRecognizer]?
private var animTimer: Timer?
private var initialOffset: CGFloat = 0.0
private var didImpact: Bool = false
required init(appContext: AppContext? = nil) {
super.init(appContext: appContext)
let pg = UIPanGestureRecognizer(target: self, action: #selector(callOnPan(_:)))
pg.delegate = self
self.addGestureRecognizer(pg)
@@ -34,27 +34,28 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
self.cancelGestureRecognizers = [lpg, tg]
}
// We don't want to recognize the scroll pan gesture and the swipe back gesture together
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer is UIPanGestureRecognizer, otherGestureRecognizer is UIPanGestureRecognizer {
return false
}
return true
}
// We only want the "scroll" gesture to happen whenever the pan is vertical, otherwise it will
// interfere with the native swipe back gesture.
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
guard let gestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer else {
return true
}
let velocity = gestureRecognizer.velocity(in: self)
return abs(velocity.y) > abs(velocity.x)
}
// This will be used to cancel the scroll animation whenever we tap inside of the header. We don't need another
// recognizer for this one.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
@@ -63,32 +64,32 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
// This will be used to cancel the animation whenever we press inside of the scroll view. We don't want to change
// the scroll view gesture's delegate, so we add an additional recognizer to detect this.
@IBAction func callOnPress(_ sender: UITapGestureRecognizer) {
@IBAction func callOnPress(_ sender: UITapGestureRecognizer) -> Void {
self.stopTimer()
}
@IBAction func callOnPan(_ sender: UIPanGestureRecognizer) {
@IBAction func callOnPan(_ sender: UIPanGestureRecognizer) -> Void {
guard let rctsv = self.rctScrollView, let sv = rctsv.scrollView else {
return
}
let translation = sender.translation(in: self).y
if sender.state == .began {
if sv.contentOffset.y < 0 {
sv.contentOffset.y = 0
}
self.initialOffset = sv.contentOffset.y
}
if sender.state == .changed {
sv.contentOffset.y = self.dampenOffset(-translation + self.initialOffset)
if sv.contentOffset.y <= -130, !didImpact {
let generator = UIImpactFeedbackGenerator(style: .light)
generator.impactOccurred()
self.didImpact = true
}
}
@@ -96,7 +97,7 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
if sender.state == .ended {
let velocity = sender.velocity(in: self).y
self.didImpact = false
if sv.contentOffset.y <= -130 {
self.rctRefreshCtrl?.forwarderBeginRefreshing()
return
@@ -107,40 +108,40 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
if abs(velocity) < 250, sv.contentOffset.y >= 0 {
return
}
self.startDecayAnimation(translation, velocity)
}
}
func startDecayAnimation(_ translation: CGFloat, _ velocity: CGFloat) {
guard let sv = self.rctScrollView?.scrollView else {
return
}
var velocity = velocity
self.enableCancelGestureRecognizers()
if velocity > 0 {
velocity = min(velocity, 5000)
} else {
velocity = max(velocity, -5000)
}
var animTranslation = -translation
self.animTimer = Timer.scheduledTimer(withTimeInterval: 1.0 / 120, repeats: true) { _ in
self.animTimer = Timer.scheduledTimer(withTimeInterval: 1.0 / 120, repeats: true) { timer in
velocity *= 0.9875
animTranslation = (-velocity / 120) + animTranslation
let nextOffset = self.dampenOffset(animTranslation + self.initialOffset)
if nextOffset <= 0 {
if self.initialOffset <= 1 {
self.scrollToOffset(0)
} else {
sv.contentOffset.y = 0
}
self.stopTimer()
return
} else {
@@ -152,60 +153,61 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
}
}
}
func dampenOffset(_ offset: CGFloat) -> CGFloat {
if offset < 0 {
return offset - (offset * 0.55)
}
return offset
}
func tryFindScrollView() {
guard let scrollViewTag = scrollViewTag else {
return
}
// Before we switch to a different scrollview, we always want to remove the cancel gesture recognizer.
// Otherwise we might end up with duplicates when we switch back to that scrollview.
self.removeCancelGestureRecognizers()
self.rctScrollView = self.appContext?
.findView(withTag: scrollViewTag, ofType: RCTScrollView.self)
self.rctRefreshCtrl = self.rctScrollView?.scrollView.refreshControl as? RCTRefreshControl
self.addCancelGestureRecognizers()
}
func addCancelGestureRecognizers() {
self.cancelGestureRecognizers?.forEach { r in
self.rctScrollView?.scrollView?.addGestureRecognizer(r)
}
}
func removeCancelGestureRecognizers() {
self.cancelGestureRecognizers?.forEach { r in
self.rctScrollView?.scrollView?.removeGestureRecognizer(r)
}
}
func enableCancelGestureRecognizers() {
self.cancelGestureRecognizers?.forEach { r in
r.isEnabled = true
}
}
func disableCancelGestureRecognizers() {
self.cancelGestureRecognizers?.forEach { r in
r.isEnabled = false
}
}
func scrollToOffset(_ offset: Int, animated: Bool = true) {
func scrollToOffset(_ offset: Int, animated: Bool = true) -> Void {
self.rctScrollView?.scroll(toOffset: CGPoint(x: 0, y: offset), animated: animated)
}
func stopTimer() {
func stopTimer() -> Void {
self.disableCancelGestureRecognizers()
self.animTimer?.invalidate()
self.animTimer = nil
+11 -11
View File
@@ -1,6 +1,6 @@
{
"name": "bsky.app",
"version": "1.91.0",
"version": "1.88.0",
"private": true,
"engines": {
"node": ">=18"
@@ -29,12 +29,9 @@
"test-ci": "NODE_ENV=test jest --ci --forceExit --reporters=default --reporters=jest-junit",
"test-coverage": "NODE_ENV=test jest --coverage",
"lint": "eslint --cache --ext .js,.jsx,.ts,.tsx src",
"lint-native": "swiftlint ./modules && ktlint ./modules",
"lint-native:fix": "swiftlint --fix ./modules && ktlint --format ./modules",
"typecheck": "tsc --project ./tsconfig.check.json",
"e2e:mock-server": "NODE_ENV=development ./jest/dev-infra/with-test-redis-and-db.sh ts-node --project tsconfig.e2e.json __e2e__/mock-server.ts",
"e2e:mock-server": "./jest/dev-infra/with-test-redis-and-db.sh ts-node --project tsconfig.e2e.json __e2e__/mock-server.ts",
"e2e:metro": "EXPO_PUBLIC_ENV=e2e NODE_ENV=test RN_SRC_EXT=e2e.ts,e2e.tsx expo run:ios",
"e2e:metro-android": "EXPO_PUBLIC_ENV=e2e NODE_ENV=test RN_SRC_EXT=e2e.ts,e2e.tsx expo run:android",
"e2e:run": "maestro test __e2e__",
"perf:test": "NODE_ENV=test maestro test",
"perf:test:run": "NODE_ENV=test maestro test __e2e__/perf-test.yml",
@@ -52,7 +49,7 @@
"open-analyzer": "EXPO_PUBLIC_OPEN_ANALYZER=1 yarn build-web"
},
"dependencies": {
"@atproto/api": "0.13.5",
"@atproto/api": "^0.12.23",
"@bam.tech/react-native-image-resizer": "^3.0.4",
"@braintree/sanitize-url": "^6.0.2",
"@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
@@ -139,11 +136,10 @@
"expo-system-ui": "~3.0.4",
"expo-task-manager": "~11.8.1",
"expo-updates": "~0.25.14",
"expo-video": "https://github.com/bluesky-social/expo/raw/expo-video-1.2.4-patch/packages/expo-video/expo-video-v1.2.4-1.tgz",
"expo-video": "^1.1.10",
"expo-web-browser": "~13.0.3",
"fast-text-encoding": "^1.0.6",
"history": "^5.3.0",
"hls.js": "^1.5.11",
"js-sha256": "^0.9.0",
"jwt-decode": "^4.0.0",
"lande": "^1.0.10",
@@ -169,18 +165,19 @@
"react-avatar-editor": "^13.0.0",
"react-compiler-runtime": "file:./lib/react-compiler-runtime",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.13",
"react-keyed-flatten-children": "^3.0.0",
"react-native": "0.74.1",
"react-native-compressor": "^1.8.24",
"react-native-date-picker": "^4.4.2",
"react-native-drawer-layout": "^4.0.0-alpha.3",
"react-native-fetch-api": "^3.0.0",
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "~2.16.2",
"react-native-get-random-values": "~1.11.0",
"react-native-image-crop-picker": "0.40.3",
"react-native-ios-context-menu": "^1.15.3",
"react-native-keyboard-controller": "^1.12.1",
"react-native-mmkv": "^2.12.2",
"react-native-pager-view": "6.2.3",
"react-native-picker-select": "^9.1.3",
"react-native-progress": "bluesky-social/react-native-progress",
@@ -198,17 +195,20 @@
"react-native-web-webview": "^1.0.2",
"react-native-webview": "13.10.2",
"react-responsive": "^9.0.2",
"react-server-dom-webpack": "19.0.0-canary-adb717393-20240411",
"react-textarea-autosize": "^8.5.3",
"rn-fetch-blob": "^0.12.0",
"rn-tourguide": "bluesky-social/rn-tourguide",
"sentry-expo": "~7.0.1",
"statsig-react-native-expo": "^4.6.1",
"tippy.js": "^6.3.7",
"tlds": "^1.234.0",
"web-streams-polyfill": "3.1.1",
"zeego": "^1.6.2",
"zod": "^3.20.2"
},
"devDependencies": {
"@atproto/dev-env": "^0.3.39",
"@atproto/dev-env": "^0.3.5",
"@babel/core": "^7.23.2",
"@babel/preset-env": "^7.20.0",
"@babel/runtime": "^7.20.0",
@@ -270,7 +270,7 @@
"react-scripts": "^5.0.1",
"react-test-renderer": "18.2.0",
"ts-node": "^10.9.1",
"typescript": "^5.5.4",
"typescript": "^5.3.3",
"url-loader": "^4.1.1",
"webpack": "^5.75.0",
"webpack-bundle-analyzer": "^4.10.1",
+28
View File
@@ -0,0 +1,28 @@
diff --git a/node_modules/@atproto/lexicon/dist/validators/complex.js b/node_modules/@atproto/lexicon/dist/validators/complex.js
index 32d7798..9d688b7 100644
--- a/node_modules/@atproto/lexicon/dist/validators/complex.js
+++ b/node_modules/@atproto/lexicon/dist/validators/complex.js
@@ -113,7 +113,22 @@ function object(lexicons, path, def, value) {
if (value[key] === null && nullableProps.has(key)) {
continue;
}
- const propDef = def.properties[key];
+ const propDef = def.properties[key]
+ if (typeof value[key] === 'undefined' && !requiredProps.has(key)) {
+ // Fast path for non-required undefined props.
+ if (
+ propDef.type === 'integer' ||
+ propDef.type === 'boolean' ||
+ propDef.type === 'string'
+ ) {
+ if (typeof propDef.default === 'undefined') {
+ continue
+ }
+ } else {
+ // Other types have no defaults.
+ continue
+ }
+ }
const propPath = `${path}/${key}`;
const validated = (0, util_1.validateOneOf)(lexicons, propPath, propDef, value[key]);
const propValue = validated.success ? validated.value : value[key];
-25
View File
@@ -12,28 +12,3 @@ index bb74e80..0aa0202 100644
Map<String, Object> constants = new HashMap<>(3);
constants.put(MODULES_CONSTANTS_KEY, new HashMap<>());
diff --git a/node_modules/expo-modules-core/build/uuid/uuid.js b/node_modules/expo-modules-core/build/uuid/uuid.js
index 109d3fe..c421931 100644
--- a/node_modules/expo-modules-core/build/uuid/uuid.js
+++ b/node_modules/expo-modules-core/build/uuid/uuid.js
@@ -1,5 +1,7 @@
import bytesToUuid from './lib/bytesToUuid';
import { Uuidv5Namespace } from './uuid.types';
+import { ensureNativeModulesAreInstalled } from '../ensureNativeModulesAreInstalled';
+ensureNativeModulesAreInstalled();
const nativeUuidv4 = globalThis?.expo?.uuidv4;
const nativeUuidv5 = globalThis?.expo?.uuidv5;
function uuidv4() {
diff --git a/node_modules/expo-modules-core/ios/Core/SharedObjects/SharedObjectRegistry.swift b/node_modules/expo-modules-core/ios/Core/SharedObjects/SharedObjectRegistry.swift
index ee2268a..4851b67 100644
--- a/node_modules/expo-modules-core/ios/Core/SharedObjects/SharedObjectRegistry.swift
+++ b/node_modules/expo-modules-core/ios/Core/SharedObjects/SharedObjectRegistry.swift
@@ -173,7 +173,7 @@ public final class SharedObjectRegistry {
}
internal func clear() {
- Self.lockQueue.async {
+ Self.lockQueue.sync {
self.pairs.removeAll()
}
}
@@ -207,3 +207,31 @@ index 88b3fdf..2488ebc 100644
const { layout, entering, exiting, sharedTransitionTag } = this.props;
if (
diff --git a/node_modules/react-native-reanimated/lib/module/reanimated2/index.js b/node_modules/react-native-reanimated/lib/module/reanimated2/index.js
index ac9be5d..86d4605 100644
--- a/node_modules/react-native-reanimated/lib/module/reanimated2/index.js
+++ b/node_modules/react-native-reanimated/lib/module/reanimated2/index.js
@@ -47,4 +47,5 @@ export { LayoutAnimationConfig } from './component/LayoutAnimationConfig';
export { PerformanceMonitor } from './component/PerformanceMonitor';
export { startMapper, stopMapper } from './mappers';
export { startScreenTransition, finishScreenTransition, ScreenTransition } from './screenTransition';
+export { isReducedMotion } from './PlatformChecker';
//# sourceMappingURL=index.js.map
diff --git a/node_modules/react-native-reanimated/lib/typescript/reanimated2/index.d.ts b/node_modules/react-native-reanimated/lib/typescript/reanimated2/index.d.ts
index f01dc57..161ef22 100644
--- a/node_modules/react-native-reanimated/lib/typescript/reanimated2/index.d.ts
+++ b/node_modules/react-native-reanimated/lib/typescript/reanimated2/index.d.ts
@@ -36,3 +36,4 @@ export type { FlatListPropsWithLayout } from './component/FlatList';
export { startMapper, stopMapper } from './mappers';
export { startScreenTransition, finishScreenTransition, ScreenTransition, } from './screenTransition';
export type { AnimatedScreenTransition, GoBackGesture, ScreenTransitionConfig, } from './screenTransition';
+export { isReducedMotion } from './PlatformChecker';
diff --git a/node_modules/react-native-reanimated/src/reanimated2/index.ts b/node_modules/react-native-reanimated/src/reanimated2/index.ts
index 5885fa1..a3c693f 100644
--- a/node_modules/react-native-reanimated/src/reanimated2/index.ts
+++ b/node_modules/react-native-reanimated/src/reanimated2/index.ts
@@ -284,3 +284,4 @@ export type {
GoBackGesture,
ScreenTransitionConfig,
} from './screenTransition';
+export { isReducedMotion } from './PlatformChecker';
@@ -0,0 +1,683 @@
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js
index dcb23c5..9f5ee0b 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js
@@ -128,7 +128,7 @@ var chunkCache = new Map();
function requireAsyncModule(id) {
// We've already loaded all the chunks. We can require the module.
- var promise = __webpack_require__(id);
+ var promise = __bsky_require__(id);
if (typeof promise.then !== 'function') {
// This wasn't a promise after all.
@@ -195,7 +195,7 @@ function preloadModule(metadata) {
// Increase priority if necessary.
function requireModule(metadata) {
- var moduleExports = __webpack_require__(metadata[ID]);
+ var moduleExports = __bsky_require__(metadata[ID]);
if (isAsyncImport(metadata)) {
if (typeof moduleExports.then !== 'function') ; else if (moduleExports.status === 'fulfilled') {
@@ -227,9 +227,9 @@ var chunkMap = new Map();
* of chunks that come from Flight and may not be known to the webpack runtime
*/
-var webpackGetChunkFilename = __webpack_require__.u;
+var webpackGetChunkFilename = __bsky_require__.u;
-__webpack_require__.u = function (chunkId) {
+__bsky_require__.u = function (chunkId) {
var flightChunk = chunkMap.get(chunkId);
if (flightChunk !== undefined) {
@@ -241,7 +241,7 @@ __webpack_require__.u = function (chunkId) {
function loadChunk(chunkId, filename) {
chunkMap.set(chunkId, filename);
- return __webpack_chunk_load__(chunkId);
+ return __bsky_chunk_load__(chunkId);
}
var ReactDOMSharedInternals = ReactDOM.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.production.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.production.js
index 6ad0195..a400d00 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.production.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.production.js
@@ -81,7 +81,7 @@ const chunkCache = new Map();
function requireAsyncModule(id) {
// We've already loaded all the chunks. We can require the module.
- const promise = __webpack_require__(id);
+ const promise = __bsky_require__(id);
if (typeof promise.then !== 'function') {
// This wasn't a promise after all.
@@ -148,7 +148,7 @@ function preloadModule(metadata) {
// Increase priority if necessary.
function requireModule(metadata) {
- let moduleExports = __webpack_require__(metadata[ID]);
+ let moduleExports = __bsky_require__(metadata[ID]);
if (isAsyncImport(metadata)) {
if (typeof moduleExports.then !== 'function') ; else if (moduleExports.status === 'fulfilled') {
@@ -180,9 +180,9 @@ const chunkMap = new Map();
* of chunks that come from Flight and may not be known to the webpack runtime
*/
-const webpackGetChunkFilename = __webpack_require__.u;
+const webpackGetChunkFilename = __bsky_require__.u;
-__webpack_require__.u = function (chunkId) {
+__bsky_require__.u = function (chunkId) {
const flightChunk = chunkMap.get(chunkId);
if (flightChunk !== undefined) {
@@ -194,7 +194,7 @@ __webpack_require__.u = function (chunkId) {
function loadChunk(chunkId, filename) {
chunkMap.set(chunkId, filename);
- return __webpack_chunk_load__(chunkId);
+ return __bsky_chunk_load__(chunkId);
}
const ReactDOMSharedInternals = ReactDOM.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.production.min.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.production.min.js
index 8573fab..1b34e95 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.production.min.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.production.min.js
@@ -8,8 +8,8 @@
LICENSE file in the root directory of this source tree.
*/
'use strict';var u=require("react-dom"),v={stream:!0};function z(a,b){if(a){var c=a[b[0]];if(a=c[b[2]])c=a.name;else{a=c["*"];if(!a)throw Error('Could not find the module "'+b[0]+'" in the React SSR Manifest. This is probably a bug in the React Server Components bundler.');c=b[2]}return 4===b.length?[a.id,a.chunks,c,1]:[a.id,a.chunks,c]}return b}var A=new Map;
-function B(a){var b=__webpack_require__(a);if("function"!==typeof b.then||"fulfilled"===b.status)return null;b.then(function(c){b.status="fulfilled";b.value=c},function(c){b.status="rejected";b.reason=c});return b}function C(){}
-function D(a){for(var b=a[1],c=[],e=0;e<b.length;){var m=b[e++],k=b[e++],g=A.get(m);void 0===g?(E.set(m,k),k=__webpack_chunk_load__(m),c.push(k),g=A.set.bind(A,m,null),k.then(g,C),A.set(m,k)):null!==g&&c.push(g)}return 4===a.length?0===c.length?B(a[0]):Promise.all(c).then(function(){return B(a[0])}):0<c.length?Promise.all(c):null}var E=new Map,aa=__webpack_require__.u;__webpack_require__.u=function(a){var b=E.get(a);return void 0!==b?b:aa(a)};
+function B(a){var b=__bsky_require__(a);if("function"!==typeof b.then||"fulfilled"===b.status)return null;b.then(function(c){b.status="fulfilled";b.value=c},function(c){b.status="rejected";b.reason=c});return b}function C(){}
+function D(a){for(var b=a[1],c=[],e=0;e<b.length;){var m=b[e++],k=b[e++],g=A.get(m);void 0===g?(E.set(m,k),k=__bsky_chunk_load__(m),c.push(k),g=A.set.bind(A,m,null),k.then(g,C),A.set(m,k)):null!==g&&c.push(g)}return 4===a.length?0===c.length?B(a[0]):Promise.all(c).then(function(){return B(a[0])}):0<c.length?Promise.all(c):null}var E=new Map,aa=__bsky_require__.u;__bsky_require__.u=function(a){var b=E.get(a);return void 0!==b?b:aa(a)};
var ba=u.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,G=Symbol.for("react.element"),H=Symbol.for("react.lazy"),I=Symbol.iterator;function ca(a){if(null===a||"object"!==typeof a)return null;a=I&&a[I]||a["@@iterator"];return"function"===typeof a?a:null}var da=Array.isArray,J=Object.getPrototypeOf;function K(a,b){var c=a.length;a.push(b);return c}var ea=Object.prototype,L=new WeakMap;
function fa(a){return Number.isFinite(a)?0===a&&-Infinity===1/a?"$-0":a:Infinity===a?"$Infinity":-Infinity===a?"$-Infinity":"$NaN"}
function ha(a,b,c,e,m){function k(q,d){if(null===d)return null;if("object"===typeof d){switch(d.$$typeof){case G:if(void 0===c)throw Error("React Element cannot be passed to Server Functions from the Client without a temporary reference set. Pass a TemporaryReferenceSet to the options.");return"$T"+K(c,d).toString(16);case H:q=d._payload;var f=d._init;null===l&&(l=new FormData);h++;try{var p=f(q),n=g++,t=JSON.stringify(p,k);l.append(b+n,t);return"$"+n.toString(16)}catch(r){if("object"===typeof r&&
@@ -21,7 +21,7 @@ function M(a,b,c,e){this.status=a;this.value=b;this.reason=c;this._response=e}M.
function ma(a){switch(a.status){case "resolved_model":N(a);break;case "resolved_module":O(a)}switch(a.status){case "fulfilled":return a.value;case "pending":case "blocked":case "cyclic":throw a;default:throw a.reason;}}function P(a,b){for(var c=0;c<a.length;c++)(0,a[c])(b)}function Q(a,b,c){switch(a.status){case "fulfilled":P(b,a.value);break;case "pending":case "blocked":case "cyclic":a.value=b;a.reason=c;break;case "rejected":c&&P(c,a.reason)}}
function R(a,b){if("pending"===a.status||"blocked"===a.status){var c=a.reason;a.status="rejected";a.reason=b;null!==c&&P(c,b)}}function S(a,b){if("pending"===a.status||"blocked"===a.status){var c=a.value,e=a.reason;a.status="resolved_module";a.value=b;null!==c&&(O(a),Q(a,c,e))}}var T=null,U=null;
function N(a){var b=T,c=U;T=a;U=null;var e=a.value;a.status="cyclic";a.value=null;a.reason=null;try{var m=JSON.parse(e,a._response._fromJSON);if(null!==U&&0<U.deps)U.value=m,a.status="blocked",a.value=null,a.reason=null;else{var k=a.value;a.status="fulfilled";a.value=m;null!==k&&P(k,m)}}catch(g){a.status="rejected",a.reason=g}finally{T=b,U=c}}
-function O(a){try{var b=a.value,c=__webpack_require__(b[0]);if(4===b.length&&"function"===typeof c.then)if("fulfilled"===c.status)c=c.value;else throw c.reason;var e="*"===b[2]?c:""===b[2]?c.__esModule?c.default:c:c[b[2]];a.status="fulfilled";a.value=e}catch(m){a.status="rejected",a.reason=m}}function V(a,b){a._chunks.forEach(function(c){"pending"===c.status&&R(c,b)})}function W(a,b){var c=a._chunks,e=c.get(b);e||(e=new M("pending",null,null,a),c.set(b,e));return e}
+function O(a){try{var b=a.value,c=__bsky_require__(b[0]);if(4===b.length&&"function"===typeof c.then)if("fulfilled"===c.status)c=c.value;else throw c.reason;var e="*"===b[2]?c:""===b[2]?c.__esModule?c.default:c:c[b[2]];a.status="fulfilled";a.value=e}catch(m){a.status="rejected",a.reason=m}}function V(a,b){a._chunks.forEach(function(c){"pending"===c.status&&R(c,b)})}function W(a,b){var c=a._chunks,e=c.get(b);e||(e=new M("pending",null,null,a),c.set(b,e));return e}
function na(a,b,c,e,m,k){if(U){var g=U;e||g.deps++}else g=U={deps:e?0:1,value:null};return function(h){b[c]=k(m,h);""===c&&null===g.value&&(g.value=b[c]);g.deps--;0===g.deps&&"blocked"===a.status&&(h=a.value,a.status="fulfilled",a.value=g.value,null!==h&&P(h,g.value))}}function oa(a){return function(b){return R(a,b)}}
function pa(a,b){function c(){var m=Array.prototype.slice.call(arguments),k=b.bound;return k?"fulfilled"===k.status?e(b.id,k.value.concat(m)):Promise.resolve(k).then(function(g){return e(b.id,g.concat(m))}):e(b.id,m)}var e=a._callServer;L.set(c,b);return c}
function X(a,b,c,e,m){b=W(a,b);switch(b.status){case "resolved_model":N(b);break;case "resolved_module":O(b)}switch(b.status){case "fulfilled":return m(a,b.value);case "pending":case "blocked":case "cyclic":var k=T;b.then(na(k,c,e,"cyclic"===b.status,a,m),oa(k));return null;default:throw b.reason;}}function qa(a,b){return new Map(b)}function ra(a,b){return new Set(b)}function sa(a,b){a=new FormData;for(var c=0;c<b.length;c++)a.append(b[c][0],b[c][1]);return a}function ta(a,b){return b}
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.development.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.development.js
index 993d7cd..59a6c24 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.development.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.development.js
@@ -139,7 +139,7 @@ var chunkCache = new Map();
function requireAsyncModule(id) {
// We've already loaded all the chunks. We can require the module.
- var promise = __webpack_require__(id);
+ var promise = __bsky_require__(id);
if (typeof promise.then !== 'function') {
// This wasn't a promise after all.
@@ -206,7 +206,7 @@ function preloadModule(metadata) {
// Increase priority if necessary.
function requireModule(metadata) {
- var moduleExports = __webpack_require__(metadata[ID]);
+ var moduleExports = __bsky_require__(metadata[ID]);
if (isAsyncImport(metadata)) {
if (typeof moduleExports.then !== 'function') ; else if (moduleExports.status === 'fulfilled') {
@@ -233,7 +233,7 @@ function requireModule(metadata) {
}
function loadChunk(chunkId, filename) {
- return __webpack_chunk_load__(chunkId);
+ return __bsky_chunk_load__(chunkId);
}
function prepareDestinationWithChunks(moduleLoading, // Chunks are double-indexed [..., idx, filenamex, idy, filenamey, ...]
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.production.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.production.js
index 83b0367..f5b0e0b 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.production.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.production.js
@@ -91,7 +91,7 @@ const chunkCache = new Map();
function requireAsyncModule(id) {
// We've already loaded all the chunks. We can require the module.
- const promise = __webpack_require__(id);
+ const promise = __bsky_require__(id);
if (typeof promise.then !== 'function') {
// This wasn't a promise after all.
@@ -158,7 +158,7 @@ function preloadModule(metadata) {
// Increase priority if necessary.
function requireModule(metadata) {
- let moduleExports = __webpack_require__(metadata[ID]);
+ let moduleExports = __bsky_require__(metadata[ID]);
if (isAsyncImport(metadata)) {
if (typeof moduleExports.then !== 'function') ; else if (moduleExports.status === 'fulfilled') {
@@ -185,7 +185,7 @@ function requireModule(metadata) {
}
function loadChunk(chunkId, filename) {
- return __webpack_chunk_load__(chunkId);
+ return __bsky_chunk_load__(chunkId);
}
function prepareDestinationWithChunks(moduleLoading, // Chunks are double-indexed [..., idx, filenamex, idy, filenamey, ...]
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.production.min.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.production.min.js
index c00ccd0..661d3a2 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.production.min.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.production.min.js
@@ -8,8 +8,8 @@
LICENSE file in the root directory of this source tree.
*/
'use strict';var aa=require("react-dom"),ba={stream:!0};function ca(a,b){if(a){var c=a[b[0]];if(a=c[b[2]])c=a.name;else{a=c["*"];if(!a)throw Error('Could not find the module "'+b[0]+'" in the React SSR Manifest. This is probably a bug in the React Server Components bundler.');c=b[2]}return 4===b.length?[a.id,a.chunks,c,1]:[a.id,a.chunks,c]}return b}var u=new Map;
-function v(a){var b=__webpack_require__(a);if("function"!==typeof b.then||"fulfilled"===b.status)return null;b.then(function(c){b.status="fulfilled";b.value=c},function(c){b.status="rejected";b.reason=c});return b}function da(){}
-function ea(a){for(var b=a[1],c=[],d=0;d<b.length;){var f=b[d++];b[d++];var g=u.get(f);if(void 0===g){g=__webpack_chunk_load__(f);c.push(g);var l=u.set.bind(u,f,null);g.then(l,da);u.set(f,g)}else null!==g&&c.push(g)}return 4===a.length?0===c.length?v(a[0]):Promise.all(c).then(function(){return v(a[0])}):0<c.length?Promise.all(c):null}
+function v(a){var b=__bsky_require__(a);if("function"!==typeof b.then||"fulfilled"===b.status)return null;b.then(function(c){b.status="fulfilled";b.value=c},function(c){b.status="rejected";b.reason=c});return b}function da(){}
+function ea(a){for(var b=a[1],c=[],d=0;d<b.length;){var f=b[d++];b[d++];var g=u.get(f);if(void 0===g){g=__bsky_chunk_load__(f);c.push(g);var l=u.set.bind(u,f,null);g.then(l,da);u.set(f,g)}else null!==g&&c.push(g)}return 4===a.length?0===c.length?v(a[0]):Promise.all(c).then(function(){return v(a[0])}):0<c.length?Promise.all(c):null}
function fa(a,b,c){if(null!==a)for(var d=1;d<b.length;d+=2){var f=c,g=w.d,l=g.X,k=a.prefix+b[d];var m=a.crossOrigin;m="string"===typeof m?"use-credentials"===m?m:"":void 0;l.call(g,k,{crossOrigin:m,nonce:f})}}var w=aa.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,A=Symbol.for("react.element"),B=Symbol.for("react.lazy"),C=Symbol.iterator;function ha(a){if(null===a||"object"!==typeof a)return null;a=C&&a[C]||a["@@iterator"];return"function"===typeof a?a:null}var ia=Array.isArray,D=Object.getPrototypeOf;
function E(a,b){var c=a.length;a.push(b);return c}var ja=Object.prototype,F=new WeakMap;function ka(a){return Number.isFinite(a)?0===a&&-Infinity===1/a?"$-0":a:Infinity===a?"$Infinity":-Infinity===a?"$-Infinity":"$NaN"}
function H(a,b,c,d,f){function g(q,e){if(null===e)return null;if("object"===typeof e){switch(e.$$typeof){case A:if(void 0===c)throw Error("React Element cannot be passed to Server Functions from the Client without a temporary reference set. Pass a TemporaryReferenceSet to the options.");return"$T"+E(c,e).toString(16);case B:q=e._payload;var h=e._init;null===m&&(m=new FormData);k++;try{var p=h(q),n=l++,t=JSON.stringify(p,g);m.append(b+n,t);return"$"+n.toString(16)}catch(r){if("object"===typeof r&&
@@ -26,7 +26,7 @@ function M(a,b,c,d){this.status=a;this.value=b;this.reason=c;this._response=d}M.
function ta(a){switch(a.status){case "resolved_model":N(a);break;case "resolved_module":O(a)}switch(a.status){case "fulfilled":return a.value;case "pending":case "blocked":case "cyclic":throw a;default:throw a.reason;}}function P(a,b){for(var c=0;c<a.length;c++)(0,a[c])(b)}function Q(a,b,c){switch(a.status){case "fulfilled":P(b,a.value);break;case "pending":case "blocked":case "cyclic":a.value=b;a.reason=c;break;case "rejected":c&&P(c,a.reason)}}
function R(a,b){if("pending"===a.status||"blocked"===a.status){var c=a.reason;a.status="rejected";a.reason=b;null!==c&&P(c,b)}}function S(a,b){if("pending"===a.status||"blocked"===a.status){var c=a.value,d=a.reason;a.status="resolved_module";a.value=b;null!==c&&(O(a),Q(a,c,d))}}var T=null,U=null;
function N(a){var b=T,c=U;T=a;U=null;var d=a.value;a.status="cyclic";a.value=null;a.reason=null;try{var f=JSON.parse(d,a._response._fromJSON);if(null!==U&&0<U.deps)U.value=f,a.status="blocked",a.value=null,a.reason=null;else{var g=a.value;a.status="fulfilled";a.value=f;null!==g&&P(g,f)}}catch(l){a.status="rejected",a.reason=l}finally{T=b,U=c}}
-function O(a){try{var b=a.value,c=__webpack_require__(b[0]);if(4===b.length&&"function"===typeof c.then)if("fulfilled"===c.status)c=c.value;else throw c.reason;var d="*"===b[2]?c:""===b[2]?c.__esModule?c.default:c:c[b[2]];a.status="fulfilled";a.value=d}catch(f){a.status="rejected",a.reason=f}}function V(a,b){a._chunks.forEach(function(c){"pending"===c.status&&R(c,b)})}function W(a,b){var c=a._chunks,d=c.get(b);d||(d=new M("pending",null,null,a),c.set(b,d));return d}
+function O(a){try{var b=a.value,c=__bsky_require__(b[0]);if(4===b.length&&"function"===typeof c.then)if("fulfilled"===c.status)c=c.value;else throw c.reason;var d="*"===b[2]?c:""===b[2]?c.__esModule?c.default:c:c[b[2]];a.status="fulfilled";a.value=d}catch(f){a.status="rejected",a.reason=f}}function V(a,b){a._chunks.forEach(function(c){"pending"===c.status&&R(c,b)})}function W(a,b){var c=a._chunks,d=c.get(b);d||(d=new M("pending",null,null,a),c.set(b,d));return d}
function ua(a,b,c,d,f,g){if(U){var l=U;d||l.deps++}else l=U={deps:d?0:1,value:null};return function(k){b[c]=g(f,k);""===c&&null===l.value&&(l.value=b[c]);l.deps--;0===l.deps&&"blocked"===a.status&&(k=a.value,a.status="fulfilled",a.value=l.value,null!==k&&P(k,l.value))}}function va(a){return function(b){return R(a,b)}}
function wa(a,b){function c(){var f=Array.prototype.slice.call(arguments),g=b.bound;return g?"fulfilled"===g.status?d(b.id,g.value.concat(f)):Promise.resolve(g).then(function(l){return d(b.id,l.concat(f))}):d(b.id,f)}var d=a._callServer;K(c,b,a._encodeFormAction);return c}
function X(a,b,c,d,f){b=W(a,b);switch(b.status){case "resolved_model":N(b);break;case "resolved_module":O(b)}switch(b.status){case "fulfilled":return f(a,b.value);case "pending":case "blocked":case "cyclic":var g=T;b.then(ua(g,c,d,"cyclic"===b.status,a,f),va(g));return null;default:throw b.reason;}}function xa(a,b){return new Map(b)}function ya(a,b){return new Set(b)}function za(a,b){a=new FormData;for(var c=0;c<b.length;c++)a.append(b[c][0],b[c][1]);return a}function Aa(a,b){return b}
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.development.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.development.js
index 6a03153..f9143a7 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.development.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.development.js
@@ -140,7 +140,7 @@ var chunkCache = new Map();
function requireAsyncModule(id) {
// We've already loaded all the chunks. We can require the module.
- var promise = __webpack_require__(id);
+ var promise = __bsky_require__(id);
if (typeof promise.then !== 'function') {
// This wasn't a promise after all.
@@ -207,7 +207,7 @@ function preloadModule(metadata) {
// Increase priority if necessary.
function requireModule(metadata) {
- var moduleExports = __webpack_require__(metadata[ID]);
+ var moduleExports = __bsky_require__(metadata[ID]);
if (isAsyncImport(metadata)) {
if (typeof moduleExports.then !== 'function') ; else if (moduleExports.status === 'fulfilled') {
@@ -234,7 +234,7 @@ function requireModule(metadata) {
}
function loadChunk(chunkId, filename) {
- return __webpack_chunk_load__(chunkId);
+ return __bsky_chunk_load__(chunkId);
}
function prepareDestinationWithChunks(moduleLoading, // Chunks are double-indexed [..., idx, filenamex, idy, filenamey, ...]
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.production.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.production.js
index 62abbfd..f5f1630 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.production.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.production.js
@@ -92,7 +92,7 @@ const chunkCache = new Map();
function requireAsyncModule(id) {
// We've already loaded all the chunks. We can require the module.
- const promise = __webpack_require__(id);
+ const promise = __bsky_require__(id);
if (typeof promise.then !== 'function') {
// This wasn't a promise after all.
@@ -159,7 +159,7 @@ function preloadModule(metadata) {
// Increase priority if necessary.
function requireModule(metadata) {
- let moduleExports = __webpack_require__(metadata[ID]);
+ let moduleExports = __bsky_require__(metadata[ID]);
if (isAsyncImport(metadata)) {
if (typeof moduleExports.then !== 'function') ; else if (moduleExports.status === 'fulfilled') {
@@ -186,7 +186,7 @@ function requireModule(metadata) {
}
function loadChunk(chunkId, filename) {
- return __webpack_chunk_load__(chunkId);
+ return __bsky_chunk_load__(chunkId);
}
function prepareDestinationWithChunks(moduleLoading, // Chunks are double-indexed [..., idx, filenamex, idy, filenamey, ...]
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.production.min.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.production.min.js
index 6c4162e..d26ec84 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.production.min.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.production.min.js
@@ -8,8 +8,8 @@
LICENSE file in the root directory of this source tree.
*/
'use strict';var r=require("util"),t=require("react-dom"),aa={stream:!0};function ba(a,b){if(a){var c=a[b[0]];if(a=c[b[2]])c=a.name;else{a=c["*"];if(!a)throw Error('Could not find the module "'+b[0]+'" in the React SSR Manifest. This is probably a bug in the React Server Components bundler.');c=b[2]}return 4===b.length?[a.id,a.chunks,c,1]:[a.id,a.chunks,c]}return b}var u=new Map;
-function x(a){var b=__webpack_require__(a);if("function"!==typeof b.then||"fulfilled"===b.status)return null;b.then(function(c){b.status="fulfilled";b.value=c},function(c){b.status="rejected";b.reason=c});return b}function ca(){}
-function da(a){for(var b=a[1],c=[],d=0;d<b.length;){var f=b[d++];b[d++];var g=u.get(f);if(void 0===g){g=__webpack_chunk_load__(f);c.push(g);var h=u.set.bind(u,f,null);g.then(h,ca);u.set(f,g)}else null!==g&&c.push(g)}return 4===a.length?0===c.length?x(a[0]):Promise.all(c).then(function(){return x(a[0])}):0<c.length?Promise.all(c):null}
+function x(a){var b=__bsky_require__(a);if("function"!==typeof b.then||"fulfilled"===b.status)return null;b.then(function(c){b.status="fulfilled";b.value=c},function(c){b.status="rejected";b.reason=c});return b}function ca(){}
+function da(a){for(var b=a[1],c=[],d=0;d<b.length;){var f=b[d++];b[d++];var g=u.get(f);if(void 0===g){g=__bsky_chunk_load__(f);c.push(g);var h=u.set.bind(u,f,null);g.then(h,ca);u.set(f,g)}else null!==g&&c.push(g)}return 4===a.length?0===c.length?x(a[0]):Promise.all(c).then(function(){return x(a[0])}):0<c.length?Promise.all(c):null}
function ea(a,b,c){if(null!==a)for(var d=1;d<b.length;d+=2){var f=c,g=y.d,h=g.X,l=a.prefix+b[d];var e=a.crossOrigin;e="string"===typeof e?"use-credentials"===e?e:"":void 0;h.call(g,l,{crossOrigin:e,nonce:f})}}var y=t.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,z=Symbol.for("react.element"),A=Symbol.for("react.lazy"),B=Symbol.iterator;function fa(a){if(null===a||"object"!==typeof a)return null;a=B&&a[B]||a["@@iterator"];return"function"===typeof a?a:null}var ha=Array.isArray,D=Object.getPrototypeOf;
function E(a,b){var c=a.length;a.push(b);return c}var ia=Object.prototype,F=new WeakMap;function ja(a){return Number.isFinite(a)?0===a&&-Infinity===1/a?"$-0":a:Infinity===a?"$Infinity":-Infinity===a?"$-Infinity":"$NaN"}
function ka(a,b,c,d,f){function g(n,k){if(null===k)return null;if("object"===typeof k){switch(k.$$typeof){case z:if(void 0===c)throw Error("React Element cannot be passed to Server Functions from the Client without a temporary reference set. Pass a TemporaryReferenceSet to the options.");return"$T"+E(c,k).toString(16);case A:n=k._payload;var I=k._init;null===e&&(e=new FormData);l++;try{var m=I(n),p=h++,v=JSON.stringify(m,g);e.append(b+p,v);return"$"+p.toString(16)}catch(q){if("object"===typeof q&&
@@ -26,7 +26,7 @@ function L(a,b,c,d){this.status=a;this.value=b;this.reason=c;this._response=d}L.
function ta(a){switch(a.status){case "resolved_model":M(a);break;case "resolved_module":N(a)}switch(a.status){case "fulfilled":return a.value;case "pending":case "blocked":case "cyclic":throw a;default:throw a.reason;}}function Q(a,b){for(var c=0;c<a.length;c++)(0,a[c])(b)}function R(a,b,c){switch(a.status){case "fulfilled":Q(b,a.value);break;case "pending":case "blocked":case "cyclic":a.value=b;a.reason=c;break;case "rejected":c&&Q(c,a.reason)}}
function S(a,b){if("pending"===a.status||"blocked"===a.status){var c=a.reason;a.status="rejected";a.reason=b;null!==c&&Q(c,b)}}function T(a,b){if("pending"===a.status||"blocked"===a.status){var c=a.value,d=a.reason;a.status="resolved_module";a.value=b;null!==c&&(N(a),R(a,c,d))}}var U=null,V=null;
function M(a){var b=U,c=V;U=a;V=null;var d=a.value;a.status="cyclic";a.value=null;a.reason=null;try{var f=JSON.parse(d,a._response._fromJSON);if(null!==V&&0<V.deps)V.value=f,a.status="blocked",a.value=null,a.reason=null;else{var g=a.value;a.status="fulfilled";a.value=f;null!==g&&Q(g,f)}}catch(h){a.status="rejected",a.reason=h}finally{U=b,V=c}}
-function N(a){try{var b=a.value,c=__webpack_require__(b[0]);if(4===b.length&&"function"===typeof c.then)if("fulfilled"===c.status)c=c.value;else throw c.reason;var d="*"===b[2]?c:""===b[2]?c.__esModule?c.default:c:c[b[2]];a.status="fulfilled";a.value=d}catch(f){a.status="rejected",a.reason=f}}function W(a,b){a._chunks.forEach(function(c){"pending"===c.status&&S(c,b)})}function X(a,b){var c=a._chunks,d=c.get(b);d||(d=new L("pending",null,null,a),c.set(b,d));return d}
+function N(a){try{var b=a.value,c=__bsky_require__(b[0]);if(4===b.length&&"function"===typeof c.then)if("fulfilled"===c.status)c=c.value;else throw c.reason;var d="*"===b[2]?c:""===b[2]?c.__esModule?c.default:c:c[b[2]];a.status="fulfilled";a.value=d}catch(f){a.status="rejected",a.reason=f}}function W(a,b){a._chunks.forEach(function(c){"pending"===c.status&&S(c,b)})}function X(a,b){var c=a._chunks,d=c.get(b);d||(d=new L("pending",null,null,a),c.set(b,d));return d}
function ua(a,b,c,d,f,g){if(V){var h=V;d||h.deps++}else h=V={deps:d?0:1,value:null};return function(l){b[c]=g(f,l);""===c&&null===h.value&&(h.value=b[c]);h.deps--;0===h.deps&&"blocked"===a.status&&(l=a.value,a.status="fulfilled",a.value=h.value,null!==l&&Q(l,h.value))}}function va(a){return function(b){return S(a,b)}}
function wa(a,b){function c(){var f=Array.prototype.slice.call(arguments),g=b.bound;return g?"fulfilled"===g.status?d(b.id,g.value.concat(f)):Promise.resolve(g).then(function(h){return d(b.id,h.concat(f))}):d(b.id,f)}var d=a._callServer;J(c,b,a._encodeFormAction);return c}
function Y(a,b,c,d,f){b=X(a,b);switch(b.status){case "resolved_model":M(b);break;case "resolved_module":N(b)}switch(b.status){case "fulfilled":return f(a,b.value);case "pending":case "blocked":case "cyclic":var g=U;b.then(ua(g,c,d,"cyclic"===b.status,a,f),va(g));return null;default:throw b.reason;}}function xa(a,b){return new Map(b)}function ya(a,b){return new Set(b)}function za(a,b){a=new FormData;for(var c=0;c<b.length;c++)a.append(b[c][0],b[c][1]);return a}function Aa(a,b){return b}
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.development.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.development.js
index 17c270d..74f4ef3 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.development.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.development.js
@@ -3301,7 +3301,7 @@ var chunkCache = new Map();
function requireAsyncModule(id) {
// We've already loaded all the chunks. We can require the module.
- var promise = __webpack_require__(id);
+ var promise = __bsky_require__(id);
if (typeof promise.then !== 'function') {
// This wasn't a promise after all.
@@ -3368,7 +3368,7 @@ function preloadModule(metadata) {
// Increase priority if necessary.
function requireModule(metadata) {
- var moduleExports = __webpack_require__(metadata[ID]);
+ var moduleExports = __bsky_require__(metadata[ID]);
if (isAsyncImport(metadata)) {
if (typeof moduleExports.then !== 'function') ; else if (moduleExports.status === 'fulfilled') {
@@ -3400,9 +3400,9 @@ var chunkMap = new Map();
* of chunks that come from Flight and may not be known to the webpack runtime
*/
-var webpackGetChunkFilename = __webpack_require__.u;
+var webpackGetChunkFilename = __bsky_require__.u;
-__webpack_require__.u = function (chunkId) {
+__bsky_require__.u = function (chunkId) {
var flightChunk = chunkMap.get(chunkId);
if (flightChunk !== undefined) {
@@ -3414,7 +3414,7 @@ __webpack_require__.u = function (chunkId) {
function loadChunk(chunkId, filename) {
chunkMap.set(chunkId, filename);
- return __webpack_chunk_load__(chunkId);
+ return __bsky_chunk_load__(chunkId);
}
// The server acts as a Client of itself when resolving Server References.
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.js
index da256f7..040d06d 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.js
@@ -2650,7 +2650,7 @@ const chunkCache = new Map();
function requireAsyncModule(id) {
// We've already loaded all the chunks. We can require the module.
- const promise = __webpack_require__(id);
+ const promise = __bsky_require__(id);
if (typeof promise.then !== 'function') {
// This wasn't a promise after all.
@@ -2717,7 +2717,7 @@ function preloadModule(metadata) {
// Increase priority if necessary.
function requireModule(metadata) {
- let moduleExports = __webpack_require__(metadata[ID]);
+ let moduleExports = __bsky_require__(metadata[ID]);
if (isAsyncImport(metadata)) {
if (typeof moduleExports.then !== 'function') ; else if (moduleExports.status === 'fulfilled') {
@@ -2749,9 +2749,9 @@ const chunkMap = new Map();
* of chunks that come from Flight and may not be known to the webpack runtime
*/
-const webpackGetChunkFilename = __webpack_require__.u;
+const webpackGetChunkFilename = __bsky_require__.u;
-__webpack_require__.u = function (chunkId) {
+__bsky_require__.u = function (chunkId) {
const flightChunk = chunkMap.get(chunkId);
if (flightChunk !== undefined) {
@@ -2763,7 +2763,7 @@ __webpack_require__.u = function (chunkId) {
function loadChunk(chunkId, filename) {
chunkMap.set(chunkId, filename);
- return __webpack_chunk_load__(chunkId);
+ return __bsky_chunk_load__(chunkId);
}
// The server acts as a Client of itself when resolving Server References.
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.min.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.min.js
index e33cbce..9cd2ef6 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.min.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.production.min.js
@@ -60,9 +60,9 @@ function gb(a){var b=K.H;K.H=Pa;var c=x;F=x=a;try{var e=a.pingedTasks;a.pingedTa
function P(a,b){l=new Uint8Array(2048);n=0;try{for(var c=a.completedImportChunks,e=0;e<c.length;e++)a.pendingChunks--,p(b,c[e]);c.splice(0,e);var d=a.completedHintChunks;for(e=0;e<d.length;e++)p(b,d[e]);d.splice(0,e);var g=a.completedRegularChunks;for(e=0;e<g.length;e++)a.pendingChunks--,p(b,g[e]);g.splice(0,e);var f=a.completedErrorChunks;for(e=0;e<f.length;e++)a.pendingChunks--,p(b,f[e]);f.splice(0,e)}finally{a.flushScheduled=!1,l&&0<n&&(b.enqueue(new Uint8Array(l.buffer,0,n)),l=null,n=0)}0===a.pendingChunks&&
b.close()}function lb(a,b){try{var c=a.abortableTasks;if(0<c.size){a.pendingChunks++;var e=a.nextChunkId++,d=void 0===b?Error("The render was aborted by the server without a reason."):b,g=N(a,d);O(a,e,g,d);c.forEach(function(f){f.status=3;var h=T(e);f=hb(a,f.id,h);a.completedErrorChunks.push(f)});c.clear()}null!==a.destination&&P(a,a.destination)}catch(f){N(a,f),kb(a,f)}}
function mb(a,b){var c="",e=a[b];if(e)c=e.name;else{var d=b.lastIndexOf("#");-1!==d&&(c=b.slice(d+1),e=a[b.slice(0,d)]);if(!e)throw Error('Could not find the module "'+b+'" in the React Server Manifest. This is probably a bug in the React Server Components bundler.');}return[e.id,e.chunks,c]}var nb=new Map;
-function ob(a){var b=__webpack_require__(a);if("function"!==typeof b.then||"fulfilled"===b.status)return null;b.then(function(c){b.status="fulfilled";b.value=c},function(c){b.status="rejected";b.reason=c});return b}function pb(){}
-function qb(a){for(var b=a[1],c=[],e=0;e<b.length;){var d=b[e++],g=b[e++],f=nb.get(d);void 0===f?(rb.set(d,g),g=__webpack_chunk_load__(d),c.push(g),f=nb.set.bind(nb,d,null),g.then(f,pb),nb.set(d,g)):null!==f&&c.push(f)}return 4===a.length?0===c.length?ob(a[0]):Promise.all(c).then(function(){return ob(a[0])}):0<c.length?Promise.all(c):null}
-function W(a){var b=__webpack_require__(a[0]);if(4===a.length&&"function"===typeof b.then)if("fulfilled"===b.status)b=b.value;else throw b.reason;return"*"===a[2]?b:""===a[2]?b.__esModule?b.default:b:b[a[2]]}var rb=new Map,sb=__webpack_require__.u;__webpack_require__.u=function(a){var b=rb.get(a);return void 0!==b?b:sb(a)};function tb(a,b,c,e){this.status=a;this.value=b;this.reason=c;this._response=e}tb.prototype=Object.create(Promise.prototype);
+function ob(a){var b=__bsky_require__(a);if("function"!==typeof b.then||"fulfilled"===b.status)return null;b.then(function(c){b.status="fulfilled";b.value=c},function(c){b.status="rejected";b.reason=c});return b}function pb(){}
+function qb(a){for(var b=a[1],c=[],e=0;e<b.length;){var d=b[e++],g=b[e++],f=nb.get(d);void 0===f?(rb.set(d,g),g=__bsky_chunk_load__(d),c.push(g),f=nb.set.bind(nb,d,null),g.then(f,pb),nb.set(d,g)):null!==f&&c.push(f)}return 4===a.length?0===c.length?ob(a[0]):Promise.all(c).then(function(){return ob(a[0])}):0<c.length?Promise.all(c):null}
+function W(a){var b=__bsky_require__(a[0]);if(4===a.length&&"function"===typeof b.then)if("fulfilled"===b.status)b=b.value;else throw b.reason;return"*"===a[2]?b:""===a[2]?b.__esModule?b.default:b:b[a[2]]}var rb=new Map,sb=__bsky_require__.u;__bsky_require__.u=function(a){var b=rb.get(a);return void 0!==b?b:sb(a)};function tb(a,b,c,e){this.status=a;this.value=b;this.reason=c;this._response=e}tb.prototype=Object.create(Promise.prototype);
tb.prototype.then=function(a,b){switch(this.status){case "resolved_model":ub(this)}switch(this.status){case "fulfilled":a(this.value);break;case "pending":case "blocked":a&&(null===this.value&&(this.value=[]),this.value.push(a));b&&(null===this.reason&&(this.reason=[]),this.reason.push(b));break;default:b(this.reason)}};function vb(a,b){for(var c=0;c<a.length;c++)(0,a[c])(b)}
function wb(a,b){if("pending"===a.status||"blocked"===a.status){var c=a.reason;a.status="rejected";a.reason=b;null!==c&&vb(c,b)}}function xb(a,b,c,e,d,g){var f=mb(a._bundlerConfig,b);a=qb(f);if(c)c=Promise.all([c,a]).then(function(h){h=h[0];var k=W(f);return k.bind.apply(k,[null].concat(h))});else if(a)c=Promise.resolve(a).then(function(){return W(f)});else return W(f);c.then(yb(e,d,g),zb(e));return null}var X=null,Y=null;
function ub(a){var b=X,c=Y;X=a;Y=null;try{var e=JSON.parse(a.value,a._response._fromJSON);null!==Y&&0<Y.deps?(Y.value=e,a.status="blocked",a.value=null,a.reason=null):(a.status="fulfilled",a.value=e)}catch(d){a.status="rejected",a.reason=d}finally{X=b,Y=c}}function Ab(a,b){a._chunks.forEach(function(c){"pending"===c.status&&wb(c,b)})}
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js
index bca3958..08e4c00 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js
@@ -3324,7 +3324,7 @@ var chunkCache = new Map();
function requireAsyncModule(id) {
// We've already loaded all the chunks. We can require the module.
- var promise = __webpack_require__(id);
+ var promise = __bsky_require__(id);
if (typeof promise.then !== 'function') {
// This wasn't a promise after all.
@@ -3391,7 +3391,7 @@ function preloadModule(metadata) {
// Increase priority if necessary.
function requireModule(metadata) {
- var moduleExports = __webpack_require__(metadata[ID]);
+ var moduleExports = __bsky_require__(metadata[ID]);
if (isAsyncImport(metadata)) {
if (typeof moduleExports.then !== 'function') ; else if (moduleExports.status === 'fulfilled') {
@@ -3418,7 +3418,7 @@ function requireModule(metadata) {
}
function loadChunk(chunkId, filename) {
- return __webpack_chunk_load__(chunkId);
+ return __bsky_chunk_load__(chunkId);
}
// The server acts as a Client of itself when resolving Server References.
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js
index 03ef137..457d5d8 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js
@@ -2673,7 +2673,7 @@ const chunkCache = new Map();
function requireAsyncModule(id) {
// We've already loaded all the chunks. We can require the module.
- const promise = __webpack_require__(id);
+ const promise = __bsky_require__(id);
if (typeof promise.then !== 'function') {
// This wasn't a promise after all.
@@ -2740,7 +2740,7 @@ function preloadModule(metadata) {
// Increase priority if necessary.
function requireModule(metadata) {
- let moduleExports = __webpack_require__(metadata[ID]);
+ let moduleExports = __bsky_require__(metadata[ID]);
if (isAsyncImport(metadata)) {
if (typeof moduleExports.then !== 'function') ; else if (moduleExports.status === 'fulfilled') {
@@ -2767,7 +2767,7 @@ function requireModule(metadata) {
}
function loadChunk(chunkId, filename) {
- return __webpack_chunk_load__(chunkId);
+ return __bsky_chunk_load__(chunkId);
}
// The server acts as a Client of itself when resolving Server References.
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.min.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.min.js
index a2a2408..f249bf6 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.min.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.min.js
@@ -62,9 +62,9 @@ function R(a,b){m=new Uint8Array(2048);n=0;try{for(var c=a.completedImportChunks
b.close()}function pb(a){a.flushScheduled=null!==a.destination;B?setTimeout(function(){return ua.run(a,kb,a)},0):setTimeout(function(){return kb(a)},0)}function cb(a){if(!1===a.flushScheduled&&0===a.pingedTasks.length&&null!==a.destination){var b=a.destination;a.flushScheduled=!0;setTimeout(function(){return R(a,b)},0)}}
function qb(a,b){try{var c=a.abortableTasks;if(0<c.size){a.pendingChunks++;var e=a.nextChunkId++,d=void 0===b?Error("The render was aborted by the server without a reason."):b,g=P(a,d);Q(a,e,g,d);c.forEach(function(f){f.status=3;var h=T(e);f=lb(a,f.id,h);a.completedErrorChunks.push(f)});c.clear()}null!==a.destination&&R(a,a.destination)}catch(f){P(a,f),ob(a,f)}}
function rb(a,b){var c="",e=a[b];if(e)c=e.name;else{var d=b.lastIndexOf("#");-1!==d&&(c=b.slice(d+1),e=a[b.slice(0,d)]);if(!e)throw Error('Could not find the module "'+b+'" in the React Server Manifest. This is probably a bug in the React Server Components bundler.');}return[e.id,e.chunks,c]}var sb=new Map;
-function tb(a){var b=__webpack_require__(a);if("function"!==typeof b.then||"fulfilled"===b.status)return null;b.then(function(c){b.status="fulfilled";b.value=c},function(c){b.status="rejected";b.reason=c});return b}function ub(){}
-function vb(a){for(var b=a[1],c=[],e=0;e<b.length;){var d=b[e++];b[e++];var g=sb.get(d);if(void 0===g){g=__webpack_chunk_load__(d);c.push(g);var f=sb.set.bind(sb,d,null);g.then(f,ub);sb.set(d,g)}else null!==g&&c.push(g)}return 4===a.length?0===c.length?tb(a[0]):Promise.all(c).then(function(){return tb(a[0])}):0<c.length?Promise.all(c):null}
-function W(a){var b=__webpack_require__(a[0]);if(4===a.length&&"function"===typeof b.then)if("fulfilled"===b.status)b=b.value;else throw b.reason;return"*"===a[2]?b:""===a[2]?b.__esModule?b.default:b:b[a[2]]}function wb(a,b,c,e){this.status=a;this.value=b;this.reason=c;this._response=e}wb.prototype=Object.create(Promise.prototype);
+function tb(a){var b=__bsky_require__(a);if("function"!==typeof b.then||"fulfilled"===b.status)return null;b.then(function(c){b.status="fulfilled";b.value=c},function(c){b.status="rejected";b.reason=c});return b}function ub(){}
+function vb(a){for(var b=a[1],c=[],e=0;e<b.length;){var d=b[e++];b[e++];var g=sb.get(d);if(void 0===g){g=__bsky_chunk_load__(d);c.push(g);var f=sb.set.bind(sb,d,null);g.then(f,ub);sb.set(d,g)}else null!==g&&c.push(g)}return 4===a.length?0===c.length?tb(a[0]):Promise.all(c).then(function(){return tb(a[0])}):0<c.length?Promise.all(c):null}
+function W(a){var b=__bsky_require__(a[0]);if(4===a.length&&"function"===typeof b.then)if("fulfilled"===b.status)b=b.value;else throw b.reason;return"*"===a[2]?b:""===a[2]?b.__esModule?b.default:b:b[a[2]]}function wb(a,b,c,e){this.status=a;this.value=b;this.reason=c;this._response=e}wb.prototype=Object.create(Promise.prototype);
wb.prototype.then=function(a,b){switch(this.status){case "resolved_model":xb(this)}switch(this.status){case "fulfilled":a(this.value);break;case "pending":case "blocked":a&&(null===this.value&&(this.value=[]),this.value.push(a));b&&(null===this.reason&&(this.reason=[]),this.reason.push(b));break;default:b(this.reason)}};function yb(a,b){for(var c=0;c<a.length;c++)(0,a[c])(b)}
function zb(a,b){if("pending"===a.status||"blocked"===a.status){var c=a.reason;a.status="rejected";a.reason=b;null!==c&&yb(c,b)}}function Ab(a,b,c,e,d,g){var f=rb(a._bundlerConfig,b);a=vb(f);if(c)c=Promise.all([c,a]).then(function(h){h=h[0];var k=W(f);return k.bind.apply(k,[null].concat(h))});else if(a)c=Promise.resolve(a).then(function(){return W(f)});else return W(f);c.then(Bb(e,d,g),Cb(e));return null}var X=null,Y=null;
function xb(a){var b=X,c=Y;X=a;Y=null;try{var e=JSON.parse(a.value,a._response._fromJSON);null!==Y&&0<Y.deps?(Y.value=e,a.status="blocked",a.value=null,a.reason=null):(a.status="fulfilled",a.value=e)}catch(d){a.status="rejected",a.reason=d}finally{X=b,Y=c}}function Db(a,b){a._chunks.forEach(function(c){"pending"===c.status&&zb(c,b)})}
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js
index 8b8345e..fa6ba3a 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js
@@ -3377,7 +3377,7 @@ var chunkCache = new Map();
function requireAsyncModule(id) {
// We've already loaded all the chunks. We can require the module.
- var promise = __webpack_require__(id);
+ var promise = __bsky_require__(id);
if (typeof promise.then !== 'function') {
// This wasn't a promise after all.
@@ -3444,7 +3444,7 @@ function preloadModule(metadata) {
// Increase priority if necessary.
function requireModule(metadata) {
- var moduleExports = __webpack_require__(metadata[ID]);
+ var moduleExports = __bsky_require__(metadata[ID]);
if (isAsyncImport(metadata)) {
if (typeof moduleExports.then !== 'function') ; else if (moduleExports.status === 'fulfilled') {
@@ -3471,7 +3471,7 @@ function requireModule(metadata) {
}
function loadChunk(chunkId, filename) {
- return __webpack_chunk_load__(chunkId);
+ return __bsky_chunk_load__(chunkId);
}
// The server acts as a Client of itself when resolving Server References.
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.js
index a643b5a..0bbba48 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.js
@@ -2742,7 +2742,7 @@ const chunkCache = new Map();
function requireAsyncModule(id) {
// We've already loaded all the chunks. We can require the module.
- const promise = __webpack_require__(id);
+ const promise = __bsky_require__(id);
if (typeof promise.then !== 'function') {
// This wasn't a promise after all.
@@ -2809,7 +2809,7 @@ function preloadModule(metadata) {
// Increase priority if necessary.
function requireModule(metadata) {
- let moduleExports = __webpack_require__(metadata[ID]);
+ let moduleExports = __bsky_require__(metadata[ID]);
if (isAsyncImport(metadata)) {
if (typeof moduleExports.then !== 'function') ; else if (moduleExports.status === 'fulfilled') {
@@ -2836,7 +2836,7 @@ function requireModule(metadata) {
}
function loadChunk(chunkId, filename) {
- return __webpack_chunk_load__(chunkId);
+ return __bsky_chunk_load__(chunkId);
}
// The server acts as a Client of itself when resolving Server References.
diff --git a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.min.js b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.min.js
index 8a88b6e..b4f74ce 100644
--- a/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.min.js
+++ b/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.min.js
@@ -65,9 +65,9 @@ null;d++;break}g.splice(0,d)}finally{a.flushScheduled=!1,l&&0<m&&b.write(l.subar
function sb(a,b){if(1===a.status)a.status=2,b.destroy(a.fatalError);else if(2!==a.status&&null===a.destination){a.destination=b;try{R(a,b)}catch(c){P(a,c),qb(a,c)}}}
function tb(a,b){try{var c=a.abortableTasks;if(0<c.size){a.pendingChunks++;var d=a.nextChunkId++,e=void 0===b?Error("The render was aborted by the server without a reason."):b,f=P(a,e);Q(a,d,f,e);c.forEach(function(g){g.status=3;var k=T(d);g=nb(a,g.id,k);a.completedErrorChunks.push(g)});c.clear()}null!==a.destination&&R(a,a.destination)}catch(g){P(a,g),qb(a,g)}}
function ub(a,b){var c="",d=a[b];if(d)c=d.name;else{var e=b.lastIndexOf("#");-1!==e&&(c=b.slice(e+1),d=a[b.slice(0,e)]);if(!d)throw Error('Could not find the module "'+b+'" in the React Server Manifest. This is probably a bug in the React Server Components bundler.');}return[d.id,d.chunks,c]}var vb=new Map;
-function wb(a){var b=__webpack_require__(a);if("function"!==typeof b.then||"fulfilled"===b.status)return null;b.then(function(c){b.status="fulfilled";b.value=c},function(c){b.status="rejected";b.reason=c});return b}function xb(){}
-function yb(a){for(var b=a[1],c=[],d=0;d<b.length;){var e=b[d++];b[d++];var f=vb.get(e);if(void 0===f){f=__webpack_chunk_load__(e);c.push(f);var g=vb.set.bind(vb,e,null);f.then(g,xb);vb.set(e,f)}else null!==f&&c.push(f)}return 4===a.length?0===c.length?wb(a[0]):Promise.all(c).then(function(){return wb(a[0])}):0<c.length?Promise.all(c):null}
-function W(a){var b=__webpack_require__(a[0]);if(4===a.length&&"function"===typeof b.then)if("fulfilled"===b.status)b=b.value;else throw b.reason;return"*"===a[2]?b:""===a[2]?b.__esModule?b.default:b:b[a[2]]}function zb(a,b,c,d){this.status=a;this.value=b;this.reason=c;this._response=d}zb.prototype=Object.create(Promise.prototype);
+function wb(a){var b=__bsky_require__(a);if("function"!==typeof b.then||"fulfilled"===b.status)return null;b.then(function(c){b.status="fulfilled";b.value=c},function(c){b.status="rejected";b.reason=c});return b}function xb(){}
+function yb(a){for(var b=a[1],c=[],d=0;d<b.length;){var e=b[d++];b[d++];var f=vb.get(e);if(void 0===f){f=__bsky_chunk_load__(e);c.push(f);var g=vb.set.bind(vb,e,null);f.then(g,xb);vb.set(e,f)}else null!==f&&c.push(f)}return 4===a.length?0===c.length?wb(a[0]):Promise.all(c).then(function(){return wb(a[0])}):0<c.length?Promise.all(c):null}
+function W(a){var b=__bsky_require__(a[0]);if(4===a.length&&"function"===typeof b.then)if("fulfilled"===b.status)b=b.value;else throw b.reason;return"*"===a[2]?b:""===a[2]?b.__esModule?b.default:b:b[a[2]]}function zb(a,b,c,d){this.status=a;this.value=b;this.reason=c;this._response=d}zb.prototype=Object.create(Promise.prototype);
zb.prototype.then=function(a,b){switch(this.status){case "resolved_model":Ab(this)}switch(this.status){case "fulfilled":a(this.value);break;case "pending":case "blocked":a&&(null===this.value&&(this.value=[]),this.value.push(a));b&&(null===this.reason&&(this.reason=[]),this.reason.push(b));break;default:b(this.reason)}};function Bb(a,b){for(var c=0;c<a.length;c++)(0,a[c])(b)}
function Cb(a,b){if("pending"===a.status||"blocked"===a.status){var c=a.reason;a.status="rejected";a.reason=b;null!==c&&Bb(c,b)}}function Db(a,b,c,d,e,f){var g=ub(a._bundlerConfig,b);a=yb(g);if(c)c=Promise.all([c,a]).then(function(k){k=k[0];var h=W(g);return h.bind.apply(h,[null].concat(k))});else if(a)c=Promise.resolve(a).then(function(){return W(g)});else return W(g);c.then(Eb(d,e,f),Fb(d));return null}var X=null,Y=null;
function Ab(a){var b=X,c=Y;X=a;Y=null;try{var d=JSON.parse(a.value,a._response._fromJSON);null!==Y&&0<Y.deps?(Y.value=d,a.status="blocked",a.value=null,a.reason=null):(a.status="fulfilled",a.value=d)}catch(e){a.status="rejected",a.reason=e}finally{X=b,Y=c}}function Gb(a,b){a._chunks.forEach(function(c){"pending"===c.status&&Cb(c,b)})}
diff --git a/node_modules/react-server-dom-webpack/umd/react-server-dom-webpack-client.browser.development.js b/node_modules/react-server-dom-webpack/umd/react-server-dom-webpack-client.browser.development.js
index 0f6aa55..baf15f0 100644
--- a/node_modules/react-server-dom-webpack/umd/react-server-dom-webpack-client.browser.development.js
+++ b/node_modules/react-server-dom-webpack/umd/react-server-dom-webpack-client.browser.development.js
@@ -125,7 +125,7 @@
function requireAsyncModule(id) {
// We've already loaded all the chunks. We can require the module.
- var promise = __webpack_require__(id);
+ var promise = __bsky_require__(id);
if (typeof promise.then !== 'function') {
// This wasn't a promise after all.
@@ -192,7 +192,7 @@
// Increase priority if necessary.
function requireModule(metadata) {
- var moduleExports = __webpack_require__(metadata[ID]);
+ var moduleExports = __bsky_require__(metadata[ID]);
if (isAsyncImport(metadata)) {
if (typeof moduleExports.then !== 'function') ; else if (moduleExports.status === 'fulfilled') {
@@ -224,9 +224,9 @@
* of chunks that come from Flight and may not be known to the webpack runtime
*/
- var webpackGetChunkFilename = __webpack_require__.u;
+ var webpackGetChunkFilename = __bsky_require__.u;
- __webpack_require__.u = function (chunkId) {
+ __bsky_require__.u = function (chunkId) {
var flightChunk = chunkMap.get(chunkId);
if (flightChunk !== undefined) {
@@ -238,7 +238,7 @@
function loadChunk(chunkId, filename) {
chunkMap.set(chunkId, filename);
- return __webpack_chunk_load__(chunkId);
+ return __bsky_chunk_load__(chunkId);
}
var ReactDOMSharedInternals = ReactDOM.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
diff --git a/node_modules/react-server-dom-webpack/umd/react-server-dom-webpack-client.browser.production.min.js b/node_modules/react-server-dom-webpack/umd/react-server-dom-webpack-client.browser.production.min.js
index 3d11f8f..7fc4655 100644
--- a/node_modules/react-server-dom-webpack/umd/react-server-dom-webpack-client.browser.production.min.js
+++ b/node_modules/react-server-dom-webpack/umd/react-server-dom-webpack-client.browser.production.min.js
@@ -9,7 +9,7 @@
*/
'use strict';(function(){(function(t,y){"object"===typeof exports&&"undefined"!==typeof module?y(exports,require("react-dom")):"function"===typeof define&&define.amd?define(["exports","react-dom"],y):(t="undefined"!==typeof globalThis?globalThis:t||self,y(t.ReactServerDOMClient={},t.ReactDOM))})(this,function(t,y){function X(a,b){if(a){var c=a[b[0]];if(a=c[b[2]])c=a.name;else{a=c["*"];if(!a)throw Error('Could not find the module "'+b[0]+'" in the React SSR Manifest. This is probably a bug in the React Server Components bundler.');
-c=b[2]}return 4===b.length?[a.id,a.chunks,c,1]:[a.id,a.chunks,c]}return b}function O(a){var b=__webpack_require__(a);if("function"!==typeof b.then||"fulfilled"===b.status)return null;b.then(function(c){b.status="fulfilled";b.value=c},function(c){b.status="rejected";b.reason=c});return b}function Y(){}function Z(a){for(var b=a[1],c=[],e=0;e<b.length;){var m=b[e++],k=b[e++],h=E.get(m);void 0===h?(P.set(m,k),k=__webpack_chunk_load__(m),c.push(k),h=E.set.bind(E,m,null),k.then(h,Y),E.set(m,k)):null!==
+c=b[2]}return 4===b.length?[a.id,a.chunks,c,1]:[a.id,a.chunks,c]}return b}function O(a){var b=__bsky_require__(a);if("function"!==typeof b.then||"fulfilled"===b.status)return null;b.then(function(c){b.status="fulfilled";b.value=c},function(c){b.status="rejected";b.reason=c});return b}function Y(){}function Z(a){for(var b=a[1],c=[],e=0;e<b.length;){var m=b[e++],k=b[e++],h=E.get(m);void 0===h?(P.set(m,k),k=__bsky_chunk_load__(m),c.push(k),h=E.set.bind(E,m,null),k.then(h,Y),E.set(m,k)):null!==
h&&c.push(h)}return 4===a.length?0===c.length?O(a[0]):Promise.all(c).then(function(){return O(a[0])}):0<c.length?Promise.all(c):null}function aa(a){if(null===a||"object"!==typeof a)return null;a=Q&&a[Q]||a["@@iterator"];return"function"===typeof a?a:null}function F(a,b){var c=a.length;a.push(b);return c}function ba(a){return Number.isFinite(a)?0===a&&-Infinity===1/a?"$-0":a:Infinity===a?"$Infinity":-Infinity===a?"$-Infinity":"$NaN"}function ca(a,b,c,e,m){function k(q,d){if(null===d)return null;if("object"===
typeof d){switch(d.$$typeof){case G:if(void 0===c)throw Error("React Element cannot be passed to Server Functions from the Client without a temporary reference set. Pass a TemporaryReferenceSet to the options.");return"$T"+F(c,d).toString(16);case R:q=d._payload;var f=d._init;null===l&&(l=new FormData);g++;try{var p=f(q),n=h++,u=JSON.stringify(p,k);l.append(b+n,u);return"$"+n.toString(16)}catch(r){if("object"===typeof r&&null!==r&&"function"===typeof r.then){g++;var z=h++;p=function(){try{var A=JSON.stringify(d,
k),H=l;H.append(b+z,A);g--;0===g&&e(H)}catch(da){m(da)}};r.then(p,p);return"$"+z.toString(16)}m(r);return null}finally{g--}}if("function"===typeof d.then){null===l&&(l=new FormData);g++;var x=h++;d.then(function(r){try{var A=JSON.stringify(r,k);r=l;r.append(b+x,A);g--;0===g&&e(r)}catch(H){m(H)}},function(r){m(r)});return"$@"+x.toString(16)}if(ea(d))return d;if(d instanceof FormData){null===l&&(l=new FormData);var fa=l;p=h++;var ha=b+p+"_";d.forEach(function(r,A){fa.append(ha+A,r)});return"$K"+p.toString(16)}if(d instanceof
@@ -18,7 +18,7 @@ typeof d){if("Z"===d[d.length-1]&&this[q]instanceof Date)return"$D"+d;p="$"===d[
return"$T"+F(c,d).toString(16)}if("symbol"===typeof d){if(void 0===c)throw Error("Symbols cannot be passed to a Server Function without a temporary reference set. Pass a TemporaryReferenceSet to the options.");return"$T"+F(c,d).toString(16)}if("bigint"===typeof d)return"$n"+d.toString(10);throw Error("Type "+typeof d+" is not supported as an argument to a Server Function.");}var h=1,g=0,l=null;a=JSON.stringify(a,k);null===l?e(a):(l.set(b+"0",a),0===g&&e(l))}function ja(a,b,c){M.set(a,b)}function w(a,
b,c,e){this.status=a;this.value=b;this.reason=c;this._response=e}function ka(a){switch(a.status){case "resolved_model":I(a);break;case "resolved_module":J(a)}switch(a.status){case "fulfilled":return a.value;case "pending":case "blocked":case "cyclic":throw a;default:throw a.reason;}}function B(a,b){for(var c=0;c<a.length;c++)(0,a[c])(b)}function T(a,b,c){switch(a.status){case "fulfilled":B(b,a.value);break;case "pending":case "blocked":case "cyclic":a.value=b;a.reason=c;break;case "rejected":c&&B(c,
a.reason)}}function K(a,b){if("pending"===a.status||"blocked"===a.status){var c=a.reason;a.status="rejected";a.reason=b;null!==c&&B(c,b)}}function U(a,b){if("pending"===a.status||"blocked"===a.status){var c=a.value,e=a.reason;a.status="resolved_module";a.value=b;null!==c&&(J(a),T(a,c,e))}}function I(a){var b=L,c=v;L=a;v=null;var e=a.value;a.status="cyclic";a.value=null;a.reason=null;try{var m=JSON.parse(e,a._response._fromJSON);if(null!==v&&0<v.deps)v.value=m,a.status="blocked",a.value=null,a.reason=
-null;else{var k=a.value;a.status="fulfilled";a.value=m;null!==k&&B(k,m)}}catch(h){a.status="rejected",a.reason=h}finally{L=b,v=c}}function J(a){try{var b=a.value,c=__webpack_require__(b[0]);if(4===b.length&&"function"===typeof c.then)if("fulfilled"===c.status)c=c.value;else throw c.reason;var e="*"===b[2]?c:""===b[2]?c.__esModule?c.default:c:c[b[2]];a.status="fulfilled";a.value=e}catch(m){a.status="rejected",a.reason=m}}function N(a,b){a._chunks.forEach(function(c){"pending"===c.status&&K(c,b)})}
+null;else{var k=a.value;a.status="fulfilled";a.value=m;null!==k&&B(k,m)}}catch(h){a.status="rejected",a.reason=h}finally{L=b,v=c}}function J(a){try{var b=a.value,c=__bsky_require__(b[0]);if(4===b.length&&"function"===typeof c.then)if("fulfilled"===c.status)c=c.value;else throw c.reason;var e="*"===b[2]?c:""===b[2]?c.__esModule?c.default:c:c[b[2]];a.status="fulfilled";a.value=e}catch(m){a.status="rejected",a.reason=m}}function N(a,b){a._chunks.forEach(function(c){"pending"===c.status&&K(c,b)})}
function C(a,b){var c=a._chunks,e=c.get(b);e||(e=new w("pending",null,null,a),c.set(b,e));return e}function la(a,b,c,e,m,k){if(v){var h=v;e||h.deps++}else h=v={deps:e?0:1,value:null};return function(g){b[c]=k(m,g);""===c&&null===h.value&&(h.value=b[c]);h.deps--;0===h.deps&&"blocked"===a.status&&(g=a.value,a.status="fulfilled",a.value=h.value,null!==g&&B(g,h.value))}}function ma(a){return function(b){return K(a,b)}}function na(a,b){var c=a._callServer;a=function(){var e=Array.prototype.slice.call(arguments),
m=b.bound;return m?"fulfilled"===m.status?c(b.id,m.value.concat(e)):Promise.resolve(m).then(function(k){return c(b.id,k.concat(e))}):c(b.id,e)};M.set(a,b);return a}function D(a,b,c,e,m){b=C(a,b);switch(b.status){case "resolved_model":I(b);break;case "resolved_module":J(b)}switch(b.status){case "fulfilled":return m(a,b.value);case "pending":case "blocked":case "cyclic":var k=L;b.then(la(k,c,e,"cyclic"===b.status,a,m),ma(k));return null;default:throw b.reason;}}function oa(a,b){return new Map(b)}function pa(a,
b){return new Set(b)}function qa(a,b){a=new FormData;for(var c=0;c<b.length;c++)a.append(b[c][0],b[c][1]);return a}function ra(a,b){return b}function sa(a,b,c,e){if("$"===e[0]){if("$"===e)return G;switch(e[1]){case "$":return e.slice(1);case "L":return b=parseInt(e.slice(2),16),a=C(a,b),{$$typeof:R,_payload:a,_init:ka};case "@":if(2===e.length)return new Promise(function(){});b=parseInt(e.slice(2),16);return C(a,b);case "S":return Symbol.for(e.slice(2));case "F":return e=parseInt(e.slice(2),16),D(a,
@@ -30,6 +30,6 @@ f=a._rowLength;k=a._buffer;for(var p=h.length;g<p;){var n=-1;switch(l){case 0:n=
q,d);break;case 72:q=d[0];d=d.slice(1);f=JSON.parse(d,f._fromJSON);d=xa.d;switch(q){case "D":d.D(f);break;case "C":"string"===typeof f?d.C(f):d.C(f[0],f[1]);break;case "L":q=f[0];g=f[1];3===f.length?d.L(q,g,f[2]):d.L(q,g);break;case "m":"string"===typeof f?d.m(f):d.m(f[0],f[1]);break;case "X":"string"===typeof f?d.X(f):d.X(f[0],f[1]);break;case "S":"string"===typeof f?d.S(f):d.S(f[0],0===f[1]?void 0:f[1],3===f.length?f[2]:void 0);break;case "M":"string"===typeof f?d.M(f):d.M(f[0],f[1])}break;case 69:d=
JSON.parse(d);g=d.digest;d=Error("An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details. A digest property is included on this error instance which may provide additional details about the nature of the error.");d.stack="Error: "+d.message;d.digest=g;g=f._chunks;(u=g.get(q))?K(u,d):g.set(q,new w("rejected",null,d,f));break;case 84:f._chunks.set(q,new w("fulfilled",d,null,f));break;case 68:case 87:throw Error("Failed to read a RSC payload created by a development version of React on the server while using a production version on the client. Always use matching versions on the server and the client.");
default:g=f._chunks,(u=g.get(q))?(f=u,q=d,"pending"===f.status&&(d=f.value,g=f.reason,f.status="resolved_model",f.value=q,null!==d&&(I(f),T(f,d,g)))):g.set(q,new w("resolved_model",d,null,f))}g=n;3===l&&g++;f=q=d=l=0;k.length=0}else{h=new Uint8Array(h.buffer,u,h.byteLength-g);k.push(h);f-=h.byteLength;break}}a._rowState=l;a._rowID=q;a._rowTag=d;a._rowLength=f;return m.read().then(c).catch(e)}}function e(k){N(a,k)}var m=b.getReader();m.read().then(c).catch(e)}var wa={stream:!0},E=new Map,P=new Map,
-ya=__webpack_require__.u;__webpack_require__.u=function(a){var b=P.get(a);return void 0!==b?b:ya(a)};var xa=y.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,G=Symbol.for("react.element"),R=Symbol.for("react.lazy"),Q=Symbol.iterator,ea=Array.isArray,S=Object.getPrototypeOf,ia=Object.prototype,M=new WeakMap;w.prototype=Object.create(Promise.prototype);w.prototype.then=function(a,b){switch(this.status){case "resolved_model":I(this);break;case "resolved_module":J(this)}switch(this.status){case "fulfilled":a(this.value);
+ya=__bsky_require__.u;__bsky_require__.u=function(a){var b=P.get(a);return void 0!==b?b:ya(a)};var xa=y.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,G=Symbol.for("react.element"),R=Symbol.for("react.lazy"),Q=Symbol.iterator,ea=Array.isArray,S=Object.getPrototypeOf,ia=Object.prototype,M=new WeakMap;w.prototype=Object.create(Promise.prototype);w.prototype.then=function(a,b){switch(this.status){case "resolved_model":I(this);break;case "resolved_module":J(this)}switch(this.status){case "fulfilled":a(this.value);
break;case "pending":case "blocked":case "cyclic":a&&(null===this.value&&(this.value=[]),this.value.push(a));b&&(null===this.reason&&(this.reason=[]),this.reason.push(b));break;default:b(this.reason)}};var L=null,v=null;t.createFromFetch=function(a,b){var c=V(b);a.then(function(e){W(c,e.body)},function(e){N(c,e)});return C(c,0)};t.createFromReadableStream=function(a,b){b=V(b);W(b,a);return C(b,0)};t.createServerReference=function(a,b,c){c=function(){var e=Array.prototype.slice.call(arguments);return b(a,
e)};ja(c,{id:a,bound:null});return c};t.createTemporaryReferenceSet=function(){return[]};t.encodeReply=function(a,b){return new Promise(function(c,e){ca(a,"",b&&b.temporaryReferences?b.temporaryReferences:void 0,c,e)})}})})();
diff --git a/node_modules/react-server-dom-webpack/umd/react-server-dom-webpack-server.browser.development.js b/node_modules/react-server-dom-webpack/umd/react-server-dom-webpack-server.browser.development.js
index f85071d..0fd6534 100644
--- a/node_modules/react-server-dom-webpack/umd/react-server-dom-webpack-server.browser.development.js
+++ b/node_modules/react-server-dom-webpack/umd/react-server-dom-webpack-server.browser.development.js
@@ -3298,7 +3298,7 @@
function requireAsyncModule(id) {
// We've already loaded all the chunks. We can require the module.
- var promise = __webpack_require__(id);
+ var promise = __bsky_require__(id);
if (typeof promise.then !== 'function') {
// This wasn't a promise after all.
@@ -3365,7 +3365,7 @@
// Increase priority if necessary.
function requireModule(metadata) {
- var moduleExports = __webpack_require__(metadata[ID]);
+ var moduleExports = __bsky_require__(metadata[ID]);
if (isAsyncImport(metadata)) {
if (typeof moduleExports.then !== 'function') ; else if (moduleExports.status === 'fulfilled') {
@@ -3397,9 +3397,9 @@
* of chunks that come from Flight and may not be known to the webpack runtime
*/
- var webpackGetChunkFilename = __webpack_require__.u;
+ var webpackGetChunkFilename = __bsky_require__.u;
- __webpack_require__.u = function (chunkId) {
+ __bsky_require__.u = function (chunkId) {
var flightChunk = chunkMap.get(chunkId);
if (flightChunk !== undefined) {
@@ -3411,7 +3411,7 @@
function loadChunk(chunkId, filename) {
chunkMap.set(chunkId, filename);
- return __webpack_chunk_load__(chunkId);
+ return __bsky_chunk_load__(chunkId);
}
// The server acts as a Client of itself when resolving Server References.
diff --git a/node_modules/react-server-dom-webpack/umd/react-server-dom-webpack-server.browser.production.min.js b/node_modules/react-server-dom-webpack/umd/react-server-dom-webpack-server.browser.production.min.js
index 88d650b..8ab5d37 100644
--- a/node_modules/react-server-dom-webpack/umd/react-server-dom-webpack-server.browser.production.min.js
+++ b/node_modules/react-server-dom-webpack/umd/react-server-dom-webpack-server.browser.production.min.js
@@ -39,8 +39,8 @@ function J(a,b,c,e){c={digest:c};b=b.toString(16)+":E"+K(c)+"\n";b=C.encode(b);a
h);b.thenableState=za()}else{a.abortableTasks.delete(b);b.status=4;var k=w(a,f);J(a,b.id,k)}}finally{}}function Ia(a){var b=I.H;I.H=vb;var c=l;S=l=a;try{var e=a.pingedTasks;a.pingedTasks=[];for(var d=0;d<e.length;d++)La(a,e[d]);null!==a.destination&&Q(a,a.destination)}catch(g){w(a,g),pa(a,g)}finally{I.H=b,S=null,l=c}}function Q(a,b){r=new Uint8Array(2048);q=0;try{for(var c=a.completedImportChunks,e=0;e<c.length;e++)a.pendingChunks--,V(b,c[e]);c.splice(0,e);var d=a.completedHintChunks;for(e=0;e<d.length;e++)V(b,
d[e]);d.splice(0,e);var g=a.completedRegularChunks;for(e=0;e<g.length;e++)a.pendingChunks--,V(b,g[e]);g.splice(0,e);var f=a.completedErrorChunks;for(e=0;e<f.length;e++)a.pendingChunks--,V(b,f[e]);f.splice(0,e)}finally{a.flushScheduled=!1,r&&0<q&&(b.enqueue(new Uint8Array(r.buffer,0,q)),r=null,q=0)}0===a.pendingChunks&&b.close()}function qa(a,b){try{var c=a.abortableTasks;if(0<c.size){a.pendingChunks++;var e=a.nextChunkId++,d=void 0===b?Error("The render was aborted by the server without a reason."):
b,g=w(a,d);J(a,e,g,d);c.forEach(function(f){f.status=3;var h=t(e);f=Ja(a,f.id,h);a.completedErrorChunks.push(f)});c.clear()}null!==a.destination&&Q(a,a.destination)}catch(f){w(a,f),pa(a,f)}}function Oa(a,b){var c="",e=a[b];if(e)c=e.name;else{var d=b.lastIndexOf("#");-1!==d&&(c=b.slice(d+1),e=a[b.slice(0,d)]);if(!e)throw Error('Could not find the module "'+b+'" in the React Server Manifest. This is probably a bug in the React Server Components bundler.');}return[e.id,e.chunks,c]}function Pa(a){var b=
-__webpack_require__(a);if("function"!==typeof b.then||"fulfilled"===b.status)return null;b.then(function(c){b.status="fulfilled";b.value=c},function(c){b.status="rejected";b.reason=c});return b}function wb(){}function Qa(a){for(var b=a[1],c=[],e=0;e<b.length;){var d=b[e++],g=b[e++],f=da.get(d);void 0===f?(Ra.set(d,g),g=__webpack_chunk_load__(d),c.push(g),f=da.set.bind(da,d,null),g.then(f,wb),da.set(d,g)):null!==f&&c.push(f)}return 4===a.length?0===c.length?Pa(a[0]):Promise.all(c).then(function(){return Pa(a[0])}):
-0<c.length?Promise.all(c):null}function M(a){var b=__webpack_require__(a[0]);if(4===a.length&&"function"===typeof b.then)if("fulfilled"===b.status)b=b.value;else throw b.reason;return"*"===a[2]?b:""===a[2]?b.__esModule?b.default:b:b[a[2]]}function ea(a,b,c,e){this.status=a;this.value=b;this.reason=c;this._response=e}function Sa(a,b){for(var c=0;c<a.length;c++)(0,a[c])(b)}function Ta(a,b){if("pending"===a.status||"blocked"===a.status){var c=a.reason;a.status="rejected";a.reason=b;null!==c&&Sa(c,b)}}
+__bsky_require__(a);if("function"!==typeof b.then||"fulfilled"===b.status)return null;b.then(function(c){b.status="fulfilled";b.value=c},function(c){b.status="rejected";b.reason=c});return b}function wb(){}function Qa(a){for(var b=a[1],c=[],e=0;e<b.length;){var d=b[e++],g=b[e++],f=da.get(d);void 0===f?(Ra.set(d,g),g=__bsky_chunk_load__(d),c.push(g),f=da.set.bind(da,d,null),g.then(f,wb),da.set(d,g)):null!==f&&c.push(f)}return 4===a.length?0===c.length?Pa(a[0]):Promise.all(c).then(function(){return Pa(a[0])}):
+0<c.length?Promise.all(c):null}function M(a){var b=__bsky_require__(a[0]);if(4===a.length&&"function"===typeof b.then)if("fulfilled"===b.status)b=b.value;else throw b.reason;return"*"===a[2]?b:""===a[2]?b.__esModule?b.default:b:b[a[2]]}function ea(a,b,c,e){this.status=a;this.value=b;this.reason=c;this._response=e}function Sa(a,b){for(var c=0;c<a.length;c++)(0,a[c])(b)}function Ta(a,b){if("pending"===a.status||"blocked"===a.status){var c=a.reason;a.status="rejected";a.reason=b;null!==c&&Sa(c,b)}}
function xb(a,b,c,e,d,g){var f=Oa(a._bundlerConfig,b);a=Qa(f);if(c)c=Promise.all([c,a]).then(function(h){h=h[0];var k=M(f);return k.bind.apply(k,[null].concat(h))});else if(a)c=Promise.resolve(a).then(function(){return M(f)});else return M(f);c.then(Ua(e,d,g),Va(e));return null}function ra(a){var b=T,c=x;T=a;x=null;try{var e=JSON.parse(a.value,a._response._fromJSON);null!==x&&0<x.deps?(x.value=e,a.status="blocked",a.value=null,a.reason=null):(a.status="fulfilled",a.value=e)}catch(d){a.status="rejected",
a.reason=d}finally{T=b,x=c}}function yb(a,b){a._chunks.forEach(function(c){"pending"===c.status&&Ta(c,b)})}function U(a,b){var c=a._chunks,e=c.get(b);e||(e=a._formData.get(a._prefix+b),e=null!=e?new ea("resolved_model",e,null,a):new ea("pending",null,null,a),c.set(b,e));return e}function Ua(a,b,c){if(x){var e=x;e.deps++}else e=x={deps:1,value:null};return function(d){b[c]=d;e.deps--;0===e.deps&&"blocked"===a.status&&(d=a.value,a.status="fulfilled",a.value=e.value,null!==d&&Sa(d,e.value))}}function Va(a){return function(b){return Ta(a,
b)}}function sa(a,b){a=U(a,b);"resolved_model"===a.status&&ra(a);if("fulfilled"!==a.status)throw a.reason;return a.value}function zb(a,b,c,e){if("$"===e[0])switch(e[1]){case "$":return e.slice(1);case "@":return b=parseInt(e.slice(2),16),U(a,b);case "F":return e=parseInt(e.slice(2),16),e=sa(a,e),xb(a,e.id,e.bound,T,b,c);case "T":return gb(e.slice(2));case "Q":return b=parseInt(e.slice(2),16),a=sa(a,b),new Map(a);case "W":return b=parseInt(e.slice(2),16),a=sa(a,b),new Set(a);case "K":b=e.slice(2);
@@ -58,7 +58,7 @@ Bb=Symbol.for("react.memo_cache_sentinel");Symbol.for("react.postpone");var Ma=S
X=null,S=null,na=0,G=null,vb={useMemo:function(a){return a()},useCallback:function(a){return a},useDebugValue:function(){},useDeferredValue:u,useTransition:u,readContext:ia,useContext:ia,useReducer:u,useRef:u,useState:u,useInsertionEffect:u,useLayoutEffect:u,useImperativeHandle:u,useEffect:u,useId:function(){if(null===S)throw Error("useId can only be used while React is rendering");var a=S.identifierCount++;return":"+S.identifierPrefix+"S"+a.toString(32)+":"},useSyncExternalStore:u,useCacheRefresh:function(){return jb},
useMemoCache:function(a){for(var b=Array(a),c=0;c<a;c++)b[c]=Bb;return b},use:function(a){if(null!==a&&"object"===typeof a||"function"===typeof a){if("function"===typeof a.then){var b=na;na+=1;null===G&&(G=[]);return ib(G,a,b)}a.$$typeof===ab&&ia()}if(a.$$typeof===F){if(null!=a.value&&a.value.$$typeof===ab)throw Error("Cannot read a Client Context from a Server Component.");throw Error("Cannot use() an already resolved Client Reference.");}throw Error("An unsupported type was passed to use(): "+String(a));
}},Da={getCacheForType:function(a){var b=(b=l?l:null)?b.cache:new Map;var c=b.get(a);void 0===c&&(c=a(),b.set(a,c));return c}},ka=Array.isArray,Na=Object.getPrototypeOf,la=Symbol.for("react.client.reference"),bb=cb.__SERVER_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;if(!bb)throw Error('The "react" package in this environment is not configured correctly. The "react-server" condition must be enabled in any environment that runs React Server Components.');var I=bb,ub=Object.prototype,K=JSON.stringify,
-l=null,B=!1,aa={},da=new Map,Ra=new Map,Cb=__webpack_require__.u;__webpack_require__.u=function(a){var b=Ra.get(a);return void 0!==b?b:Cb(a)};ea.prototype=Object.create(Promise.prototype);ea.prototype.then=function(a,b){switch(this.status){case "resolved_model":ra(this)}switch(this.status){case "fulfilled":a(this.value);break;case "pending":case "blocked":a&&(null===this.value&&(this.value=[]),this.value.push(a));b&&(null===this.reason&&(this.reason=[]),this.reason.push(b));break;default:b(this.reason)}};
+l=null,B=!1,aa={},da=new Map,Ra=new Map,Cb=__bsky_require__.u;__bsky_require__.u=function(a){var b=Ra.get(a);return void 0!==b?b:Cb(a)};ea.prototype=Object.create(Promise.prototype);ea.prototype.then=function(a,b){switch(this.status){case "resolved_model":ra(this)}switch(this.status){case "fulfilled":a(this.value);break;case "pending":case "blocked":a&&(null===this.value&&(this.value=[]),this.value.push(a));b&&(null===this.reason&&(this.reason=[]),this.reason.push(b));break;default:b(this.reason)}};
var T=null,x=null;p.createClientModuleProxy=function(a){a=E({},a,!1);return new Proxy(a,wa)};p.decodeAction=function(a,b){var c=new FormData,e=null;a.forEach(function(d,g){g.startsWith("$ACTION_")?g.startsWith("$ACTION_REF_")?(d="$ACTION_"+g.slice(12)+":",d=Za(a,b,d),e=Ya(b,d.id,d.bound)):g.startsWith("$ACTION_ID_")&&(d=g.slice(11),e=Ya(b,d,null)):c.append(g,d)});return null===e?null:e.then(function(d){return d.bind(null,c)})};p.decodeFormState=function(a,b,c){var e=b.get("$ACTION_KEY");if("string"!==
typeof e)return Promise.resolve(null);var d=null;b.forEach(function(f,h){h.startsWith("$ACTION_REF_")&&(f="$ACTION_"+h.slice(12)+":",d=Za(b,c,f))});if(null===d)return Promise.resolve(null);var g=d.id;return Promise.resolve(d.bound).then(function(f){return null===f?null:[a,e,g,f.length-1]})};p.decodeReply=function(a,b){if("string"===typeof a){var c=new FormData;c.append("0",a);a=c}a=Wa(b,"",a);b=U(a,0);Xa(a);return b};p.registerClientReference=function(a,b,c){return E(a,b+"#"+c,!1)};p.registerServerReference=
function(a,b,c){return Object.defineProperties(a,{$$typeof:{value:W},$$id:{value:null===c?b:b+"#"+c,configurable:!0},$$bound:{value:null,configurable:!0},bind:{value:ua,configurable:!0}})};p.renderToReadableStream=function(a,b,c){var e=ob(a,b,c?c.onError:void 0,c?c.identifierPrefix:void 0,c?c.onPostpone:void 0);if(c&&c.signal){var d=c.signal;if(d.aborted)qa(e,d.reason);else{var g=function(){qa(e,d.reason);d.removeEventListener("abort",g)};d.addEventListener("abort",g)}}return new ReadableStream({type:"bytes",
@@ -57,7 +57,7 @@ const withXcodeTarget = (config, {targetName}) => {
buildSettingsObj.SWIFT_VERSION = '5.0'
buildSettingsObj.TARGETED_DEVICE_FAMILY = `"1"`
buildSettingsObj.DEVELOPMENT_TEAM = 'B3LX46C5HS'
buildSettingsObj.IPHONEOS_DEPLOYMENT_TARGET = '15.1'
buildSettingsObj.IPHONEOS_DEPLOYMENT_TARGET = '14.0'
buildSettingsObj.ASSETCATALOG_COMPILER_APPICON_NAME = 'AppIcon'
}
}
-41
View File
@@ -1,41 +0,0 @@
const {withAppDelegate} = require('@expo/config-plugins')
const {mergeContents} = require('@expo/config-plugins/build/utils/generateCode')
const path = require('path')
const fs = require('fs')
module.exports = config => {
// eslint-disable-next-line no-shadow
return withAppDelegate(config, async config => {
const delegatePath = path.join(
config.modRequest.platformProjectRoot,
'AppDelegate.mm',
)
let newContents = config.modResults.contents
newContents = mergeContents({
src: newContents,
anchor: '// Linking API',
newSrc: `
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:options[UIApplicationOpenURLOptionsSourceApplicationKey] forKey:@"referrerApp"];\n`,
offset: 2,
tag: 'referrer info - deep links',
comment: '//',
}).contents
newContents = mergeContents({
src: newContents,
anchor: '// Universal Links',
newSrc: `
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setURL:userActivity.referrerURL forKey:@"referrer"];\n`,
offset: 2,
tag: 'referrer info - universal links',
comment: '//',
}).contents
config.modResults.contents = newContents
return config
})
}
+11 -10
View File
@@ -2,6 +2,7 @@ const path = require('path')
const fs = require('fs')
const projectRoot = path.join(__dirname, '..')
const webBuildJs = path.join(projectRoot, 'web-build', 'static', 'js')
const templateFile = path.join(
projectRoot,
'bskyweb',
@@ -9,18 +10,18 @@ const templateFile = path.join(
'scripts.html',
)
const {entrypoints} = require(path.join(
projectRoot,
'web-build/asset-manifest.json',
))
const jsFiles = fs.readdirSync(webBuildJs).filter(name => name.endsWith('.js'))
jsFiles.sort((a, b) => {
// make sure main is written last
if (a.startsWith('main')) return 1
if (b.startsWith('main')) return -1
return a.localeCompare(b)
})
console.log(`Found ${entrypoints.length} entrypoints`)
console.log(`Found ${jsFiles.length} js files in web-build`)
console.log(`Writing ${templateFile}`)
const outputFile = entrypoints
.map(name => {
const file = path.basename(name)
return `<script defer="defer" src="/static/js/${file}"></script>`
})
const outputFile = jsFiles
.map(name => `<script defer="defer" src="/static/js/${name}"></script>`)
.join('\n')
fs.writeFileSync(templateFile, outputFile)
+15
View File
@@ -0,0 +1,15 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
# production
/build
.eslintcache
# misc
.DS_Store
npm-debug.log*
yarn-debug.log*
yarn-error.log*
+3
View File
@@ -0,0 +1,3 @@
{
"type": "module"
}

Some files were not shown because too many files have changed in this diff Show More