Live video on the AT Protocol

app: configure atproto agent to use .place lexicons, add place.stream.live.getSegments (#182)

* xrpc: add place.stream.live.getSegments

* app: make use of place.stream.live.getSegments

* app: clean logging

* app: cleanup a bit

* app: bump @atproto to avoid having 2 lexicons embedded lol

* app: fix types post-upgrade

* fixup

authored by

Eli Mallon and committed by
GitHub
6504ba85 7a25b884

+582 -370
-1
js/app/.env
··· 1 - EXPO_USE_METRO_WORKSPACE_ROOT=1
+1 -2
js/app/.env.development
··· 1 1 EXPO_PUBLIC_STREAMPLACE_URL=http://127.0.0.1:38080 2 - EXPO_PUBLIC_WEB_TRY_LOCAL=true 3 - EXPO_USE_METRO_WORKSPACE_ROOT=1 2 + EXPO_PUBLIC_WEB_TRY_LOCAL=true
+1 -2
js/app/.env.production
··· 1 1 EXPO_PUBLIC_STREAMPLACE_URL=https://stream.place 2 - EXPO_PUBLIC_WEB_TRY_LOCAL=true 3 - EXPO_USE_METRO_WORKSPACE_ROOT=0 2 + EXPO_PUBLIC_WEB_TRY_LOCAL=true
+2 -1
js/app/components/chat/chat.tsx
··· 17 17 import { Button, ScrollView, Sheet, Text, useMedia, View } from "tamagui"; 18 18 import { RichText } from "@atproto/api"; 19 19 import { ReactElement } from "react"; 20 + import { isMention } from "@atproto/api/dist/client/types/app/bsky/richtext/facet"; 20 21 21 22 export default function Chat({ 22 23 isChatVisible, ··· 343 344 // Process facets to add DID information for mentions 344 345 rt.facets?.forEach((facet) => { 345 346 facet.features.forEach((feature) => { 346 - if (feature.$type === "app.bsky.richtext.facet#mention") { 347 + if (isMention(feature)) { 347 348 const mentionText = message.record.text.slice( 348 349 facet.index.byteStart, 349 350 facet.index.byteEnd,
+20
js/app/features/bluesky/agent.tsx
··· 1 + import { Agent } from "@atproto/api"; 2 + import { SessionManager } from "@atproto/api/dist/session-manager"; 3 + import { PlaceNS } from "lexicons"; 4 + import { schemas as parentSchemas } from "@atproto/api/dist/client/lexicons"; 5 + import { schemas as appSchemas } from "../../lexicons/lexicons"; 6 + import { Lexicons } from "@atproto/lexicon"; 7 + export class StreamplaceAgent extends Agent { 8 + place = new PlaceNS(this); 9 + lex: Lexicons; 10 + 11 + constructor(options: string | URL | SessionManager) { 12 + super(options); 13 + 14 + const streamplaceSchemas = appSchemas.filter((x) => 15 + x.id.startsWith("place.stream"), 16 + ); 17 + 18 + this.lex = new Lexicons([...parentSchemas, ...streamplaceSchemas]); 19 + } 20 + }
+15 -8
js/app/features/bluesky/blueskySlice.tsx
··· 5 5 BlobRef, 6 6 RichText, 7 7 } from "@atproto/api"; 8 - import { ProfileViewDetailed } from "@atproto/api/src/client/types/app/bsky/actor/defs"; 8 + import { ProfileViewDetailed } from "@atproto/api/dist/client/types/app/bsky/actor/defs"; 9 9 import { bytesToMultibase, Secp256k1Keypair } from "@atproto/crypto"; 10 10 import { hydrate, STORED_KEY_KEY } from "features/base/baseSlice"; 11 11 import { openLoginLink } from "features/platform/platformSlice"; ··· 26 26 import { createAppSlice } from "../../hooks/createSlice"; 27 27 import { BlueskyState } from "./blueskyTypes"; 28 28 import createOAuthClient from "./oauthClient"; 29 + import { StreamplaceAgent } from "./agent"; 30 + import { 31 + isLink, 32 + isMention, 33 + } from "@atproto/api/dist/client/types/app/bsky/richtext/facet"; 29 34 30 35 const initialState: BlueskyState = { 31 36 status: "start", ··· 125 130 ...state, 126 131 client: client, 127 132 oauthSession: initResult.session as any, 128 - pdsAgent: new Agent(initResult.session), 133 + pdsAgent: new StreamplaceAgent(initResult.session), 129 134 }; 130 135 } 131 136 return { ··· 429 434 }, 430 435 ]; 431 436 const record: AppBskyFeedPost.Record = { 437 + $type: "app.bsky.feed.post", 432 438 text: content, 433 439 "place.stream.livestream": { 434 440 url: linkUrl, ··· 490 496 throw new Error("No post"); 491 497 } 492 498 const record: AppBskyFeedPost.Record = { 499 + $type: "app.bsky.feed.post", 493 500 text: text, 494 501 createdAt: new Date().toISOString(), 495 502 reply: { ··· 537 544 throw new Error("No profile"); 538 545 } 539 546 const record: AppBskyGraphBlock.Record = { 547 + $type: "app.bsky.graph.block", 540 548 subject: subjectDID, 541 549 createdAt: new Date().toISOString(), 542 550 }; ··· 621 629 feature.$type === "app.bsky.richtext.facet#mention", 622 630 ) 623 631 .map((feature) => { 624 - if (feature.$type === "app.bsky.richtext.facet#link") { 632 + if (isLink(feature)) { 625 633 return { 626 634 $type: "app.bsky.richtext.facet#link", 627 635 uri: feature.uri, 628 636 }; 629 - } else { 637 + } else if (isMention(feature)) { 630 638 return { 631 639 $type: "app.bsky.richtext.facet#mention", 632 640 did: feature.did, 633 641 }; 642 + } else { 643 + throw new Error("invalid code path"); 634 644 } 635 645 }), 636 646 })), ··· 960 970 if (!res.success) { 961 971 throw new Error("Failed to create chat profile record"); 962 972 } 963 - if (PlaceStreamChatProfile.isRecord(res.data.value)) { 964 - return res.data.value; 965 - } 966 - return null; 973 + return chatProfile; 967 974 }, 968 975 { 969 976 pending: (state) => {
+2 -2
js/app/features/bluesky/blueskyTypes.tsx
··· 1 1 import { OAuthSession } from "@streamplace/atproto-oauth-client-react-native"; 2 - import { Agent } from "@atproto/api"; 3 2 import { ProfileViewDetailed } from "@atproto/api/dist/client/types/app/bsky/actor/defs"; 4 3 import { StreamKey } from "features/base/baseSlice"; 5 4 import { PlaceStreamChatProfile, PlaceStreamLivestream } from "lexicons"; 6 5 import { StreamplaceOAuthClient } from "./oauthClient"; 6 + import { StreamplaceAgent } from "./agent"; 7 7 8 8 type NewLivestream = { 9 9 loading: boolean; ··· 15 15 status: "start" | "loggedIn" | "loggedOut"; 16 16 oauthState: null | string; 17 17 oauthSession: null | OAuthSession; 18 - pdsAgent: null | Agent; 18 + pdsAgent: null | StreamplaceAgent; 19 19 profiles: { [key: string]: ProfileViewDetailed }; 20 20 client: null | StreamplaceOAuthClient; 21 21 login: {
+45
js/app/features/streamplace/streamplaceSlice.tsx
··· 1 1 import { isWeb } from "tamagui"; 2 2 import { createAppSlice } from "../../hooks/createSlice"; 3 3 import Storage from "../../storage"; 4 + import { BlueskyState } from "features/bluesky/blueskyTypes"; 5 + import { SegmentView } from "lexicons/types/place/stream/segment"; 4 6 5 7 let DEFAULT_URL = process.env.EXPO_PUBLIC_STREAMPLACE_URL as string; 6 8 if (isWeb && process.env.EXPO_PUBLIC_WEB_TRY_LOCAL === "true") { ··· 45 47 loading: boolean; 46 48 firstRequest: boolean; 47 49 }; 50 + mySegments: SegmentView[]; 48 51 telemetry: boolean | null; 49 52 userMuted: boolean | null; 50 53 chatWarned: boolean; ··· 60 63 loading: false, 61 64 firstRequest: true, 62 65 }, 66 + mySegments: [], 63 67 telemetry: null, 64 68 userMuted: null, 65 69 chatWarned: false, ··· 237 241 }; 238 242 }, 239 243 rejected: (state, err) => { 244 + console.error("pollSegments rejected", err); 240 245 return { 241 246 ...state, 242 247 recentSegments: { ··· 248 253 }, 249 254 }, 250 255 ), 256 + 257 + pollMySegments: create.asyncThunk( 258 + async (_, { getState, dispatch }) => { 259 + const { streamplace } = getState() as { 260 + streamplace: StreamplaceState; 261 + }; 262 + const { bluesky } = getState() as { 263 + bluesky: BlueskyState; 264 + }; 265 + 266 + if (!bluesky.pdsAgent) { 267 + throw new Error("no pdsAgent"); 268 + } 269 + return await bluesky.pdsAgent.place.stream.live.getSegments({ 270 + userDID: bluesky.oauthSession?.did, 271 + }); 272 + }, 273 + { 274 + pending: (state) => { 275 + return { 276 + ...state, 277 + }; 278 + }, 279 + fulfilled: (state, action) => { 280 + return { 281 + ...state, 282 + mySegments: action.payload.data.segments ?? [], 283 + }; 284 + }, 285 + rejected: (state, err) => { 286 + console.error("pollMySegments rejected", err); 287 + return { 288 + ...state, 289 + }; 290 + }, 291 + }, 292 + ), 251 293 }), 252 294 253 295 selectors: { 254 296 selectStreamplace: (streamplace) => streamplace, 255 297 selectUrl: (streamplace) => streamplace.url, 256 298 selectRecentSegments: (streamplace) => streamplace.recentSegments, 299 + selectMySegments: (streamplace) => streamplace.mySegments, 257 300 selectTelemetry: (streamplace) => streamplace.telemetry, 258 301 selectUserMuted: (streamplace) => streamplace.userMuted, 259 302 selectChatWarned: (streamplace) => streamplace.chatWarned, ··· 266 309 setURL, 267 310 initialize, 268 311 pollSegments, 312 + pollMySegments, 269 313 telemetryOpt, 270 314 userMute, 271 315 chatWarn, ··· 273 317 export const { 274 318 selectStreamplace, 275 319 selectRecentSegments, 320 + selectMySegments, 276 321 selectTelemetry, 277 322 selectUserMuted, 278 323 selectChatWarned,
+13 -9
js/app/hooks/useLiveUser.tsx
··· 1 - import { selectUserProfile } from "features/bluesky/blueskySlice"; 2 - import { selectRecentSegments } from "features/streamplace/streamplaceSlice"; 1 + import { selectMySegments } from "features/streamplace/streamplaceSlice"; 2 + import { isRecord } from "lexicons/types/place/stream/segment"; 3 3 import { useAppSelector } from "store/hooks"; 4 + import { PlaceStreamSegment } from "lexicons"; 4 5 5 6 // composite selector that tells us when the current user is live 6 7 export const useLiveUser = (): boolean => { 7 - const profile = useAppSelector(selectUserProfile); 8 - const { segments } = useAppSelector(selectRecentSegments); 9 - if (!profile) { 8 + const mySegments = useAppSelector(selectMySegments); 9 + if (mySegments.length === 0) { 10 10 return false; 11 11 } 12 - const isLive = segments.some( 13 - (segment) => segment.repo && segment.repo.did === profile.did, 14 - ); 15 - return isLive; 12 + if (!isRecord(mySegments[0].record)) { 13 + return false; 14 + } 15 + const record = mySegments[0].record as PlaceStreamSegment.Record; 16 + if (Date.now() - new Date(record.startTime).getTime() < 1000 * 10) { 17 + return true; 18 + } 19 + return false; 16 20 };
+6 -3
js/app/package.json
··· 26 26 }, 27 27 "dependencies": { 28 28 "@atproto-labs/pipe": "^0.1.0", 29 - "@atproto/crypto": "^0.4.2", 30 - "@atproto/jwk-jose": "^0.1.2", 31 - "@atproto/oauth-client": "^0.3.1", 29 + "@atproto/api": "^0.15.7", 30 + "@atproto/crypto": "^0.4.4", 31 + "@atproto/jwk-jose": "^0.1.6", 32 + "@atproto/jwk-webcrypto": "^0.1.6", 33 + "@atproto/oauth-client": "^0.3.16", 34 + "@atproto/oauth-client-browser": "^0.3.16", 32 35 "@bacons/text-decoder": "^0.0.0", 33 36 "@emoji-mart/react": "^1.1.1", 34 37 "@rainbow-me/rainbowkit": "2.2.0",
+8 -3
js/app/src/router.tsx
··· 32 32 import { Provider, Settings } from "components"; 33 33 import AQLink from "components/aqlink"; 34 34 import Login from "components/login/login"; 35 - import StreamList from "components/stream-list/stream-list"; 36 35 import { selectUserProfile } from "features/bluesky/blueskySlice"; 37 36 import usePlatform from "hooks/usePlatform"; 38 37 import { ReactElement, useEffect, useState } from "react"; ··· 45 44 StatusBar, 46 45 } from "react-native"; 47 46 import { useAppDispatch, useAppSelector } from "store/hooks"; 48 - import { useTheme, Text, View, H3, useWindowDimensions } from "tamagui"; 47 + import { useTheme, Text, View, H3 } from "tamagui"; 49 48 import AppReturnScreen from "./screens/app-return"; 50 49 import MultiScreen from "./screens/multi"; 51 50 import StreamScreen from "./screens/stream"; ··· 61 60 selectNotificationDestination, 62 61 selectNotificationToken, 63 62 } from "features/platform/platformSlice.native"; 64 - import { pollSegments } from "features/streamplace/streamplaceSlice"; 63 + import { 64 + pollMySegments, 65 + pollSegments, 66 + } from "features/streamplace/streamplaceSlice"; 65 67 import { useLiveUser } from "hooks/useLiveUser"; 66 68 import { useToastController } from "@tamagui/toast"; 67 69 import LiveDashboard from "./screens/live-dashboard"; ··· 74 76 // probabl should move this 75 77 import { store } from "store/store"; 76 78 import { loadStateFromStorage } from "features/base/sidebarSlice"; 79 + import StreamList from "components/stream-list/stream-list"; 77 80 78 81 store.dispatch(loadStateFromStorage()); 79 82 ··· 311 314 // Top-level stuff to handle polling for live streamers 312 315 useEffect(() => { 313 316 dispatch(pollSegments()); 317 + dispatch(pollMySegments()); 314 318 const interval = setInterval(() => { 315 319 dispatch(pollSegments()); 320 + dispatch(pollMySegments()); 316 321 }, 5000); 317 322 return () => clearInterval(interval); 318 323 }, []);
+11 -11
js/atproto-oauth-client-react-native/package.json
··· 28 28 "dist" 29 29 ], 30 30 "dependencies": { 31 - "@atproto-labs/did-resolver": "0.1.5", 32 - "@atproto-labs/handle-resolver-node": "0.1.7", 33 - "@atproto-labs/simple-store": "0.1.1", 34 - "@atproto-labs/simple-store-memory": "0.1.1", 35 - "@atproto/did": "0.1.3", 36 - "@atproto/jwk": "0.1.1", 37 - "@atproto/jwk-jose": "0.1.2", 38 - "@atproto/jwk-webcrypto": "0.1.2", 39 - "@atproto/oauth-client": "0.3.2", 40 - "@atproto/oauth-client-browser": "0.3.2", 41 - "@atproto/oauth-types": "0.2.1", 31 + "@atproto-labs/did-resolver": "0.1.12", 32 + "@atproto-labs/handle-resolver-node": "0.1.15", 33 + "@atproto-labs/simple-store": "0.2.0", 34 + "@atproto-labs/simple-store-memory": "0.1.3", 35 + "@atproto/did": "0.1.5", 36 + "@atproto/jwk": "0.1.5", 37 + "@atproto/jwk-jose": "0.1.6", 38 + "@atproto/jwk-webcrypto": "0.1.6", 39 + "@atproto/oauth-client": "0.3.16", 40 + "@atproto/oauth-client-browser": "0.3.16", 41 + "@atproto/oauth-types": "0.2.7", 42 42 "abortcontroller-polyfill": "^1.7.6", 43 43 "event-target-shim": "^6.0.2", 44 44 "expo-sqlite": "^15.0.3",
+1 -1
js/desktop/package.json
··· 48 48 }, 49 49 "license": "MIT", 50 50 "dependencies": { 51 - "@atproto/crypto": "^0.4.3", 51 + "@atproto/crypto": "^0.4.4", 52 52 "electron-squirrel-startup": "^1.0.1", 53 53 "source-map-support": "^0.5.21", 54 54 "update-electron-app": "^3.0.0",
+88
js/docs/src/content/docs/lex-reference/live/place-stream-live-getsegments.md
··· 1 + --- 2 + title: place.stream.live.getSegments 3 + description: Reference for the place.stream.live.getSegments lexicon 4 + --- 5 + 6 + **Lexicon Version:** 1 7 + 8 + ## Definitions 9 + 10 + <a name="main"></a> 11 + 12 + ### `main` 13 + 14 + **Type:** `query` 15 + 16 + Get a list of livestream segments for a user 17 + 18 + **Parameters:** 19 + 20 + | Name | Type | Req'd | Description | Constraints | 21 + | --------- | --------- | ----- | ----------------------------------------- | ------------------------------------- | 22 + | `userDID` | `string` | ✅ | The DID of the potentially-following user | Format: `did` | 23 + | `limit` | `integer` | ❌ | | Min: 1<br/>Max: 100<br/>Default: `50` | 24 + | `before` | `string` | ❌ | | Format: `datetime` | 25 + 26 + **Output:** 27 + 28 + - **Encoding:** `application/json` 29 + - **Schema:** 30 + 31 + **Schema Type:** `object` 32 + 33 + | Name | Type | Req'd | Description | Constraints | 34 + | ---------- | ---------------------------------------------------------------------------------------------- | ----- | ----------- | ----------- | 35 + | `segments` | Array of [`place.stream.segment#segmentView`](/lex-reference/place-stream-segment#segmentview) | ❌ | | | 36 + 37 + --- 38 + 39 + ## Lexicon Source 40 + 41 + ```json 42 + { 43 + "lexicon": 1, 44 + "id": "place.stream.live.getSegments", 45 + "defs": { 46 + "main": { 47 + "type": "query", 48 + "description": "Get a list of livestream segments for a user", 49 + "parameters": { 50 + "type": "params", 51 + "required": ["userDID"], 52 + "properties": { 53 + "userDID": { 54 + "type": "string", 55 + "format": "did", 56 + "description": "The DID of the potentially-following user" 57 + }, 58 + "limit": { 59 + "type": "integer", 60 + "minimum": 1, 61 + "maximum": 100, 62 + "default": 50 63 + }, 64 + "before": { 65 + "type": "string", 66 + "format": "datetime" 67 + } 68 + } 69 + }, 70 + "output": { 71 + "encoding": "application/json", 72 + "schema": { 73 + "type": "object", 74 + "properties": { 75 + "segments": { 76 + "type": "array", 77 + "items": { 78 + "type": "ref", 79 + "ref": "place.stream.segment#segmentView" 80 + } 81 + } 82 + } 83 + } 84 + } 85 + } 86 + } 87 + } 88 + ```
+28
js/docs/src/content/docs/lex-reference/place-stream-segment.md
··· 79 79 80 80 --- 81 81 82 + <a name="segmentview"></a> 83 + 84 + ### `segmentView` 85 + 86 + **Type:** `object` 87 + 88 + **Properties:** 89 + 90 + | Name | Type | Req'd | Description | Constraints | 91 + | -------- | --------- | ----- | ----------- | ------------- | 92 + | `cid` | `string` | ✅ | | Format: `cid` | 93 + | `record` | `unknown` | ✅ | | | 94 + 95 + --- 96 + 82 97 ## Lexicon Source 83 98 84 99 ```json ··· 177 192 }, 178 193 "den": { 179 194 "type": "integer" 195 + } 196 + } 197 + }, 198 + "segmentView": { 199 + "type": "object", 200 + "required": ["cid", "record"], 201 + "properties": { 202 + "cid": { 203 + "type": "string", 204 + "format": "cid" 205 + }, 206 + "record": { 207 + "type": "unknown" 180 208 } 181 209 } 182 210 }
+43
lexicons/place/stream/live/getSegments.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "place.stream.live.getSegments", 4 + "defs": { 5 + "main": { 6 + "type": "query", 7 + "description": "Get a list of livestream segments for a user", 8 + "parameters": { 9 + "type": "params", 10 + "required": ["userDID"], 11 + "properties": { 12 + "userDID": { 13 + "type": "string", 14 + "format": "did", 15 + "description": "The DID of the potentially-following user" 16 + }, 17 + "limit": { 18 + "type": "integer", 19 + "minimum": 1, 20 + "maximum": 100, 21 + "default": 50 22 + }, 23 + "before": { "type": "string", "format": "datetime" } 24 + } 25 + }, 26 + "output": { 27 + "encoding": "application/json", 28 + "schema": { 29 + "type": "object", 30 + "properties": { 31 + "segments": { 32 + "type": "array", 33 + "items": { 34 + "type": "ref", 35 + "ref": "place.stream.segment#segmentView" 36 + } 37 + } 38 + } 39 + } 40 + } 41 + } 42 + } 43 + }
+8
lexicons/place/stream/segment.json
··· 77 77 "num": { "type": "integer" }, 78 78 "den": { "type": "integer" } 79 79 } 80 + }, 81 + "segmentView": { 82 + "type": "object", 83 + "required": ["cid", "record"], 84 + "properties": { 85 + "cid": { "type": "string", "format": "cid" }, 86 + "record": { "type": "unknown" } 87 + } 80 88 } 81 89 } 82 90 }
-3
package.json
··· 36 36 ], 37 37 "packageManager": "yarn@4.3.0", 38 38 "dependencies": { 39 - "@atproto/api": "^0.13.16", 40 - "@atproto/jwk-webcrypto": "^0.1.2", 41 - "@atproto/oauth-client-browser": "^0.3.1", 42 39 "firebase-admin": "^12.7.0", 43 40 "lex-md": "^0.0.3" 44 41 }
+1
pkg/model/model.go
··· 36 36 CreateSegment(segment *Segment) error 37 37 MostRecentSegments() ([]Segment, error) 38 38 LatestSegmentForUser(user string) (*Segment, error) 39 + LatestSegmentsForUser(user string, limit int, before *time.Time) ([]Segment, error) 39 40 CreateThumbnail(thumb *Thumbnail) error 40 41 LatestThumbnailForUser(user string) (*Thumbnail, error) 41 42 GetSegment(id string) (*Segment, error)
+13
pkg/model/segment.go
··· 155 155 return &seg, nil 156 156 } 157 157 158 + func (m *DBModel) LatestSegmentsForUser(user string, limit int, before *time.Time) ([]Segment, error) { 159 + var segs []Segment 160 + if before == nil { 161 + later := time.Now().Add(1000 * time.Hour) 162 + before = &later 163 + } 164 + err := m.DB.Model(Segment{}).Where("repo_did = ? AND start_time < ?", user, before.UTC()).Order("start_time DESC").Limit(limit).Find(&segs).Error 165 + if err != nil { 166 + return nil, err 167 + } 168 + return segs, nil 169 + } 170 + 158 171 func (m *DBModel) GetLiveUsers() ([]Segment, error) { 159 172 var liveUsers []Segment 160 173 thirtySecondsAgo := aqtime.FromTime(time.Now().Add(-30 * time.Second)).Time()
+73
pkg/spxrpc/place_stream_live.go
··· 1 + package spxrpc 2 + 3 + import ( 4 + "bytes" 5 + "context" 6 + "fmt" 7 + "net/http" 8 + "time" 9 + 10 + "github.com/bluesky-social/indigo/lex/util" 11 + "github.com/bluesky-social/indigo/repo" 12 + "github.com/ipfs/go-cid" 13 + "github.com/labstack/echo/v4" 14 + "github.com/multiformats/go-multihash" 15 + placestreamtypes "stream.place/streamplace/pkg/streamplace" 16 + ) 17 + 18 + func (s *Server) handlePlaceStreamLiveGetSegments(ctx context.Context, before string, limit int, userDID string) (*placestreamtypes.LiveGetSegments_Output, error) { 19 + if userDID == "" { 20 + return nil, echo.NewHTTPError(http.StatusBadRequest, "User DID is required") 21 + } 22 + var beforeTime *time.Time 23 + if before != "" { 24 + parsedTime, err := time.Parse(time.RFC3339, before) 25 + if err != nil { 26 + return nil, echo.NewHTTPError(http.StatusBadRequest, "Invalid 'before' parameter: must be RFC3339 format") 27 + } 28 + beforeTime = &parsedTime 29 + } 30 + 31 + segments, err := s.model.LatestSegmentsForUser(userDID, limit, beforeTime) 32 + if err != nil { 33 + return nil, echo.NewHTTPError(http.StatusInternalServerError, "Failed to fetch segments") 34 + } 35 + 36 + // Convert segments to the expected output format 37 + output := &placestreamtypes.LiveGetSegments_Output{ 38 + Segments: make([]*placestreamtypes.Segment_SegmentView, len(segments)), 39 + } 40 + 41 + for i, segment := range segments { 42 + record, err := segment.ToStreamplaceSegment() 43 + if err != nil { 44 + return nil, echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Failed to convert segment to streamplace segment: %s", err)) 45 + } 46 + c, err := getCID(record) 47 + if err != nil { 48 + return nil, echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Failed to get CID: %s", err)) 49 + } 50 + ltd := &util.LexiconTypeDecoder{Val: record} 51 + 52 + output.Segments[i] = &placestreamtypes.Segment_SegmentView{ 53 + Record: ltd, 54 + Cid: c.String(), 55 + } 56 + } 57 + 58 + return output, nil 59 + } 60 + 61 + func getCID(record repo.CborMarshaler) (*cid.Cid, error) { 62 + builder := cid.NewPrefixV1(cid.DagCBOR, multihash.SHA2_256) 63 + buf := bytes.NewBuffer(nil) 64 + err := record.MarshalCBOR(buf) 65 + if err != nil { 66 + return nil, err 67 + } 68 + c, err := builder.Sum(buf.Bytes()) 69 + if err != nil { 70 + return nil, err 71 + } 72 + return &c, nil 73 + }
+27
pkg/spxrpc/stubs.go
··· 97 97 98 98 func (s *Server) RegisterHandlersPlaceStream(e *echo.Echo) error { 99 99 e.GET("/xrpc/place.stream.graph.getFollowingUser", s.HandlePlaceStreamGraphGetFollowingUser) 100 + e.GET("/xrpc/place.stream.live.getSegments", s.HandlePlaceStreamLiveGetSegments) 100 101 return nil 101 102 } 102 103 ··· 109 110 var handleErr error 110 111 // func (s *Server) handlePlaceStreamGraphGetFollowingUser(ctx context.Context,subjectDID string,userDID string) (*placestreamtypes.GraphGetFollowingUser_Output, error) 111 112 out, handleErr = s.handlePlaceStreamGraphGetFollowingUser(ctx, subjectDID, userDID) 113 + if handleErr != nil { 114 + return handleErr 115 + } 116 + return c.JSON(200, out) 117 + } 118 + 119 + func (s *Server) HandlePlaceStreamLiveGetSegments(c echo.Context) error { 120 + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandlePlaceStreamLiveGetSegments") 121 + defer span.End() 122 + before := c.QueryParam("before") 123 + 124 + var limit int 125 + if p := c.QueryParam("limit"); p != "" { 126 + var err error 127 + limit, err = strconv.Atoi(p) 128 + if err != nil { 129 + return err 130 + } 131 + } else { 132 + limit = 50 133 + } 134 + userDID := c.QueryParam("userDID") 135 + var out *placestreamtypes.LiveGetSegments_Output 136 + var handleErr error 137 + // func (s *Server) handlePlaceStreamLiveGetSegments(ctx context.Context,before string,limit int,userDID string) (*placestreamtypes.LiveGetSegments_Output, error) 138 + out, handleErr = s.handlePlaceStreamLiveGetSegments(ctx, before, limit, userDID) 112 139 if handleErr != nil { 113 140 return handleErr 114 141 }
+34
pkg/streamplace/livegetSegments.go
··· 1 + // Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. 2 + 3 + package streamplace 4 + 5 + // schema: place.stream.live.getSegments 6 + 7 + import ( 8 + "context" 9 + 10 + "github.com/bluesky-social/indigo/xrpc" 11 + ) 12 + 13 + // LiveGetSegments_Output is the output of a place.stream.live.getSegments call. 14 + type LiveGetSegments_Output struct { 15 + Segments []*Segment_SegmentView `json:"segments,omitempty" cborgen:"segments,omitempty"` 16 + } 17 + 18 + // LiveGetSegments calls the XRPC method "place.stream.live.getSegments". 19 + // 20 + // userDID: The DID of the potentially-following user 21 + func LiveGetSegments(ctx context.Context, c *xrpc.Client, before string, limit int64, userDID string) (*LiveGetSegments_Output, error) { 22 + var out LiveGetSegments_Output 23 + 24 + params := map[string]interface{}{ 25 + "before": before, 26 + "limit": limit, 27 + "userDID": userDID, 28 + } 29 + if err := c.Do(ctx, xrpc.Query, "", "place.stream.live.getSegments", params, nil, &out); err != nil { 30 + return nil, err 31 + } 32 + 33 + return &out, nil 34 + }
+6
pkg/streamplace/streamsegment.go
··· 40 40 Num int64 `json:"num" cborgen:"num"` 41 41 } 42 42 43 + // Segment_SegmentView is a "segmentView" in the place.stream.segment schema. 44 + type Segment_SegmentView struct { 45 + Cid string `json:"cid" cborgen:"cid"` 46 + Record *util.LexiconTypeDecoder `json:"record" cborgen:"record"` 47 + } 48 + 43 49 // Segment_Video is a "video" in the place.stream.segment schema. 44 50 type Segment_Video struct { 45 51 Codec string `json:"codec" cborgen:"codec"`
+136 -324
yarn.lock
··· 191 191 languageName: node 192 192 linkType: hard 193 193 194 - "@atproto-labs/did-resolver@npm:0.1.11": 195 - version: 0.1.11 196 - resolution: "@atproto-labs/did-resolver@npm:0.1.11" 194 + "@atproto-labs/did-resolver@npm:0.1.12": 195 + version: 0.1.12 196 + resolution: "@atproto-labs/did-resolver@npm:0.1.12" 197 197 dependencies: 198 198 "@atproto-labs/fetch": "npm:0.2.2" 199 199 "@atproto-labs/pipe": "npm:0.1.0" 200 - "@atproto-labs/simple-store": "npm:0.1.2" 201 - "@atproto-labs/simple-store-memory": "npm:0.1.2" 200 + "@atproto-labs/simple-store": "npm:0.2.0" 201 + "@atproto-labs/simple-store-memory": "npm:0.1.3" 202 202 "@atproto/did": "npm:0.1.5" 203 203 zod: "npm:^3.23.8" 204 - checksum: 10/9c5edbf7814046926fa7aec9783196d40edd9e8c3a3c1cd553146749794ed3c54f668d11e0582f49656c27c596acee541ae8f24993221800958706122e412749 204 + checksum: 10/f5a3ef64734e4a7432ee7ccf34b7e53b5fc2966d64c831b16fbda8f95e0161c9bc60655ddb103529842b8deb19f735f94f8a535671c3950be38ba903743cd8d4 205 205 languageName: node 206 206 linkType: hard 207 207 208 - "@atproto-labs/did-resolver@npm:0.1.5": 209 - version: 0.1.5 210 - resolution: "@atproto-labs/did-resolver@npm:0.1.5" 208 + "@atproto-labs/fetch-node@npm:0.1.8": 209 + version: 0.1.8 210 + resolution: "@atproto-labs/fetch-node@npm:0.1.8" 211 211 dependencies: 212 - "@atproto-labs/fetch": "npm:0.1.1" 213 - "@atproto-labs/pipe": "npm:0.1.0" 214 - "@atproto-labs/simple-store": "npm:0.1.1" 215 - "@atproto-labs/simple-store-memory": "npm:0.1.1" 216 - "@atproto/did": "npm:0.1.3" 217 - zod: "npm:^3.23.8" 218 - checksum: 10/a1fccf30df2eb2e9f2c9df2e22e78fd63ccfc8024085b7783876d6914b7f1acd664e5b298ab744ca71f22ea70a44a5478fa8af3b4648c40649082ecca7d37c85 219 - languageName: node 220 - linkType: hard 221 - 222 - "@atproto-labs/fetch-node@npm:0.1.3": 223 - version: 0.1.3 224 - resolution: "@atproto-labs/fetch-node@npm:0.1.3" 225 - dependencies: 226 - "@atproto-labs/fetch": "npm:0.1.1" 212 + "@atproto-labs/fetch": "npm:0.2.2" 227 213 "@atproto-labs/pipe": "npm:0.1.0" 228 214 ipaddr.js: "npm:^2.1.0" 229 215 psl: "npm:^1.9.0" 230 216 undici: "npm:^6.14.1" 231 - checksum: 10/7d8e13bd42998be7ece29e9418cf10b0ebf2b90967ca009b5e03e767153f4e3025ac0c67f9cdfe3e02561c8dfc9a961d407b3613b7c8302465526e7233ff9d2b 232 - languageName: node 233 - linkType: hard 234 - 235 - "@atproto-labs/fetch@npm:0.1.1": 236 - version: 0.1.1 237 - resolution: "@atproto-labs/fetch@npm:0.1.1" 238 - dependencies: 239 - "@atproto-labs/pipe": "npm:0.1.0" 240 - zod: "npm:^3.23.8" 241 - dependenciesMeta: 242 - zod: 243 - optional: true 244 - checksum: 10/557f290e1a0078f022e74b1b663b782979d9a378e6f7575d50cd2eafd1cf20aa52986544b01b586c30505704ec5624630e8718826c7d08768ac775a3b059bae0 217 + checksum: 10/b8291294d029a99a6c931c27de59a6a46fd4ad8af842548a3687b2b0a8de50dbefef1752bc3677973550e712279467ad22ac8617ed06833b442225184398e5de 245 218 languageName: node 246 219 linkType: hard 247 220 ··· 254 227 languageName: node 255 228 linkType: hard 256 229 257 - "@atproto-labs/handle-resolver-node@npm:0.1.7": 258 - version: 0.1.7 259 - resolution: "@atproto-labs/handle-resolver-node@npm:0.1.7" 260 - dependencies: 261 - "@atproto-labs/fetch-node": "npm:0.1.3" 262 - "@atproto-labs/handle-resolver": "npm:0.1.4" 263 - "@atproto/did": "npm:0.1.3" 264 - checksum: 10/d7f1896a7154978a8037a443ae8c1d6786febcfebb77f2e1a09eca6083ecc51f5a4473a49779b9720cc9e17bbd335111339b139b2e6112e3d1403e5af3f2f986 265 - languageName: node 266 - linkType: hard 267 - 268 - "@atproto-labs/handle-resolver@npm:0.1.4": 269 - version: 0.1.4 270 - resolution: "@atproto-labs/handle-resolver@npm:0.1.4" 230 + "@atproto-labs/handle-resolver-node@npm:0.1.15": 231 + version: 0.1.15 232 + resolution: "@atproto-labs/handle-resolver-node@npm:0.1.15" 271 233 dependencies: 272 - "@atproto-labs/simple-store": "npm:0.1.1" 273 - "@atproto-labs/simple-store-memory": "npm:0.1.1" 274 - "@atproto/did": "npm:0.1.3" 275 - zod: "npm:^3.23.8" 276 - checksum: 10/5679823cd0b4656e9d4345bbd4245493c314799712302066837a07e58d48d673dd0725dea5f37c12b6af14f08435585a9316c706fcbd42e376ae1a5c8a175f13 234 + "@atproto-labs/fetch-node": "npm:0.1.8" 235 + "@atproto-labs/handle-resolver": "npm:0.1.8" 236 + "@atproto/did": "npm:0.1.5" 237 + checksum: 10/937fdb42e4ee05120247fdf5f756f4e994fab660e6731998302a8a7f2ee06aaf8c49500bb352a68aa258b0a540369318619e0ed43f84046b536bdc6ad1ea5e3a 277 238 languageName: node 278 239 linkType: hard 279 240 280 - "@atproto-labs/handle-resolver@npm:0.1.7": 281 - version: 0.1.7 282 - resolution: "@atproto-labs/handle-resolver@npm:0.1.7" 241 + "@atproto-labs/handle-resolver@npm:0.1.8": 242 + version: 0.1.8 243 + resolution: "@atproto-labs/handle-resolver@npm:0.1.8" 283 244 dependencies: 284 - "@atproto-labs/simple-store": "npm:0.1.2" 285 - "@atproto-labs/simple-store-memory": "npm:0.1.2" 245 + "@atproto-labs/simple-store": "npm:0.2.0" 246 + "@atproto-labs/simple-store-memory": "npm:0.1.3" 286 247 "@atproto/did": "npm:0.1.5" 287 248 zod: "npm:^3.23.8" 288 - checksum: 10/9ce9bb7d9cd4613f6d37ee6ed2846ee8646557280691c0ff69dc0ce3e5ed96ceb7ed1e89c0e22fad2748e056402ebea0e3caff799f24d69ea462f9a2cf7b30ad 289 - languageName: node 290 - linkType: hard 291 - 292 - "@atproto-labs/identity-resolver@npm:0.1.14": 293 - version: 0.1.14 294 - resolution: "@atproto-labs/identity-resolver@npm:0.1.14" 295 - dependencies: 296 - "@atproto-labs/did-resolver": "npm:0.1.11" 297 - "@atproto-labs/handle-resolver": "npm:0.1.7" 298 - "@atproto/syntax": "npm:0.3.4" 299 - checksum: 10/2849ac884109c3e1ed83b5f29092a3517d74e51673ca3d7c8b0d153ba007d30d89e86b5f29eb76c2538dbc3183fdcadd5cd1aa046066b6c46baa1109eea444dd 249 + checksum: 10/b62cc4e2c8beefcfe2083bd29a3a4280df7d132ad325910c3eecc405a8024d5c7ca229d08bda5d7fa3f456fd241d26922bb7553d0b6c03f9c4b71f72a972ea98 300 250 languageName: node 301 251 linkType: hard 302 252 303 - "@atproto-labs/identity-resolver@npm:0.1.6": 304 - version: 0.1.6 305 - resolution: "@atproto-labs/identity-resolver@npm:0.1.6" 253 + "@atproto-labs/identity-resolver@npm:0.1.16": 254 + version: 0.1.16 255 + resolution: "@atproto-labs/identity-resolver@npm:0.1.16" 306 256 dependencies: 307 - "@atproto-labs/did-resolver": "npm:0.1.5" 308 - "@atproto-labs/handle-resolver": "npm:0.1.4" 309 - "@atproto/syntax": "npm:0.3.1" 310 - checksum: 10/23edc253bb7a2b5989ad8fb12afb047e55a0f646879d934d8a2619d70d2e8be7d68a95bc3376c175026d3f0e5392abd220a4972aa27621098bce241f7897f475 257 + "@atproto-labs/did-resolver": "npm:0.1.12" 258 + "@atproto-labs/handle-resolver": "npm:0.1.8" 259 + "@atproto/syntax": "npm:0.4.0" 260 + checksum: 10/32c4bc845c1ceaf1ae5c71a18f989ff529fedad7acc8342e40f07560ec35ba650e622aa37ab39be87acbb7d794db391351ff3f10d8f4221ee1b1c45af0a981f3 311 261 languageName: node 312 262 linkType: hard 313 263 ··· 318 268 languageName: node 319 269 linkType: hard 320 270 321 - "@atproto-labs/simple-store-memory@npm:0.1.1": 322 - version: 0.1.1 323 - resolution: "@atproto-labs/simple-store-memory@npm:0.1.1" 271 + "@atproto-labs/simple-store-memory@npm:0.1.3": 272 + version: 0.1.3 273 + resolution: "@atproto-labs/simple-store-memory@npm:0.1.3" 324 274 dependencies: 325 - "@atproto-labs/simple-store": "npm:0.1.1" 275 + "@atproto-labs/simple-store": "npm:0.2.0" 326 276 lru-cache: "npm:^10.2.0" 327 - checksum: 10/b9dfc23c7bcef6b7049015385d5cf611df27d5c4eb4b5c331a1eec7ec77391a12993a984474d6f39e6c907d5f86659e4defc35b62e73e3acf3874255077896f7 277 + checksum: 10/87f2650b613ddec5aa1b31fc9a1ca6321d6ccacc3bda8c6d5de0974de78c0f7b06078b1bee5a25e58cd03bcc5b7437f4533ff355c29e762820e31ee1c6f9d82f 328 278 languageName: node 329 279 linkType: hard 330 280 331 - "@atproto-labs/simple-store-memory@npm:0.1.2": 332 - version: 0.1.2 333 - resolution: "@atproto-labs/simple-store-memory@npm:0.1.2" 334 - dependencies: 335 - "@atproto-labs/simple-store": "npm:0.1.2" 336 - lru-cache: "npm:^10.2.0" 337 - checksum: 10/7bc79e4a496b47677740175c8fb4010790dceff02056399fa4d871db1c8292667a4011f5a4743e77277377e1f4d692286e06440d23cdfd568dcc738bc6d4c9bd 281 + "@atproto-labs/simple-store@npm:0.2.0": 282 + version: 0.2.0 283 + resolution: "@atproto-labs/simple-store@npm:0.2.0" 284 + checksum: 10/5873af563b491deb047b2d794837ad3f66574b1a437a73eebe413434505e88014e857baebcf5bdad4d45c7bb5094c8d7019cc537618b3479f7545cf6131c4f17 338 285 languageName: node 339 286 linkType: hard 340 287 341 - "@atproto-labs/simple-store@npm:0.1.1": 342 - version: 0.1.1 343 - resolution: "@atproto-labs/simple-store@npm:0.1.1" 344 - checksum: 10/6251663e6ee07fc59e77cf3aeebcd4f980a18f83e9bfc20be12dae0fbcdaaecc7a88a2d558e625ff2f0db7176b75f44d61b37cb892ae67241248655a9a4d1615 345 - languageName: node 346 - linkType: hard 347 - 348 - "@atproto-labs/simple-store@npm:0.1.2": 349 - version: 0.1.2 350 - resolution: "@atproto-labs/simple-store@npm:0.1.2" 351 - checksum: 10/61b0aa1375ce4a46233c53d24b9c3950cc27ed95dd917b48d3188baa1d892d1cb17cacaeade37945cb93425a30db1200564cc0641e808765d5026deb43e7aacf 352 - languageName: node 353 - linkType: hard 354 - 355 - "@atproto/api@npm:^0.13.16": 356 - version: 0.13.16 357 - resolution: "@atproto/api@npm:0.13.16" 288 + "@atproto/api@npm:^0.15.7": 289 + version: 0.15.7 290 + resolution: "@atproto/api@npm:0.15.7" 358 291 dependencies: 359 - "@atproto/common-web": "npm:^0.3.1" 360 - "@atproto/lexicon": "npm:^0.4.3" 361 - "@atproto/syntax": "npm:^0.3.1" 362 - "@atproto/xrpc": "npm:^0.6.4" 292 + "@atproto/common-web": "npm:^0.4.2" 293 + "@atproto/lexicon": "npm:^0.4.11" 294 + "@atproto/syntax": "npm:^0.4.0" 295 + "@atproto/xrpc": "npm:^0.7.0" 363 296 await-lock: "npm:^2.2.2" 364 297 multiformats: "npm:^9.9.0" 365 298 tlds: "npm:^1.234.0" 366 299 zod: "npm:^3.23.8" 367 - checksum: 10/0b959ba17d7453955442a8aa771951f27d35a0606d1105408f25b9b3829d4e87d0860e6c3f1af35178c2acf0deb7219452fed648847da18b25fa5b6414167127 300 + checksum: 10/42071e470dd1354128fe2062933706444ea4305f0a5856d8b17e363bafcd91c4294952369820da51584784ea64b2fa95e31322b1a5b89c772c65e8915d0eb0cd 368 301 languageName: node 369 302 linkType: hard 370 303 371 - "@atproto/common-web@npm:^0.3.1": 372 - version: 0.3.1 373 - resolution: "@atproto/common-web@npm:0.3.1" 304 + "@atproto/common-web@npm:^0.4.0": 305 + version: 0.4.0 306 + resolution: "@atproto/common-web@npm:0.4.0" 374 307 dependencies: 375 308 graphemer: "npm:^1.4.0" 376 309 multiformats: "npm:^9.9.0" 377 310 uint8arrays: "npm:3.0.0" 378 311 zod: "npm:^3.23.8" 379 - checksum: 10/185ddf35df2138eb5143380e8b2e3fa2d7517db5297251ef735163e97f710fba19a3e3af99e11d40b825ff5cefa271e1763714574b2ed4a2a5beb8305cf48687 312 + checksum: 10/1d0f5245ab953eb7e226c088d5c29a171a36eefe5d898f3a6277a90888ac44be8ddbfd3dbcb1bb97b988b29cfc74136a8ee1c3b9a2cf1a667a22264a418bbdb9 380 313 languageName: node 381 314 linkType: hard 382 315 383 - "@atproto/common-web@npm:^0.4.0": 384 - version: 0.4.0 385 - resolution: "@atproto/common-web@npm:0.4.0" 316 + "@atproto/common-web@npm:^0.4.2": 317 + version: 0.4.2 318 + resolution: "@atproto/common-web@npm:0.4.2" 386 319 dependencies: 387 320 graphemer: "npm:^1.4.0" 388 321 multiformats: "npm:^9.9.0" 389 322 uint8arrays: "npm:3.0.0" 390 323 zod: "npm:^3.23.8" 391 - checksum: 10/1d0f5245ab953eb7e226c088d5c29a171a36eefe5d898f3a6277a90888ac44be8ddbfd3dbcb1bb97b988b29cfc74136a8ee1c3b9a2cf1a667a22264a418bbdb9 324 + checksum: 10/a883155e4b36252c16e17ba055536f095dc096d1e9828e1d56de6aee5c537e141f34719bd639aa572538b5152b7d9c73780b14a252470a11e70a14a455eb3d4d 392 325 languageName: node 393 326 linkType: hard 394 327 395 - "@atproto/crypto@npm:^0.4.2, @atproto/crypto@npm:^0.4.3": 328 + "@atproto/crypto@npm:^0.4.4": 396 329 version: 0.4.4 397 330 resolution: "@atproto/crypto@npm:0.4.4" 398 331 dependencies: ··· 403 336 languageName: node 404 337 linkType: hard 405 338 406 - "@atproto/did@npm:0.1.3": 407 - version: 0.1.3 408 - resolution: "@atproto/did@npm:0.1.3" 409 - dependencies: 410 - zod: "npm:^3.23.8" 411 - checksum: 10/e5a985e1b3149a97c0000134607eedbcb9d6514750ebd9bb36635bcea135e7332adf79d1ecc5d214a04599d1e6c7ec24296c4ad333d007b4fddb0b369f835ba8 412 - languageName: node 413 - linkType: hard 414 - 415 339 "@atproto/did@npm:0.1.5": 416 340 version: 0.1.5 417 341 resolution: "@atproto/did@npm:0.1.5" ··· 421 345 languageName: node 422 346 linkType: hard 423 347 424 - "@atproto/jwk-jose@npm:0.1.2": 425 - version: 0.1.2 426 - resolution: "@atproto/jwk-jose@npm:0.1.2" 427 - dependencies: 428 - "@atproto/jwk": "npm:0.1.1" 429 - jose: "npm:^5.2.0" 430 - checksum: 10/0096bc19be294ba0a5ee550565ff27fec397e1121d622dd6921b8ec0080e9756a313c0ae1c970c1ea9e623bbfd071678f16eeb0b4f7c18ef4927c55e38ba5a19 431 - languageName: node 432 - linkType: hard 433 - 434 - "@atproto/jwk-jose@npm:^0.1.2": 435 - version: 0.1.5 436 - resolution: "@atproto/jwk-jose@npm:0.1.5" 348 + "@atproto/jwk-jose@npm:0.1.6, @atproto/jwk-jose@npm:^0.1.6": 349 + version: 0.1.6 350 + resolution: "@atproto/jwk-jose@npm:0.1.6" 437 351 dependencies: 438 - "@atproto/jwk": "npm:0.1.4" 352 + "@atproto/jwk": "npm:0.1.5" 439 353 jose: "npm:^5.2.0" 440 - checksum: 10/1e7b9d4cde31e47fae9225a12e384ff7f5b8537fead62c41809aabcb4c022b03e283c19c93f6205a6beb23e4c60ef577c32723102eb0fa7f9b85d14fdcc92266 441 - languageName: node 442 - linkType: hard 443 - 444 - "@atproto/jwk-webcrypto@npm:0.1.2, @atproto/jwk-webcrypto@npm:^0.1.2": 445 - version: 0.1.2 446 - resolution: "@atproto/jwk-webcrypto@npm:0.1.2" 447 - dependencies: 448 - "@atproto/jwk": "npm:0.1.1" 449 - "@atproto/jwk-jose": "npm:0.1.2" 450 - checksum: 10/94ef0e4b2dcf87f7e9cb795386dbaee01d87fc17b1317b7872af127098ab16b190f2d1f85af1f08eaf946a76b4197c27f35ed86ec7444992deac0cc6a64be63a 354 + checksum: 10/fc3926d1eca2aaea9ac2022cdf3340a94fa9d172520463cdb108352077d48ffac498b164506d4667f7d38a76a6511c06b654eacc6749e8af5df0ce5f4527ec28 451 355 languageName: node 452 356 linkType: hard 453 357 454 - "@atproto/jwk@npm:0.1.1": 455 - version: 0.1.1 456 - resolution: "@atproto/jwk@npm:0.1.1" 358 + "@atproto/jwk-webcrypto@npm:0.1.6, @atproto/jwk-webcrypto@npm:^0.1.6": 359 + version: 0.1.6 360 + resolution: "@atproto/jwk-webcrypto@npm:0.1.6" 457 361 dependencies: 458 - multiformats: "npm:^9.9.0" 362 + "@atproto/jwk": "npm:0.1.5" 363 + "@atproto/jwk-jose": "npm:0.1.6" 459 364 zod: "npm:^3.23.8" 460 - checksum: 10/583532fbc41edd1c51bfe257fec7966e397ac2dac9acae93fde470fd178e1b706e4fd5b138d06161868707bce72f3647973996140d76d59f7e74a685a0dcdc06 365 + checksum: 10/e212510dec62403533e6288f56b3976a27bcc81b67af61bd070db46f151767785fa4e907c48bf85eb2a0bc4ff6c776bea29629221acaaa5bb9675873b7d912c3 461 366 languageName: node 462 367 linkType: hard 463 368 464 - "@atproto/jwk@npm:0.1.4": 465 - version: 0.1.4 466 - resolution: "@atproto/jwk@npm:0.1.4" 369 + "@atproto/jwk@npm:0.1.5": 370 + version: 0.1.5 371 + resolution: "@atproto/jwk@npm:0.1.5" 467 372 dependencies: 468 373 multiformats: "npm:^9.9.0" 469 374 zod: "npm:^3.23.8" 470 - checksum: 10/cdf0b7cb707ae8d12d1a0ea1453cb82059fe32c7fde7d1551efab910d1a45a1247e7506c3fd69d4c53519311725fa2ee043980e9dc83fa2a7a9d7213c5bbccbb 375 + checksum: 10/df14d332fcad094a58dfe401f4b75169b04d8c25fef7ac90d9fdcf0b75f5c9336581358d638f48267ee95a55deeab5dd24d1be885ce12556bad6a34980c3ccb9 471 376 languageName: node 472 377 linkType: hard 473 378 ··· 489 394 languageName: node 490 395 linkType: hard 491 396 492 - "@atproto/lexicon@npm:^0.4.3": 493 - version: 0.4.3 494 - resolution: "@atproto/lexicon@npm:0.4.3" 397 + "@atproto/lexicon@npm:^0.4.11": 398 + version: 0.4.11 399 + resolution: "@atproto/lexicon@npm:0.4.11" 495 400 dependencies: 496 - "@atproto/common-web": "npm:^0.3.1" 497 - "@atproto/syntax": "npm:^0.3.1" 401 + "@atproto/common-web": "npm:^0.4.2" 402 + "@atproto/syntax": "npm:^0.4.0" 498 403 iso-datestring-validator: "npm:^2.2.2" 499 404 multiformats: "npm:^9.9.0" 500 405 zod: "npm:^3.23.8" 501 - checksum: 10/c7b0616ffcd85eb77315b4a15bf17acfc2c9de6b4112321a8dad5f0723453c8a5464418a332f0e387e999ed863fb954ccb511097e9c733efacc9b3aacc0c611c 406 + checksum: 10/7c5ff1bed85cd976dbe1435c968c75ddcb305a51e5718373376ad65d2a65945a9936e9d7bcda51c7e2bf4e5da9078bb943d953415c56f0a93495a3078a8b2cfe 502 407 languageName: node 503 408 linkType: hard 504 409 505 - "@atproto/lexicon@npm:^0.4.6, @atproto/lexicon@npm:^0.4.8": 410 + "@atproto/lexicon@npm:^0.4.6": 506 411 version: 0.4.8 507 412 resolution: "@atproto/lexicon@npm:0.4.8" 508 413 dependencies: ··· 515 420 languageName: node 516 421 linkType: hard 517 422 518 - "@atproto/oauth-client-browser@npm:0.3.2": 519 - version: 0.3.2 520 - resolution: "@atproto/oauth-client-browser@npm:0.3.2" 521 - dependencies: 522 - "@atproto-labs/did-resolver": "npm:0.1.5" 523 - "@atproto-labs/handle-resolver": "npm:0.1.4" 524 - "@atproto-labs/simple-store": "npm:0.1.1" 525 - "@atproto/did": "npm:0.1.3" 526 - "@atproto/jwk": "npm:0.1.1" 527 - "@atproto/jwk-webcrypto": "npm:0.1.2" 528 - "@atproto/oauth-client": "npm:0.3.2" 529 - "@atproto/oauth-types": "npm:0.2.1" 530 - checksum: 10/4d588524ebfd58d84f2b0c48fc65d8b834190d149f27e453915e9f608d1464b88255e224128fff3a7ba64506d5d47224ed07bd86f1edc0d8def6c1a882027c5e 531 - languageName: node 532 - linkType: hard 533 - 534 - "@atproto/oauth-client-browser@npm:^0.3.1": 535 - version: 0.3.1 536 - resolution: "@atproto/oauth-client-browser@npm:0.3.1" 423 + "@atproto/oauth-client-browser@npm:0.3.16, @atproto/oauth-client-browser@npm:^0.3.16": 424 + version: 0.3.16 425 + resolution: "@atproto/oauth-client-browser@npm:0.3.16" 537 426 dependencies: 538 - "@atproto-labs/did-resolver": "npm:0.1.5" 539 - "@atproto-labs/handle-resolver": "npm:0.1.4" 540 - "@atproto-labs/simple-store": "npm:0.1.1" 541 - "@atproto/did": "npm:0.1.3" 542 - "@atproto/jwk": "npm:0.1.1" 543 - "@atproto/jwk-webcrypto": "npm:0.1.2" 544 - "@atproto/oauth-client": "npm:0.3.1" 545 - "@atproto/oauth-types": "npm:0.2.0" 546 - checksum: 10/e8aa99f68c382884b082ab60473045b8f38d1c8a8fb247ad5cda831d7d6fce4ece4fca7d25e8c2cccce6738e7a4dc810e640a559dde0375d39d3df6e92b8f5c3 547 - languageName: node 548 - linkType: hard 549 - 550 - "@atproto/oauth-client@npm:0.3.1": 551 - version: 0.3.1 552 - resolution: "@atproto/oauth-client@npm:0.3.1" 553 - dependencies: 554 - "@atproto-labs/did-resolver": "npm:0.1.5" 555 - "@atproto-labs/fetch": "npm:0.1.1" 556 - "@atproto-labs/handle-resolver": "npm:0.1.4" 557 - "@atproto-labs/identity-resolver": "npm:0.1.6" 558 - "@atproto-labs/simple-store": "npm:0.1.1" 559 - "@atproto-labs/simple-store-memory": "npm:0.1.1" 560 - "@atproto/did": "npm:0.1.3" 561 - "@atproto/jwk": "npm:0.1.1" 562 - "@atproto/oauth-types": "npm:0.2.0" 563 - "@atproto/xrpc": "npm:0.6.4" 564 - multiformats: "npm:^9.9.0" 565 - zod: "npm:^3.23.8" 566 - checksum: 10/26eb22d9b1d0c59a79a297c0a265a5e92e1b704570bb2bf93c0b3822d3d16e9276195805112f940606d643345f7a0e1f72c57972b6c5f551dd436200ea78e461 567 - languageName: node 568 - linkType: hard 569 - 570 - "@atproto/oauth-client@npm:0.3.2": 571 - version: 0.3.2 572 - resolution: "@atproto/oauth-client@npm:0.3.2" 573 - dependencies: 574 - "@atproto-labs/did-resolver": "npm:0.1.5" 575 - "@atproto-labs/fetch": "npm:0.1.1" 576 - "@atproto-labs/handle-resolver": "npm:0.1.4" 577 - "@atproto-labs/identity-resolver": "npm:0.1.6" 578 - "@atproto-labs/simple-store": "npm:0.1.1" 579 - "@atproto-labs/simple-store-memory": "npm:0.1.1" 580 - "@atproto/did": "npm:0.1.3" 581 - "@atproto/jwk": "npm:0.1.1" 582 - "@atproto/oauth-types": "npm:0.2.1" 583 - "@atproto/xrpc": "npm:0.6.4" 584 - multiformats: "npm:^9.9.0" 585 - zod: "npm:^3.23.8" 586 - checksum: 10/0c24457411f69b036cd0c553eaa9853d459b124b48396da6561896ab693766187bfc8b5c48aa552d0085802abaac39a3020d7ce905961e999bd9d3df699a78e1 427 + "@atproto-labs/did-resolver": "npm:0.1.12" 428 + "@atproto-labs/handle-resolver": "npm:0.1.8" 429 + "@atproto-labs/simple-store": "npm:0.2.0" 430 + "@atproto/did": "npm:0.1.5" 431 + "@atproto/jwk": "npm:0.1.5" 432 + "@atproto/jwk-webcrypto": "npm:0.1.6" 433 + "@atproto/oauth-client": "npm:0.3.16" 434 + "@atproto/oauth-types": "npm:0.2.7" 435 + checksum: 10/7e108d5827d9b4dd0592abb9cbd2919591bd1ef2b95f08f91b5924fdc3967e4a3b6372388c7142b2e45347dbd3fd93b114121e6ac2da78663ec5c23b9c4e16b4 587 436 languageName: node 588 437 linkType: hard 589 438 590 - "@atproto/oauth-client@npm:^0.3.1": 591 - version: 0.3.11 592 - resolution: "@atproto/oauth-client@npm:0.3.11" 439 + "@atproto/oauth-client@npm:0.3.16, @atproto/oauth-client@npm:^0.3.16": 440 + version: 0.3.16 441 + resolution: "@atproto/oauth-client@npm:0.3.16" 593 442 dependencies: 594 - "@atproto-labs/did-resolver": "npm:0.1.11" 443 + "@atproto-labs/did-resolver": "npm:0.1.12" 595 444 "@atproto-labs/fetch": "npm:0.2.2" 596 - "@atproto-labs/handle-resolver": "npm:0.1.7" 597 - "@atproto-labs/identity-resolver": "npm:0.1.14" 598 - "@atproto-labs/simple-store": "npm:0.1.2" 599 - "@atproto-labs/simple-store-memory": "npm:0.1.2" 445 + "@atproto-labs/handle-resolver": "npm:0.1.8" 446 + "@atproto-labs/identity-resolver": "npm:0.1.16" 447 + "@atproto-labs/simple-store": "npm:0.2.0" 448 + "@atproto-labs/simple-store-memory": "npm:0.1.3" 600 449 "@atproto/did": "npm:0.1.5" 601 - "@atproto/jwk": "npm:0.1.4" 602 - "@atproto/oauth-types": "npm:0.2.4" 603 - "@atproto/xrpc": "npm:0.6.10" 450 + "@atproto/jwk": "npm:0.1.5" 451 + "@atproto/oauth-types": "npm:0.2.7" 452 + "@atproto/xrpc": "npm:0.7.0" 604 453 multiformats: "npm:^9.9.0" 605 454 zod: "npm:^3.23.8" 606 - checksum: 10/4e4c6b34badad6abd8901384e67bb468ed01b8d64a839ff05c13edf99e2dd0b1f443fd036ad6d4617615982537596145613c02851696fc1515c930df8284404e 607 - languageName: node 608 - linkType: hard 609 - 610 - "@atproto/oauth-types@npm:0.2.0": 611 - version: 0.2.0 612 - resolution: "@atproto/oauth-types@npm:0.2.0" 613 - dependencies: 614 - "@atproto/jwk": "npm:0.1.1" 615 - zod: "npm:^3.23.8" 616 - checksum: 10/e526a936f66c7c7dc6bdb3792ffac7fa168c9908a39f28a89ff5183b3e13961b264dcee9dbf3dfcbaa5ec67aedbc8c08f9d4b0b061c99badb6055ae8e491cadb 617 - languageName: node 618 - linkType: hard 619 - 620 - "@atproto/oauth-types@npm:0.2.1": 621 - version: 0.2.1 622 - resolution: "@atproto/oauth-types@npm:0.2.1" 623 - dependencies: 624 - "@atproto/jwk": "npm:0.1.1" 625 - zod: "npm:^3.23.8" 626 - checksum: 10/24a9955a51582301ddf1fdc470d8dac73b13cdecf4d5739419401e5d30b0d840a01f1d06988c25851bff350a5c00caf8f9e19b3e20bfc7033ba2971e26c27277 455 + checksum: 10/dc26a79966eefbc114bd7f45954b3d3921afe1a8cf3e95cdc2682b5275283c7511bdfff4ab66fce929879bb98733589f0a2ad5c9c6f500edd63396ec360d2b62 627 456 languageName: node 628 457 linkType: hard 629 458 630 - "@atproto/oauth-types@npm:0.2.4": 631 - version: 0.2.4 632 - resolution: "@atproto/oauth-types@npm:0.2.4" 459 + "@atproto/oauth-types@npm:0.2.7": 460 + version: 0.2.7 461 + resolution: "@atproto/oauth-types@npm:0.2.7" 633 462 dependencies: 634 - "@atproto/jwk": "npm:0.1.4" 463 + "@atproto/jwk": "npm:0.1.5" 635 464 zod: "npm:^3.23.8" 636 - checksum: 10/8d054e6db5ee25d2236d759b4fa4ca8187ae390decafff07d607a226a272775433c8a088fc2546e684e44a17d535271669196e03cb939e78741b26b5dc20ac6d 465 + checksum: 10/eeae51b6ded48a33bd14ff69f2daf00b1b5d8c23c8f1fa6e2ecc31559e7d3baa8511f7daefe2539fcc91a50ffb4606c39f92c155548756a37bee52fc8c9bb232 637 466 languageName: node 638 467 linkType: hard 639 468 640 - "@atproto/syntax@npm:0.3.1, @atproto/syntax@npm:^0.3.1": 641 - version: 0.3.1 642 - resolution: "@atproto/syntax@npm:0.3.1" 643 - checksum: 10/f5a7509b74d48d0b7be7cee82c8b93861a79671e617864c022147099fa1f87ee91da7c9b2b8688c8ae405fd465eb4e2b012eed04bf5aaadc4233c03f1badb9ed 469 + "@atproto/syntax@npm:0.4.0, @atproto/syntax@npm:^0.4.0": 470 + version: 0.4.0 471 + resolution: "@atproto/syntax@npm:0.4.0" 472 + checksum: 10/f4a1987bf6a3e0ed63df660a1543049ef023c7ecd4c394efbd247acd1e562a9dfb2beb228e26f806e0a5b56bd5c706345dfdfa804e901e2091100b4c82653556 644 473 languageName: node 645 474 linkType: hard 646 475 647 - "@atproto/syntax@npm:0.3.4, @atproto/syntax@npm:^0.3.2, @atproto/syntax@npm:^0.3.4": 476 + "@atproto/syntax@npm:^0.3.2, @atproto/syntax@npm:^0.3.4": 648 477 version: 0.3.4 649 478 resolution: "@atproto/syntax@npm:0.3.4" 650 479 checksum: 10/3f9b8462b8e7b194bf8580bdd672e215a87812075854e959327498b4958cc2437d3694c453e918d67e43fd42dc404669663fbe85ece8cc21094d98ee63bf5fbd 651 480 languageName: node 652 481 linkType: hard 653 482 654 - "@atproto/syntax@npm:^0.4.0": 655 - version: 0.4.0 656 - resolution: "@atproto/syntax@npm:0.4.0" 657 - checksum: 10/f4a1987bf6a3e0ed63df660a1543049ef023c7ecd4c394efbd247acd1e562a9dfb2beb228e26f806e0a5b56bd5c706345dfdfa804e901e2091100b4c82653556 658 - languageName: node 659 - linkType: hard 660 - 661 - "@atproto/xrpc@npm:0.6.10": 662 - version: 0.6.10 663 - resolution: "@atproto/xrpc@npm:0.6.10" 664 - dependencies: 665 - "@atproto/lexicon": "npm:^0.4.8" 666 - zod: "npm:^3.23.8" 667 - checksum: 10/a229bd851fbc5673dcb21154baea53d7817f7be74b52f76e09c966ae3426e49ee5f0289a83326e398b958871208dbfd7cd31e47efaf982a3ae251a733dc8babc 668 - languageName: node 669 - linkType: hard 670 - 671 - "@atproto/xrpc@npm:0.6.4, @atproto/xrpc@npm:^0.6.4": 672 - version: 0.6.4 673 - resolution: "@atproto/xrpc@npm:0.6.4" 483 + "@atproto/xrpc@npm:0.7.0, @atproto/xrpc@npm:^0.7.0": 484 + version: 0.7.0 485 + resolution: "@atproto/xrpc@npm:0.7.0" 674 486 dependencies: 675 - "@atproto/lexicon": "npm:^0.4.3" 487 + "@atproto/lexicon": "npm:^0.4.11" 676 488 zod: "npm:^3.23.8" 677 - checksum: 10/de610ce225218722399bb2612085dbbe001dc7531d56a8be9e01151797938b480698c2e790d2a3dbf5ef778dcf0d3452c9ede4963a1d108bf43b0f2f805441cf 489 + checksum: 10/0038b697f66e1e730dee16faf5347834a6a76b9e978a42be330f1caeee6d00abae82a45a54d13887e84ede47bbe71ce95e81b81e75370f0e6194923c2747618e 678 490 languageName: node 679 491 linkType: hard 680 492 ··· 8787 8599 version: 0.0.0-use.local 8788 8600 resolution: "@streamplace/atproto-oauth-client-react-native@workspace:js/atproto-oauth-client-react-native" 8789 8601 dependencies: 8790 - "@atproto-labs/did-resolver": "npm:0.1.5" 8791 - "@atproto-labs/handle-resolver-node": "npm:0.1.7" 8792 - "@atproto-labs/simple-store": "npm:0.1.1" 8793 - "@atproto-labs/simple-store-memory": "npm:0.1.1" 8794 - "@atproto/did": "npm:0.1.3" 8795 - "@atproto/jwk": "npm:0.1.1" 8796 - "@atproto/jwk-jose": "npm:0.1.2" 8797 - "@atproto/jwk-webcrypto": "npm:0.1.2" 8798 - "@atproto/oauth-client": "npm:0.3.2" 8799 - "@atproto/oauth-client-browser": "npm:0.3.2" 8800 - "@atproto/oauth-types": "npm:0.2.1" 8602 + "@atproto-labs/did-resolver": "npm:0.1.12" 8603 + "@atproto-labs/handle-resolver-node": "npm:0.1.15" 8604 + "@atproto-labs/simple-store": "npm:0.2.0" 8605 + "@atproto-labs/simple-store-memory": "npm:0.1.3" 8606 + "@atproto/did": "npm:0.1.5" 8607 + "@atproto/jwk": "npm:0.1.5" 8608 + "@atproto/jwk-jose": "npm:0.1.6" 8609 + "@atproto/jwk-webcrypto": "npm:0.1.6" 8610 + "@atproto/oauth-client": "npm:0.3.16" 8611 + "@atproto/oauth-client-browser": "npm:0.3.16" 8612 + "@atproto/oauth-types": "npm:0.2.7" 8801 8613 "@types/node": "npm:^22.10.1" 8802 8614 abortcontroller-polyfill: "npm:^1.7.6" 8803 8615 event-target-shim: "npm:^6.0.2" ··· 29500 29312 version: 0.0.0-use.local 29501 29313 resolution: "streamplace-desktop@workspace:js/desktop" 29502 29314 dependencies: 29503 - "@atproto/crypto": "npm:^0.4.3" 29315 + "@atproto/crypto": "npm:^0.4.4" 29504 29316 "@electron-forge/cli": "npm:^7.5.0" 29505 29317 "@electron-forge/maker-deb": "npm:^7.5.0" 29506 29318 "@electron-forge/maker-dmg": "npm:^7.5.0" ··· 29550 29362 version: 0.0.0-use.local 29551 29363 resolution: "streamplace-monorepo@workspace:." 29552 29364 dependencies: 29553 - "@atproto/api": "npm:^0.13.16" 29554 - "@atproto/jwk-webcrypto": "npm:^0.1.2" 29555 29365 "@atproto/lex-cli": "npm:^0.5.6" 29556 - "@atproto/oauth-client-browser": "npm:^0.3.1" 29557 29366 firebase-admin: "npm:^12.7.0" 29558 29367 husky: "npm:^9.1.6" 29559 29368 lerna: "npm:^8.1.9" ··· 29568 29377 resolution: "streamplace@workspace:js/app" 29569 29378 dependencies: 29570 29379 "@atproto-labs/pipe": "npm:^0.1.0" 29571 - "@atproto/crypto": "npm:^0.4.2" 29572 - "@atproto/jwk-jose": "npm:^0.1.2" 29573 - "@atproto/oauth-client": "npm:^0.3.1" 29380 + "@atproto/api": "npm:^0.15.7" 29381 + "@atproto/crypto": "npm:^0.4.4" 29382 + "@atproto/jwk-jose": "npm:^0.1.6" 29383 + "@atproto/jwk-webcrypto": "npm:^0.1.6" 29384 + "@atproto/oauth-client": "npm:^0.3.16" 29385 + "@atproto/oauth-client-browser": "npm:^0.3.16" 29574 29386 "@babel/core": "npm:^7.26.0" 29575 29387 "@babel/plugin-proposal-export-default-from": "npm:^7.25.9" 29576 29388 "@babel/plugin-syntax-export-default-from": "npm:^7.25.9"