nuxt-atproto 0.0.5 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.md +53 -249
  2. package/dist/module.d.mts +31 -2
  3. package/dist/module.json +3 -3
  4. package/dist/module.mjs +65 -21
  5. package/dist/runtime/app/composables/useAgent.d.ts +7 -0
  6. package/dist/runtime/app/composables/useAgent.js +59 -0
  7. package/dist/runtime/app/composables/useAtproto.d.ts +12 -0
  8. package/dist/runtime/app/composables/useAtproto.js +21 -0
  9. package/dist/runtime/app/composables/useAtprotoAgent.d.ts +10 -0
  10. package/dist/runtime/app/composables/useAtprotoAgent.js +8 -0
  11. package/dist/runtime/app/composables/useAtprotoAuth.d.ts +12 -0
  12. package/dist/runtime/app/composables/useAtprotoAuth.js +70 -0
  13. package/dist/runtime/app/composables/useAtprotoSession.d.ts +12 -0
  14. package/dist/runtime/app/composables/useAtprotoSession.js +18 -0
  15. package/dist/runtime/app/plugins/atproto.client.d.ts +7 -0
  16. package/dist/runtime/app/plugins/atproto.client.js +68 -0
  17. package/dist/runtime/app/utils/agentCache.d.ts +8 -0
  18. package/dist/runtime/app/utils/agentCache.js +15 -0
  19. package/dist/runtime/app/utils/sessionLifecycle.d.ts +22 -0
  20. package/dist/runtime/app/utils/sessionLifecycle.js +29 -0
  21. package/dist/runtime/app/utils/useAtprotoRuntimeConfig.d.ts +2 -0
  22. package/dist/runtime/app/utils/useAtprotoRuntimeConfig.js +4 -0
  23. package/package.json +15 -15
  24. package/dist/runtime/composables/useAgent.d.ts +0 -8
  25. package/dist/runtime/composables/useAgent.js +0 -23
  26. package/dist/runtime/composables/useAtproto.d.ts +0 -9
  27. package/dist/runtime/composables/useAtproto.js +0 -65
  28. package/dist/runtime/plugin.d.ts +0 -12
  29. package/dist/runtime/plugin.js +0 -61
  30. package/dist/runtime/utils/utilActor.d.ts +0 -2
  31. package/dist/runtime/utils/utilActor.js +0 -16
package/README.md CHANGED
@@ -5,288 +5,92 @@
5
5
  [![License][license-src]][license-href]
6
6
  [![Nuxt][nuxt-src]][nuxt-href]
7
7
 
8
- > Easily integrate [Bluesky](https://bsky.app) login and [AT Protocol](https://atproto.com/) authentication into your
9
- Nuxt.js app.
8
+ > OAuth login and session management for [Bluesky](https://bsky.app) and [AT Protocol](https://atproto.com) in [Nuxt](https://nuxt.com).
10
9
 
11
- ## Overview
10
+ ## Documentation
12
11
 
13
- `nuxt-atproto` is a Nuxt.js module that simplifies the OAuth authentication via AT Protocol.
12
+ **[Documentation](https://dxlliv.github.io/nuxt-atproto/)** getting started, guides, and API reference.
14
13
 
15
- It handles the login and the session management using the `@atproto/oauth-client` library,
16
- providing public and authenticated agents for seamless interaction with AT Protocol services.
14
+ Run the docs site locally:
17
15
 
18
- ## Features
19
-
20
- - SSR-friendly login via Bluesky and AT Protocol with automatic service endpoint resolution.
21
- - Allow logins without specifying the handle, enabling account selection from PDS interface.
22
- - Simple access to sign-in, sign-out, public and private agents from `useAtproto` composable.
23
- - Access to the underlying client and session with `$atproto` provided by the plugin.
24
- - Dynamically generates `client-metadata.json` when the Nuxt.js app starts.
25
-
26
- ## Installation
16
+ ```bash
17
+ cd docs && pnpm install && pnpm dev
18
+ ```
27
19
 
28
- Install the module via npm:
20
+ Open **http://127.0.0.1:3456/nuxt-atproto/** (use `127.0.0.1`, not `localhost`, for the OAuth demo).
29
21
 
30
- ```sh
31
- npm install nuxt-atproto
32
- ```
22
+ ## Features
33
23
 
34
- ## Configuration
24
+ - AT Protocol OAuth in the browser (`@atproto/oauth-client-browser`)
25
+ - Composables for session, auth, and cached `@atproto/api` agents
26
+ - Lifecycle hooks: `atproto:sessionCreated`, `atproto:sessionRestored`, `atproto:sessionDeleted`
27
+ - Typed `$atproto` plugin (`client`, `session`, `status`)
28
+ - Optional generation of `public/client-metadata.json` from module config
35
29
 
36
- Register the module in your `nuxt.config.js`:
30
+ ## Quick start
37
31
 
38
- ```ts
39
- export default defineNuxtConfig({
40
- modules: ['nuxt-atproto']
41
- })
32
+ ```bash
33
+ pnpm add nuxt-atproto
42
34
  ```
43
35
 
44
- You can configure `nuxt-atproto` in your `nuxt.config.ts` file under the `atproto` key.
45
- The following options are available with their default values:
46
-
47
36
  ```ts
48
- defineNuxtConfig({
49
- modules: ['nuxt-atproto'],
50
- atproto: {
51
- serviceEndpoint: {
52
- private: 'https://bsky.social',
53
- public: 'https://public.api.bsky.app'
54
- },
55
- oauth: {
56
- clientMetadata: {
57
- // url of your remote client_metadata.json, leave the field empty
58
- // to let `nuxt-atproto` generate a local /public/client_metadata.json
59
- remote: '',
60
- // configuration for the local client_metadata.json
61
- local: {
62
- client_id: 'https://nuxt-atproto.pages.dev/client-metadata.json',
63
- client_name: 'nuxt-atproto',
64
- client_uri: 'https://nuxt-atproto.pages.dev',
65
- logo_uri: 'https://nuxt-atproto.pages.dev/logo.png',
66
- tos_uri: 'https://nuxt-atproto.pages.dev',
67
- policy_uri: 'https://nuxt-atproto.pages.dev',
68
- redirect_uris: ['https://nuxt-atproto.pages.dev'],
69
- scope: "atproto transition:generic",
70
- grant_types: ["authorization_code", "refresh_token"],
71
- response_types: ["code"],
72
- token_endpoint_auth_method: 'none',
73
- application_type: 'web',
74
- dpop_bound_access_tokens: true
75
- }
76
- },
77
- signInOptions: {
78
- state: '',
79
- prompt: 'login',
80
- scope: 'atproto',
81
- ui_locales: 'en',
82
- },
37
+ // nuxt.config.ts
38
+ export default defineNuxtConfig({
39
+ modules: ['nuxt-atproto'],
40
+ atproto: {
41
+ oauth: {
42
+ clientMetadata: {
43
+ local: {
44
+ client_id: 'https://your-app.example/client-metadata.json',
45
+ client_name: 'My App',
46
+ client_uri: 'https://your-app.example',
47
+ redirect_uris: ['https://your-app.example'],
48
+ // ... see docs for full metadata
83
49
  },
84
- debug: true,
85
- }
50
+ },
51
+ },
52
+ },
86
53
  })
87
54
  ```
88
55
 
89
- You must configure the `atproto.oauth.clientMetadata` with in your `nuxt.config.ts`,
90
- especially `client_id` and `redirect_uris`, for the authentication flow to work correctly.
91
-
92
- If you don't provide a remote URL in the module options, when Nuxt.js starts it will create a `client-metadata.json` in your `public` folder.
93
- Using a local `client-metadata.json` generally offers a faster user experience compared to fetching it from a remote URL.
94
-
95
- ## Usage
96
-
97
- #### Basic example
98
-
99
- ```html
56
+ ```vue
100
57
  <script setup lang="ts">
101
- const atproto = useAtproto()
58
+ const { isLogged, session } = useAtprotoSession()
59
+ const { signIn, signInWithHandle, signOut } = useAtprotoAuth()
102
60
  </script>
103
61
 
104
62
  <template>
105
- <div>
106
- <Button @click="atproto.signIn()">
107
- Sign-in with ATProto
108
- </Button><br />
109
- <Button @click="atproto.signInWithHandle('dxlliv.bsky.social')">
110
- Sign-in with ATProto using dxlliv.bsky.social
111
- </Button><br />
112
- <Button @click="atproto.signInWithHandle()">
113
- Sign-in with ATProto using your handle (prompt)
114
- </Button>
115
- <Button @click="atproto.restore('did:plc:2pkidgvfnbxx7sq3shporxij')">
116
- Restore dxlliv.bsky.social session
117
- </Button>
118
- </div>
119
- <template v-if="atproto.agent.account">
120
- <div>logged with: {{atproto.agent.account.assertDid}}</div>
121
- <Button @click="atproto.signOut()">
122
- Sign-out
123
- </Button>
63
+ <ClientOnly>
64
+ <button v-if="!isLogged" type="button" @click="signIn()">Sign in</button>
65
+ <template v-else>
66
+ <p>{{ session?.sub }}</p>
67
+ <button type="button" @click="signOut()">Sign out</button>
124
68
  </template>
69
+ </ClientOnly>
125
70
  </template>
126
71
  ```
127
72
 
128
- <br />
129
-
130
- ## 🧩 useAtproto(service?: string, fetch?: any)
131
-
132
- A composable provided by `nuxt-atproto` that offers methods for user authentication and session management, including authenticating, signing out and session restore.
133
-
134
- ```html
135
-
136
- <script setup lang="ts">
137
- const atproto = useAtproto()
138
- </script>
139
- ```
140
-
141
- **Parameters:**
142
-
143
- - `service` (optional): Override the service endpoint of the public agent.
144
- - `fetch` (optional): A custom fetch implementation.
145
-
146
- <br />
147
-
148
- ### ➡️ signIn(serviceEndpoint?: string, options?: AtprotoSignInOptions)
149
-
150
- Initiates the standard ATProto sign-in flow redirecting the user for authentication.
151
-
152
- ```html
153
-
154
- <Button @click="atproto.signIn()">
155
- Sign-in with ATProto
156
- </Button>
157
- ```
158
-
159
- **Parameters:**
160
-
161
- - `serviceEndpoint`: *(optional)* The specific ATProto service endpoint to use for sign-in.
162
- - `options`: *(optional)* Additional options to configure the sign-in process.
163
-
164
- ```ts
165
- // options
166
- {
167
- state: "",
168
- prompt: "login",
169
- scope: "atproto",
170
- ui_locales: "en"
171
- }
172
- ```
173
-
174
- **Returns:** A Promise that might not directly resolve due to the redirection to the ATProto service.
175
-
176
- <br />
177
-
178
- ### ➡️ signInWithHandle(handle?: string, options?: AtprotoSignInOptions)
179
-
180
- Initiates the ATProto sign-in flow using the user's AT Protocol handle.
181
- The user will be prompted to enter their handle on the ATProto service if you omit the handle.
182
-
183
- ```html
184
-
185
- <Button @click="atproto.signInWithHandle()">
186
- Sign-in with ATProto
187
- </Button>
188
- ```
189
-
190
- **Parameters:**
191
-
192
- - `handle`: *(optional)* The AT Protocol handle of the user.
193
- - `options`: *(optional)* Additional options to configure the sign-in process.
194
-
195
- **Returns:** A Promise that might not directly resolve due to the redirection to the ATProto service.
196
-
197
- <br />
198
-
199
- ### ➡️ restore(did: string)
200
-
201
- Restore the user account associated with the provided Decentralized Identifier (DID).
202
-
203
- ```html
204
-
205
- <Button @click="atproto.restore('did:plc:2pkidgvfnbxx7sq3shporxij')">
206
- Restore dxlliv.bsky.social
207
- </Button>
208
- ```
209
-
210
- **Parameters:**
211
-
212
- - `handle`: *(optional)* The Decentralized Identifier (DID) of the account to be restored.
213
-
214
- **Returns:** A Promise that resolves when the restoration process is complete.
215
-
216
- <br />
217
-
218
- ### ➡️ signOut()
219
-
220
- Logs out the currently authenticated user and clears the stored session data.
221
-
222
- ```html
223
-
224
- <Button @click="atproto.signOut()">
225
- Sign-out
226
- </Button>
227
- ```
228
-
229
- **Returns:** A Promise that resolves when the restoration process is complete.
230
-
231
- <br />
232
-
233
- ### ➡️ isLogged()
234
-
235
- Indicates whether the user is currently authenticated.
236
-
237
- ```ts
238
- const atproto = useAtproto()
239
-
240
- if (!atproto.isLogged()) {
241
- return console.log('User is not logged in')
242
- }
243
-
244
- console.log('User is authenticated')
245
- ```
246
-
247
- **Returns**: Returns a boolean indicating whether the user is authenticated.
248
-
249
- <br />
250
-
251
- ### ➡️ getSession()
252
-
253
- Retrieves the current session from the Nuxt application context.
254
-
255
73
  ```ts
256
- const atproto = useAtproto()
257
-
258
- if (atproto.isLogged()) {
259
- const session = atproto.getSession()
260
-
261
- console.log('User is logged in', session.sub)
262
- }
74
+ const agent = useAtprotoAgent('authenticated')
75
+ await agent.getTimeline()
263
76
  ```
264
77
 
265
- **Returns**: Returns the current AT Protocol OAuth Browser session.
266
-
267
- <br />
268
-
269
- ## 🧩 useAgent(service?: string, fetch?: any)
270
-
271
- A composable provided by `nuxt-atproto` that offers methods for user authentication and session management, including authenticating, signing out and session restore.
272
-
273
- ```html
274
-
275
- <script setup lang="ts">
276
- const agent = useAgent('public')
277
- </script>
278
- ```
78
+ > **Client-only OAuth.** Wrap login UI in `<ClientOnly>` or disable SSR on auth routes.
79
+ > See the [introduction](https://dxlliv.github.io/nuxt-atproto/getting-started/introduction) in the docs.
279
80
 
280
- **Parameters:**
81
+ ## Composables
281
82
 
282
- - `service` (optional): Choose between `public`, `private` or a custom service endpoint.
283
- - `fetch` (optional): A custom fetch implementation.
83
+ | Composable | Purpose |
84
+ |------------|---------|
85
+ | `useAtprotoSession()` | `session`, `isLogged`, `status` |
86
+ | `useAtprotoAuth()` | `signIn`, `signInWithHandle`, `signOut`, `restore` |
87
+ | `useAtprotoAgent(scope)` | Cached `Agent` / `AtpAgent` (`authenticated`, `public`, or custom URL) |
284
88
 
285
- <br />
89
+ `useAtproto()` and `useAgent()` are deprecated — see [Migration](https://dxlliv.github.io/nuxt-atproto/advanced/migration).
286
90
 
287
91
  ## License
288
92
 
289
- This package is released under the MIT license.
93
+ Released under the [MIT License](./LICENSE).
290
94
 
291
95
  <!-- Badges -->
292
96
  [npm-version-src]: https://img.shields.io/npm/v/nuxt-atproto/latest.svg?style=flat&colorA=020420&colorB=00DC82
package/dist/module.d.mts CHANGED
@@ -1,7 +1,21 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
2
  import { HookResult } from '@nuxt/schema';
3
+ import { BrowserOAuthClient, OAuthSession } from '@atproto/oauth-client-browser';
4
+ import { Ref } from 'vue';
5
+
6
+ type AtprotoSessionStatus = 'initializing' | 'ready' | 'anonymous' | 'authenticated'
7
+
8
+ interface AtprotoContext {
9
+ client: BrowserOAuthClient
10
+ session: Ref<OAuthSession | undefined>
11
+ status: Ref<AtprotoSessionStatus>
12
+ }
3
13
 
4
14
  declare module '#app' {
15
+ interface NuxtApp {
16
+ $atproto: AtprotoContext
17
+ }
18
+
5
19
  interface RuntimeNuxtHooks {
6
20
  'atproto:sessionCreated': (did: string) => HookResult
7
21
  'atproto:sessionRestored': (did: string) => HookResult
@@ -9,7 +23,17 @@ declare module '#app' {
9
23
  }
10
24
  }
11
25
 
26
+ declare module 'vue' {
27
+ interface ComponentCustomProperties {
28
+ $atproto: AtprotoContext
29
+ }
30
+ }
31
+
12
32
  declare module 'nuxt/schema' {
33
+ /**
34
+ * Copied to `runtimeConfig.public.atproto` at build time.
35
+ * OAuth client metadata and endpoints are exposed to the client bundle by design.
36
+ */
13
37
  interface PublicRuntimeConfig {
14
38
  atproto: AtprotoNuxtOptions
15
39
  }
@@ -21,6 +45,11 @@ interface AtprotoNuxtOptions {
21
45
  public: string
22
46
  }
23
47
  oauth: {
48
+ /**
49
+ * When true, writes `public/client-metadata.json` from `oauth.clientMetadata.local` during module setup.
50
+ * @default false
51
+ */
52
+ writeClientMetadata?: boolean
24
53
  clientMetadata: {
25
54
  remote?: string
26
55
  local?: {
@@ -32,8 +61,8 @@ interface AtprotoNuxtOptions {
32
61
  policy_uri: string
33
62
  redirect_uris: string[]
34
63
  scope: string
35
- grant_types: Array<any>
36
- response_types: Array<any>
64
+ grant_types: Array<string>
65
+ response_types: Array<string>
37
66
  token_endpoint_auth_method: string
38
67
  application_type: string
39
68
  dpop_bound_access_tokens: boolean
package/dist/module.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "nuxt-atproto",
3
3
  "configKey": "atproto",
4
- "version": "0.0.5",
4
+ "version": "0.1.0",
5
5
  "builder": {
6
- "@nuxt/module-builder": "1.0.1",
7
- "unbuild": "3.5.0"
6
+ "@nuxt/module-builder": "1.0.2",
7
+ "unbuild": "unknown"
8
8
  }
9
9
  }
package/dist/module.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { mkdirSync, writeFileSync } from 'node:fs';
2
2
  import { defineNuxtModule, createResolver, addImportsDir, addPlugin } from '@nuxt/kit';
3
3
 
4
- const module = defineNuxtModule({
4
+ const module$1 = defineNuxtModule({
5
5
  meta: {
6
6
  name: "nuxt-atproto",
7
7
  configKey: "atproto"
@@ -12,6 +12,7 @@ const module = defineNuxtModule({
12
12
  public: "https://public.api.bsky.app"
13
13
  },
14
14
  oauth: {
15
+ writeClientMetadata: false,
15
16
  clientMetadata: {
16
17
  // load the client_metadata.json asynchronously from the URL
17
18
  remote: "",
@@ -46,28 +47,71 @@ const module = defineNuxtModule({
46
47
  const publicDir = resolve(_nuxt.options.rootDir, "public");
47
48
  _nuxt.options.runtimeConfig.public.atproto = _options;
48
49
  _nuxt.options.build.transpile = _nuxt.options.build.transpile || [];
49
- _nuxt.options.build.transpile.push("@atproto/oauth-client-browser");
50
- _nuxt.options.build.transpile.push("@atproto/api");
51
- _nuxt.hook("vite:extendConfig", (config) => {
52
- config.optimizeDeps = config.optimizeDeps || {};
53
- config.optimizeDeps.include = config.optimizeDeps.include || [];
54
- config.optimizeDeps.include.push("@atproto/oauth-client-browser");
55
- config.optimizeDeps.include.push("@atproto/api");
50
+ _nuxt.options.build.transpile.push(/@atproto\//);
51
+ _nuxt.hook("vite:extendConfig", (viteConfig) => {
52
+ const config = viteConfig;
53
+ config.optimizeDeps = {
54
+ ...config.optimizeDeps,
55
+ include: [
56
+ ...config.optimizeDeps?.include ?? [],
57
+ "@atproto/oauth-client-browser",
58
+ "@atproto/api",
59
+ "core-js"
60
+ ],
61
+ esbuildOptions: {
62
+ ...config.optimizeDeps?.esbuildOptions,
63
+ define: {
64
+ ...config.optimizeDeps?.esbuildOptions?.define,
65
+ global: "globalThis"
66
+ }
67
+ }
68
+ };
69
+ const existingOutput = config.build?.rollupOptions?.output;
70
+ const outputOptions = typeof existingOutput === "object" && !Array.isArray(existingOutput) ? existingOutput : {};
71
+ config.build = {
72
+ ...config.build,
73
+ commonjsOptions: {
74
+ ...config.build?.commonjsOptions,
75
+ transformMixedEsModules: true,
76
+ include: [
77
+ ...Array.isArray(config.build?.commonjsOptions?.include) ? config.build.commonjsOptions.include : [],
78
+ /node_modules\/core-js/,
79
+ /node_modules\/@atproto\//
80
+ ]
81
+ },
82
+ rollupOptions: {
83
+ ...config.build?.rollupOptions,
84
+ output: {
85
+ ...outputOptions,
86
+ // core-js (via @atproto/oauth-client) can leave bare `exports` refs in the client chunk
87
+ banner: 'var exports=typeof exports!=="undefined"?exports:{};var module=typeof module!=="undefined"?module:{exports};'
88
+ }
89
+ }
90
+ };
91
+ config.define = {
92
+ ...config.define,
93
+ "process.env": config.define?.["process.env"] ?? {},
94
+ "global": "globalThis"
95
+ };
56
96
  });
57
- try {
58
- mkdirSync(publicDir, { recursive: true });
59
- } catch (error) {
60
- console.error("Failed creating /public/client-metadata.json", error);
61
- return;
97
+ addImportsDir(resolve("./runtime/app/composables"));
98
+ addImportsDir(resolve("./runtime/app/utils"));
99
+ addPlugin({
100
+ src: resolve("./runtime/app/plugins/atproto.client"),
101
+ mode: "client"
102
+ });
103
+ if (_options.oauth.writeClientMetadata) {
104
+ try {
105
+ mkdirSync(publicDir, { recursive: true });
106
+ writeFileSync(
107
+ `${publicDir}/client-metadata.json`,
108
+ JSON.stringify(_options.oauth.clientMetadata.local, null, 2)
109
+ );
110
+ } catch (error) {
111
+ console.warn("[nuxt-atproto] Failed to write public/client-metadata.json:", error);
112
+ }
62
113
  }
63
- writeFileSync(
64
- publicDir + "/client-metadata.json",
65
- JSON.stringify(_options.oauth.clientMetadata.local, null, 2)
66
- );
67
- addImportsDir(resolve("./runtime/composables"));
68
- addImportsDir(resolve("./runtime/utils"));
69
- addPlugin(resolve("./runtime/plugin"));
70
114
  }
71
115
  });
72
116
 
73
- export { module as default };
117
+ export { module$1 as default };
@@ -0,0 +1,7 @@
1
+ import { Agent } from '@atproto/api';
2
+ /**
3
+ * Returns a cached AT Protocol agent for the given scope.
4
+ *
5
+ * @deprecated Use `useAtprotoAgent` instead (`private` → `authenticated`).
6
+ */
7
+ export declare function useAgent(service: 'private' | 'public' | (string & {}), fetch?: typeof globalThis.fetch): Agent;
@@ -0,0 +1,59 @@
1
+ import { useNuxtApp, useState } from "nuxt/app";
2
+ import { useAtprotoRuntimeConfig } from "../utils/useAtprotoRuntimeConfig.js";
3
+ import { Agent, AtpAgent } from "@atproto/api";
4
+ import {
5
+ customAgentStateKey,
6
+ invalidateAtprotoPrivateAgent,
7
+ PRIVATE_AGENT_SESSION_KEY,
8
+ PRIVATE_AGENT_STATE_KEY,
9
+ publicAgentStateKey
10
+ } from "../utils/agentCache.js";
11
+ export function useAgent(service, fetch) {
12
+ const atprotoConfig = useAtprotoRuntimeConfig();
13
+ const { $atproto } = useNuxtApp();
14
+ switch (service) {
15
+ case "private": {
16
+ if (!$atproto.session.value) {
17
+ invalidateAtprotoPrivateAgent();
18
+ throw new Error("Not authenticated");
19
+ }
20
+ const sessionSub = $atproto.session.value.sub;
21
+ const cachedAgent = useState(PRIVATE_AGENT_STATE_KEY, () => null);
22
+ const cachedSessionSub = useState(PRIVATE_AGENT_SESSION_KEY, () => null);
23
+ if (cachedAgent.value && cachedSessionSub.value === sessionSub) {
24
+ return cachedAgent.value;
25
+ }
26
+ const agent = new Agent($atproto.session.value);
27
+ cachedAgent.value = agent;
28
+ cachedSessionSub.value = sessionSub;
29
+ return agent;
30
+ }
31
+ case "public": {
32
+ const endpoint = atprotoConfig.serviceEndpoint.public;
33
+ const cacheKey = publicAgentStateKey(endpoint);
34
+ const cachedAgent = useState(cacheKey, () => null);
35
+ if (cachedAgent.value) {
36
+ return cachedAgent.value;
37
+ }
38
+ const agent = new AtpAgent({
39
+ service: endpoint,
40
+ fetch
41
+ });
42
+ cachedAgent.value = agent;
43
+ return agent;
44
+ }
45
+ default: {
46
+ const cacheKey = customAgentStateKey(service);
47
+ const cachedAgent = useState(cacheKey, () => null);
48
+ if (cachedAgent.value) {
49
+ return cachedAgent.value;
50
+ }
51
+ const agent = new AtpAgent({
52
+ service,
53
+ fetch
54
+ });
55
+ cachedAgent.value = agent;
56
+ return agent;
57
+ }
58
+ }
59
+ }
@@ -0,0 +1,12 @@
1
+ import type { OAuthSession } from '@atproto/oauth-client-browser';
2
+ /**
3
+ * @deprecated Use `useAtprotoSession` and `useAtprotoAuth` instead.
4
+ */
5
+ export declare function useAtproto(): {
6
+ signInWithHandle: (handle?: string, options?: Parameters<(handle: string, options?: import("../../../types/index.js").AtprotoSignInOptions) => Promise<void>>[1]) => Promise<void>;
7
+ isLogged: () => boolean;
8
+ getSession: () => OAuthSession | undefined;
9
+ signIn: (serviceEndpoint?: string, options?: import("../../../types/index.js").AtprotoSignInOptions) => Promise<void>;
10
+ signOut: () => Promise<void>;
11
+ restore: (did: string) => Promise<OAuthSession>;
12
+ };
@@ -0,0 +1,21 @@
1
+ import { useAtprotoAuth } from "./useAtprotoAuth.js";
2
+ import { useAtprotoSession } from "./useAtprotoSession.js";
3
+ export function useAtproto() {
4
+ const { session, isLogged } = useAtprotoSession();
5
+ const auth = useAtprotoAuth();
6
+ return {
7
+ ...auth,
8
+ signInWithHandle: async (handle, options) => {
9
+ if (!handle) {
10
+ const handlePrompt = window.prompt("Type your handle");
11
+ if (!handlePrompt) {
12
+ return;
13
+ }
14
+ return auth.signInWithHandle(handlePrompt, options);
15
+ }
16
+ return auth.signInWithHandle(handle, options);
17
+ },
18
+ isLogged: () => isLogged.value,
19
+ getSession: () => session.value
20
+ };
21
+ }
@@ -0,0 +1,10 @@
1
+ import type { Agent, AtpAgent } from '@atproto/api';
2
+ export type AtprotoAgentScope = 'authenticated' | 'public' | (string & {});
3
+ /**
4
+ * Returns a cached AT Protocol agent for the given scope (client-only).
5
+ *
6
+ * - `authenticated` — OAuth session agent (formerly `private`)
7
+ * - `public` — unauthenticated public API agent
8
+ * - custom string — `AtpAgent` for a specific PDS/service URL
9
+ */
10
+ export declare function useAtprotoAgent(scope: AtprotoAgentScope, fetch?: typeof globalThis.fetch): Agent | AtpAgent;
@@ -0,0 +1,8 @@
1
+ import { useAgent } from "./useAgent.js";
2
+ export function useAtprotoAgent(scope, fetch) {
3
+ if (import.meta.server) {
4
+ throw new Error("useAtprotoAgent is only available on the client");
5
+ }
6
+ const service = scope === "authenticated" ? "private" : scope;
7
+ return useAgent(service, fetch);
8
+ }
@@ -0,0 +1,12 @@
1
+ import type { OAuthSession } from '@atproto/oauth-client-browser';
2
+ import type { AtprotoSignInOptions } from '../../../types/index.js';
3
+ export interface UseAtprotoAuthReturn {
4
+ signIn: (serviceEndpoint?: string, options?: AtprotoSignInOptions) => Promise<void>;
5
+ signInWithHandle: (handle: string, options?: AtprotoSignInOptions) => Promise<void>;
6
+ signOut: () => Promise<void>;
7
+ restore: (did: string) => Promise<OAuthSession>;
8
+ }
9
+ /**
10
+ * ATProto sign-in, sign-out, and session restore (client-only).
11
+ */
12
+ export declare function useAtprotoAuth(): UseAtprotoAuthReturn;
@@ -0,0 +1,70 @@
1
+ import { useNuxtApp } from "nuxt/app";
2
+ import { applyAtprotoSession } from "../utils/sessionLifecycle.js";
3
+ import { useAtprotoRuntimeConfig } from "../utils/useAtprotoRuntimeConfig.js";
4
+ const serverAuthReturn = {
5
+ signIn: async () => {
6
+ },
7
+ signInWithHandle: async () => {
8
+ },
9
+ signOut: async () => {
10
+ },
11
+ restore: async () => {
12
+ throw new Error("useAtprotoAuth is only available on the client");
13
+ }
14
+ };
15
+ export function useAtprotoAuth() {
16
+ if (import.meta.server) {
17
+ return serverAuthReturn;
18
+ }
19
+ const atprotoConfig = useAtprotoRuntimeConfig();
20
+ async function signIn(serviceEndpoint = atprotoConfig.serviceEndpoint.private, options = atprotoConfig.oauth.signInOptions) {
21
+ const { $atproto } = useNuxtApp();
22
+ try {
23
+ await $atproto.client.signInRedirect(
24
+ serviceEndpoint,
25
+ {
26
+ ...options,
27
+ signal: new AbortController().signal
28
+ }
29
+ );
30
+ } catch (error) {
31
+ console.error("Error during sign-in:", error);
32
+ }
33
+ }
34
+ async function signInWithHandle(handle, options = atprotoConfig.oauth.signInOptions) {
35
+ const { $atproto } = useNuxtApp();
36
+ try {
37
+ const url = await $atproto.client.authorize(handle, options);
38
+ window.location.href = url.href;
39
+ } catch (error) {
40
+ console.error(`Error during sign-in for handle ${handle}:`, error);
41
+ }
42
+ }
43
+ async function restore(did) {
44
+ const nuxtApp = useNuxtApp();
45
+ const session = await nuxtApp.$atproto.client.restore(did);
46
+ applyAtprotoSession(nuxtApp, session, "account-switch");
47
+ return session;
48
+ }
49
+ async function signOut() {
50
+ const nuxtApp = useNuxtApp();
51
+ const session = nuxtApp.$atproto.session.value;
52
+ if (session) {
53
+ try {
54
+ await nuxtApp.$atproto.client.revoke(session.did);
55
+ } catch (error) {
56
+ console.error("Error revoking ATProto session:", error);
57
+ }
58
+ }
59
+ applyAtprotoSession(nuxtApp, void 0, "sign-out");
60
+ if (atprotoConfig.debug) {
61
+ console.log("User signed out");
62
+ }
63
+ }
64
+ return {
65
+ signIn,
66
+ signInWithHandle,
67
+ signOut,
68
+ restore
69
+ };
70
+ }
@@ -0,0 +1,12 @@
1
+ import type { OAuthSession } from '@atproto/oauth-client-browser';
2
+ import type { AtprotoSessionStatus } from '../../../types/index.js';
3
+ import { type ComputedRef, type Ref } from 'vue';
4
+ export interface UseAtprotoSessionReturn {
5
+ session: Ref<OAuthSession | undefined>;
6
+ isLogged: ComputedRef<boolean>;
7
+ status: Ref<AtprotoSessionStatus>;
8
+ }
9
+ /**
10
+ * Reactive ATProto OAuth session state (client-only).
11
+ */
12
+ export declare function useAtprotoSession(): UseAtprotoSessionReturn;
@@ -0,0 +1,18 @@
1
+ import { useNuxtApp } from "nuxt/app";
2
+ import { computed, shallowRef } from "vue";
3
+ const serverSessionReturn = {
4
+ session: shallowRef(void 0),
5
+ isLogged: computed(() => false),
6
+ status: shallowRef("anonymous")
7
+ };
8
+ export function useAtprotoSession() {
9
+ if (import.meta.server) {
10
+ return serverSessionReturn;
11
+ }
12
+ const { $atproto } = useNuxtApp();
13
+ return {
14
+ session: $atproto.session,
15
+ isLogged: computed(() => !!$atproto.session.value),
16
+ status: $atproto.status
17
+ };
18
+ }
@@ -0,0 +1,7 @@
1
+ import type { AtprotoContext } from '../../../types/index.js';
2
+ declare const _default: import("nuxt/app").Plugin<{
3
+ atproto: AtprotoContext;
4
+ }> & import("nuxt/app").ObjectPlugin<{
5
+ atproto: AtprotoContext;
6
+ }>;
7
+ export default _default;
@@ -0,0 +1,68 @@
1
+ import { BrowserOAuthClient } from "@atproto/oauth-client-browser";
2
+ import { defineNuxtPlugin } from "nuxt/app";
3
+ import { ref } from "vue";
4
+ import { useAtprotoRuntimeConfig } from "../utils/useAtprotoRuntimeConfig.js";
5
+ import { applyAtprotoSession } from "../utils/sessionLifecycle.js";
6
+ export default defineNuxtPlugin({
7
+ name: "atproto",
8
+ async setup(nuxtApp) {
9
+ const atprotoConfig = useAtprotoRuntimeConfig();
10
+ const status = ref("initializing");
11
+ const atprotoOAuthSession = ref();
12
+ const clientOptions = {
13
+ handleResolver: atprotoConfig.serviceEndpoint.private,
14
+ onDelete: (sub, cause) => {
15
+ if (atprotoConfig.debug) {
16
+ console.warn(`Session deleted for ${sub}. Cause:`, cause);
17
+ }
18
+ nuxtApp.hooks.callHook("atproto:sessionDeleted", sub);
19
+ }
20
+ };
21
+ let atprotoOAuthClient;
22
+ if (atprotoConfig.oauth.clientMetadata.remote) {
23
+ atprotoOAuthClient = await BrowserOAuthClient.load({
24
+ ...clientOptions,
25
+ clientId: atprotoConfig.oauth.clientMetadata.remote
26
+ });
27
+ } else {
28
+ atprotoOAuthClient = new BrowserOAuthClient({
29
+ ...clientOptions,
30
+ ...import.meta.env.DEV || !atprotoConfig.oauth.clientMetadata.local ? {} : { clientMetadata: atprotoConfig.oauth.clientMetadata.local }
31
+ });
32
+ }
33
+ const atproto = {
34
+ client: atprotoOAuthClient,
35
+ session: atprotoOAuthSession,
36
+ status
37
+ };
38
+ try {
39
+ const result = await atprotoOAuthClient.init();
40
+ if (result) {
41
+ const { session, state } = result;
42
+ if (atprotoConfig.debug) {
43
+ if (state != null) {
44
+ console.log(`${session.sub} was successfully authenticated (state: ${state})`);
45
+ } else {
46
+ console.log(`${session.sub} was restored (last active session)`);
47
+ }
48
+ }
49
+ applyAtprotoSession(
50
+ nuxtApp,
51
+ session,
52
+ state != null ? "oauth-return" : "cold-restore",
53
+ { deferHooks: true, atproto }
54
+ );
55
+ } else {
56
+ status.value = "anonymous";
57
+ }
58
+ } catch (error) {
59
+ console.error("Error initializing ATProto client or restoring session:", error);
60
+ status.value = "anonymous";
61
+ }
62
+ return {
63
+ provide: {
64
+ atproto
65
+ }
66
+ };
67
+ }
68
+ });
@@ -0,0 +1,8 @@
1
+ export declare const PRIVATE_AGENT_STATE_KEY = "atproto:agent:private";
2
+ export declare const PRIVATE_AGENT_SESSION_KEY = "atproto:agent:private-session-sub";
3
+ export declare function publicAgentStateKey(serviceEndpoint: string): string;
4
+ export declare function customAgentStateKey(service: string): string;
5
+ /**
6
+ * Clears the cached authenticated agent. Call after sign-out or before restore.
7
+ */
8
+ export declare function invalidateAtprotoPrivateAgent(): void;
@@ -0,0 +1,15 @@
1
+ import { useState } from "nuxt/app";
2
+ export const PRIVATE_AGENT_STATE_KEY = "atproto:agent:private";
3
+ export const PRIVATE_AGENT_SESSION_KEY = "atproto:agent:private-session-sub";
4
+ export function publicAgentStateKey(serviceEndpoint) {
5
+ return `atproto:agent:public:${serviceEndpoint}`;
6
+ }
7
+ export function customAgentStateKey(service) {
8
+ return `atproto:agent:${service}`;
9
+ }
10
+ export function invalidateAtprotoPrivateAgent() {
11
+ const cachedAgent = useState(PRIVATE_AGENT_STATE_KEY, () => null);
12
+ const cachedSessionSub = useState(PRIVATE_AGENT_SESSION_KEY, () => null);
13
+ cachedAgent.value = null;
14
+ cachedSessionSub.value = null;
15
+ }
@@ -0,0 +1,22 @@
1
+ import type { OAuthSession } from '@atproto/oauth-client-browser';
2
+ import type { NuxtApp } from 'nuxt/app';
3
+ import type { AtprotoContext } from '../../../types/index.js';
4
+ export interface AtprotoSessionLifecycleHooks {
5
+ hook: (name: string, callback: () => void) => void;
6
+ callHook: (name: string, did: string) => void | Promise<void>;
7
+ }
8
+ export type AtprotoSessionTransition = 'oauth-return' | 'cold-restore' | 'account-switch' | 'sign-out';
9
+ export interface ApplyAtprotoSessionOptions {
10
+ /** When true, lifecycle hooks run after `app:mounted` (plugin init). */
11
+ deferHooks?: boolean;
12
+ /** Pass during plugin setup before `provide` returns. */
13
+ atproto?: AtprotoContext;
14
+ }
15
+ /**
16
+ * Updates `$atproto` session state, agent cache, status, and lifecycle hooks.
17
+ */
18
+ export declare function applyAtprotoSession(nuxtApp: NuxtApp, session: OAuthSession | undefined, transition: AtprotoSessionTransition, options?: ApplyAtprotoSessionOptions): void;
19
+ /**
20
+ * @deprecated Use `applyAtprotoSession` with `deferHooks: true` instead.
21
+ */
22
+ export declare function scheduleAtprotoSessionHooks(hooks: AtprotoSessionLifecycleHooks, sessionSub: string, state: string | null | undefined): void;
@@ -0,0 +1,29 @@
1
+ import { invalidateAtprotoPrivateAgent } from "./agentCache.js";
2
+ export function applyAtprotoSession(nuxtApp, session, transition, options = {}) {
3
+ const atproto = options.atproto ?? nuxtApp.$atproto;
4
+ const { deferHooks = false } = options;
5
+ if (session) {
6
+ invalidateAtprotoPrivateAgent();
7
+ atproto.session.value = session;
8
+ atproto.status.value = "authenticated";
9
+ const hookName = transition === "oauth-return" ? "atproto:sessionCreated" : "atproto:sessionRestored";
10
+ emitSessionLifecycleHook(nuxtApp.hooks, hookName, session.sub, deferHooks);
11
+ return;
12
+ }
13
+ invalidateAtprotoPrivateAgent();
14
+ atproto.session.value = void 0;
15
+ atproto.status.value = "anonymous";
16
+ }
17
+ function emitSessionLifecycleHook(hooks, hookName, did, defer) {
18
+ if (defer) {
19
+ hooks.hook("app:mounted", () => {
20
+ hooks.callHook(hookName, did);
21
+ });
22
+ return;
23
+ }
24
+ hooks.callHook(hookName, did);
25
+ }
26
+ export function scheduleAtprotoSessionHooks(hooks, sessionSub, state) {
27
+ const hookName = state != null ? "atproto:sessionCreated" : "atproto:sessionRestored";
28
+ emitSessionLifecycleHook(hooks, hookName, sessionSub, true);
29
+ }
@@ -0,0 +1,2 @@
1
+ import type { AtprotoNuxtOptions } from '../../../types/index.js';
2
+ export declare function useAtprotoRuntimeConfig(): AtprotoNuxtOptions;
@@ -0,0 +1,4 @@
1
+ import { useRuntimeConfig } from "nuxt/app";
2
+ export function useAtprotoRuntimeConfig() {
3
+ return useRuntimeConfig().public.atproto;
4
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-atproto",
3
- "version": "0.0.5",
3
+ "version": "0.1.0",
4
4
  "description": "Interact with AT Protocol and Bluesky in your Nuxt.js application",
5
5
  "keywords": [
6
6
  "nuxt",
@@ -47,23 +47,23 @@
47
47
  "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit"
48
48
  },
49
49
  "dependencies": {
50
- "@nuxt/kit": "^3.17.2",
51
- "@atproto/api": "^0.15.3",
52
- "@atproto/oauth-client-browser": "^0.3.11"
50
+ "@nuxt/kit": "^4.4.6",
51
+ "@atproto/api": "^0.20.6",
52
+ "@atproto/oauth-client-browser": "^0.4.1"
53
53
  },
54
54
  "devDependencies": {
55
- "@nuxt/devtools": "^2.4.0",
56
- "@nuxt/eslint-config": "^1.3.0",
57
- "@nuxt/module-builder": "^1.0.1",
58
- "@nuxt/schema": "^3.17.2",
59
- "@nuxt/test-utils": "^3.18.0",
55
+ "@nuxt/devtools": "^3.2.4",
56
+ "@nuxt/eslint-config": "^1.15.2",
57
+ "@nuxt/module-builder": "^1.0.2",
58
+ "@nuxt/schema": "^4.4.6",
60
59
  "@types/node": "latest",
61
- "changelogen": "^0.6.1",
62
- "eslint": "^9.26.0",
63
- "nuxt": "^3.17.2",
64
- "typescript": "~5.8.3",
65
- "vitest": "^3.1.2",
66
- "vue-tsc": "^2.2.10"
60
+ "changelogen": "^0.6.2",
61
+ "eslint": "^10.4.0",
62
+ "nuxt": "^4.4.6",
63
+ "typescript": "~6.0.3",
64
+ "vitest": "^4.1.7",
65
+ "vue": "^3.5.35",
66
+ "vue-tsc": "^3.3.2"
67
67
  },
68
68
  "unbuild": {
69
69
  "failOnWarn": false
@@ -1,8 +0,0 @@
1
- import { Agent } from "@atproto/api";
2
- /**
3
- * Provide AT Protocol agent
4
- *
5
- * @param service
6
- * @param fetch
7
- */
8
- export declare function useAgent(service: string, fetch?: any): Agent;
@@ -1,23 +0,0 @@
1
- import { useNuxtApp, useRuntimeConfig } from "#app";
2
- import { Agent, AtpAgent } from "@atproto/api";
3
- export function useAgent(service, fetch) {
4
- const runtimeConfig = useRuntimeConfig();
5
- const { $atproto } = useNuxtApp();
6
- switch (service) {
7
- case "private":
8
- if (!$atproto.session.value) {
9
- throw new Error("Not authenticated");
10
- }
11
- return new Agent($atproto.session.value);
12
- case "public":
13
- return new AtpAgent({
14
- service: runtimeConfig.public.atproto.serviceEndpoint.public,
15
- fetch
16
- });
17
- default:
18
- return new AtpAgent({
19
- service,
20
- fetch
21
- });
22
- }
23
- }
@@ -1,9 +0,0 @@
1
- import type { OAuthSession } from '@atproto/oauth-client';
2
- export declare function useAtproto(service?: string, fetch?: any): {
3
- signIn: (serviceEndpoint?: string, options?: any) => Promise<void>;
4
- signInWithHandle: (handle?: string, options?: any) => Promise<void>;
5
- signOut: () => Promise<void>;
6
- restore: (did: string) => Promise<OAuthSession>;
7
- isLogged: () => boolean;
8
- getSession: () => any;
9
- };
@@ -1,65 +0,0 @@
1
- import { useRuntimeConfig, useNuxtApp } from "nuxt/app";
2
- export function useAtproto(service, fetch) {
3
- const runtimeConfig = useRuntimeConfig();
4
- async function signIn(serviceEndpoint = runtimeConfig.public.atproto.serviceEndpoint.private, options = runtimeConfig.public.atproto.oauth.signInOptions) {
5
- const { $atproto } = useNuxtApp();
6
- try {
7
- await $atproto.client.signInRedirect(
8
- serviceEndpoint,
9
- {
10
- ...options,
11
- signal: new AbortController().signal
12
- }
13
- );
14
- } catch (error) {
15
- console.error(`Error during sign-in:`, error);
16
- }
17
- }
18
- async function signInWithHandle(handle, options = runtimeConfig.public.atproto.oauth.signInOptions) {
19
- const { $atproto } = useNuxtApp();
20
- try {
21
- let handlePrompt = null;
22
- if (!handle) {
23
- handlePrompt = window.prompt("Type your handle");
24
- if (!handlePrompt) {
25
- return;
26
- }
27
- handle = handlePrompt;
28
- }
29
- const url = await $atproto.client.authorize(handle, options);
30
- window.location.href = url.href;
31
- } catch (error) {
32
- console.error(`Error during sign-in for handle ${handle}:`, error);
33
- }
34
- }
35
- async function restore(did) {
36
- const { $atproto } = useNuxtApp();
37
- const session = await $atproto.client.restore(did);
38
- $atproto.session.value = session;
39
- return session;
40
- }
41
- async function signOut() {
42
- const { $atproto } = useNuxtApp();
43
- $atproto.client.revoke($atproto.session.value.did);
44
- $atproto.session.value = void 0;
45
- if (runtimeConfig.public.atproto.debug) {
46
- console.log("User signed out");
47
- }
48
- }
49
- function isLogged() {
50
- const { $atproto } = useNuxtApp();
51
- return !!$atproto.session.value;
52
- }
53
- function getSession() {
54
- const { $atproto } = useNuxtApp();
55
- return $atproto.session.value;
56
- }
57
- return {
58
- signIn,
59
- signInWithHandle,
60
- signOut,
61
- restore,
62
- isLogged,
63
- getSession
64
- };
65
- }
@@ -1,12 +0,0 @@
1
- declare const _default: import("nuxt/app").Plugin<{
2
- atproto: {
3
- client: any;
4
- session: import("vue").Ref<any, any>;
5
- };
6
- }> & import("nuxt/app").ObjectPlugin<{
7
- atproto: {
8
- client: any;
9
- session: import("vue").Ref<any, any>;
10
- };
11
- }>;
12
- export default _default;
@@ -1,61 +0,0 @@
1
- import { BrowserOAuthClient } from "@atproto/oauth-client-browser";
2
- import { useRuntimeConfig, defineNuxtPlugin } from "nuxt/app";
3
- import { ref } from "vue";
4
- export default defineNuxtPlugin({
5
- name: "atproto",
6
- async setup(_nuxtApp) {
7
- const runtimeConfig = useRuntimeConfig();
8
- let atprotoOAuthClient;
9
- const atprotoOAuthSession = ref();
10
- if (runtimeConfig.public.atproto.oauth.clientMetadata.remote) {
11
- atprotoOAuthClient = await BrowserOAuthClient.load({
12
- handleResolver: runtimeConfig.public.atproto.serviceEndpoint.private,
13
- clientId: runtimeConfig.public.atproto.oauth.clientMetadata.remote
14
- // todo implement custom fetch
15
- });
16
- } else {
17
- atprotoOAuthClient = new BrowserOAuthClient({
18
- handleResolver: runtimeConfig.public.atproto.serviceEndpoint.private,
19
- // @ts-ignore
20
- clientMetadata: import.meta.env.MODE === "development" ? void 0 : runtimeConfig.public.atproto.oauth.clientMetadata.local
21
- // todo implement custom fetch
22
- });
23
- }
24
- atprotoOAuthClient.addEventListener("deleted", (event) => {
25
- const { sub, cause } = event.detail;
26
- if (runtimeConfig.public.atproto.debug) {
27
- console.warn(`Session deleted for ${sub}. Cause:`, cause);
28
- }
29
- _nuxtApp.hooks.callHook("atproto:sessionDeleted", sub);
30
- });
31
- await atprotoOAuthClient.init().then(async (result) => {
32
- if (result) {
33
- const { session, state } = result;
34
- if (runtimeConfig.public.atproto.debug) {
35
- if (state != null) {
36
- console.log(`${session.sub} was successfully authenticated (state: ${state})`);
37
- _nuxtApp.hook("app:mounted", async () => {
38
- _nuxtApp.hooks.callHook("atproto:sessionCreated", session.sub);
39
- });
40
- } else {
41
- console.log(`${session.sub} was restored (last active session)`);
42
- _nuxtApp.hook("app:mounted", async () => {
43
- _nuxtApp.hooks.callHook("atproto:sessionRestored", session.sub);
44
- });
45
- }
46
- }
47
- atprotoOAuthSession.value = session;
48
- }
49
- }).catch((error) => {
50
- console.error("Error initializing ATProto client or restoring session:", error);
51
- });
52
- return {
53
- provide: {
54
- atproto: {
55
- client: atprotoOAuthClient,
56
- session: atprotoOAuthSession
57
- }
58
- }
59
- };
60
- }
61
- });
@@ -1,2 +0,0 @@
1
- export declare function resolveActorDid(handle: string): Promise<string>;
2
- export declare function resolveActorServiceEndpoint(did: string): Promise<string>;
@@ -1,16 +0,0 @@
1
- import { useAgent } from "../composables/useAgent.js";
2
- export async function resolveActorDid(handle) {
3
- const agent = useAgent("public");
4
- const { did } = await agent.com.atproto.identity.resolveHandle({
5
- handle
6
- }).then((result) => result.data);
7
- return did;
8
- }
9
- export async function resolveActorServiceEndpoint(did) {
10
- const response = await fetch(`https://plc.directory/${did}`);
11
- if (!response.ok) {
12
- throw new Error("Failed to fetch profile service endpoint");
13
- }
14
- const data = await response.json();
15
- return data.service[0].serviceEndpoint;
16
- }