@defjs/vue 0.0.1-beta.0 → 0.0.2

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 (4) hide show
  1. package/README.md +61 -69
  2. package/index.d.ts +27 -13
  3. package/index.js +30 -15
  4. package/package.json +3 -2
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @defjs/vue
2
2
 
3
- Thin Vue 3 adapter for `@defjs/core`. It provides an existing Defjs client through Vue injection.
3
+ Thin Vue 3 plugin for `@defjs/core`: it provides an application-owned client through Vue injection. It adds no transport behavior, state management, retries, or Nuxt module, and never creates, replaces, or disposes a client.
4
4
 
5
- Supports Vue 3+.
5
+ Keeping SDK definitions in their own package means the SDK needs no Vue dependency. Requires Vue 3 or later.
6
6
 
7
7
  ## Install
8
8
 
@@ -10,56 +10,55 @@ Supports Vue 3+.
10
10
  bun add @defjs/core @defjs/vue vue
11
11
  ```
12
12
 
13
- The package is ESM and requires `@defjs/core` as a peer in the `^0.4.0` range. Its tarball retains this `README.md` and the repository `LICENSE`; repository-wide guides and examples remain outside the package.
13
+ The package is ESM and requires `@defjs/core` as a peer in the `^0.5.0` range.
14
14
 
15
- ## What this package does
16
-
17
- `createClientPlugin(client)` creates a Vue plugin that provides the exact `Client` instance supplied by the application. `injectClient()` reads the nearest provided instance. `HTTP_CLIENT` remains public for native subtree overrides.
18
-
19
- Client creation and configuration stay in `@defjs/core`. The adapter does not create, cache, replace, dispose, abort, or close anything on behalf of the application, and it does not add transport behavior, state management, retries, or a Nuxt module.
20
-
21
- ## Quick Start
22
-
23
- Create and own the client at the application entry point:
15
+ ## Quick start
24
16
 
25
17
  ```ts
26
- // main.ts
27
- import { createClient, withEndpoint } from '@defjs/core'
28
- import { createClientPlugin } from '@defjs/vue'
29
- import { createApp } from 'vue'
30
- import App from './App.vue'
18
+ // main.ts — application entry point
19
+ import { createClient, withEndpoint } from "@defjs/core";
20
+ import { createClientPlugin } from "@defjs/vue";
21
+ import { createApp } from "vue";
22
+ import App from "./App.vue";
31
23
 
32
- const client = createClient(withEndpoint('https://api.example.com'))
33
- const app = createApp(App)
24
+ const client = createClient(withEndpoint("https://api.example.com"));
25
+ const app = createApp(App);
34
26
 
35
- app.use(createClientPlugin(client))
36
- app.mount('#app')
27
+ app.use(createClientPlugin(client));
28
+ app.mount("#app");
37
29
  ```
38
30
 
39
- Use the injected client inside a component or composable and own cleanup where the work starts:
31
+ Read the client with `injectClient()` and own cleanup in the watcher:
40
32
 
41
33
  ```vue
42
34
  <script setup lang="ts">
43
- import { ref, watch } from 'vue'
44
- import { injectClient } from '@defjs/vue'
45
- import { getUser } from './api'
35
+ import { ref, watch } from "vue";
36
+ import { injectClient } from "@defjs/vue";
37
+ import { getUser } from "./api";
46
38
 
47
- const props = defineProps<{ id: number }>()
48
- const client = injectClient()
49
- const name = ref('')
39
+ const props = defineProps<{ id: number }>();
40
+ const client = injectClient();
41
+ const name = ref("");
50
42
 
51
43
  watch(
52
44
  () => props.id,
53
45
  (id, _previousId, onCleanup) => {
54
- const abort = new AbortController()
55
- onCleanup(() => abort.abort())
56
-
57
- void client.execute(getUser({ path: { id } }), { signal: abort.signal }).then(([error, user]) => {
58
- if (!abort.signal.aborted) name.value = error ? error.message : user.name
59
- })
46
+ const abort = new AbortController();
47
+ onCleanup(() => abort.abort());
48
+
49
+ void getUser(client({ abort: abort.signal }), { id }).then(
50
+ ([error, user]) => {
51
+ if (abort.signal.aborted) return;
52
+ if (error) {
53
+ name.value = error.message;
54
+ return;
55
+ }
56
+ name.value = user.name;
57
+ },
58
+ );
60
59
  },
61
60
  { immediate: true },
62
- )
61
+ );
63
62
  </script>
64
63
 
65
64
  <template>
@@ -67,54 +66,47 @@ watch(
67
66
  </template>
68
67
  ```
69
68
 
70
- Configure interceptors in core before installing the plugin:
69
+ ## API
71
70
 
72
- ```ts
73
- import { createClient, createHttpInterceptor, withEndpoint, withInterceptors } from '@defjs/core'
74
- import { createClientPlugin } from '@defjs/vue'
71
+ ### `createClientPlugin(client): Plugin`
75
72
 
76
- const auth = createHttpInterceptor((request, next) => {
77
- const headers = new Headers(request.headers)
78
- headers.set('Authorization', `Bearer ${getAccessToken()}`)
79
- return next({ ...request, headers })
80
- })
73
+ Creates a Vue plugin that provides the supplied client as `HTTP_CLIENT`.
81
74
 
82
- const client = createClient(withEndpoint('https://api.example.com'), withInterceptors(auth))
83
- app.use(createClientPlugin(client))
84
- ```
75
+ ### `injectClient(key?): Client`
85
76
 
86
- For a subtree override, use Vue's native provider with the public key:
77
+ Returns the nearest client for `key`, defaulting to `HTTP_CLIENT`. Call it in a valid injection context: synchronous `setup()` or `app.runWithContext()` (Vue 3.3+). Throws without an active context or a client for the key; a missing custom key never falls back to `HTTP_CLIENT`.
87
78
 
88
- ```ts
89
- import { createClient, withEndpoint } from '@defjs/core'
90
- import { HTTP_CLIENT } from '@defjs/vue'
91
- import { provide } from 'vue'
79
+ ### `HTTP_CLIENT`
92
80
 
93
- provide(HTTP_CLIENT, createClient(withEndpoint('https://preview.example.com')))
94
- ```
81
+ Public `InjectionKey<Client>` for native subtree overrides:
95
82
 
96
- Descendants receive that exact client; siblings outside the subtree continue to receive the app-level client.
97
-
98
- ## API
99
-
100
- ### `createClientPlugin(client: Client): Plugin`
83
+ ```ts
84
+ provide(HTTP_CLIENT, createClient(withEndpoint("https://preview.example.com")));
85
+ ```
101
86
 
102
- Creates a Vue plugin that provides the supplied client instance.
87
+ Descendants receive that client; siblings outside the subtree keep the app-level one.
103
88
 
104
- ### `injectClient(): Client`
89
+ Interceptors and every other client option belong to `@defjs/core` and are configured before the plugin is installed:
105
90
 
106
- Returns the client from the nearest Vue provider. Throws if no client was provided.
91
+ ```ts
92
+ const client = createClient(
93
+ withEndpoint("https://api.example.com"),
94
+ withInterceptors(auth),
95
+ );
96
+ app.use(createClientPlugin(client));
97
+ ```
107
98
 
108
- ### `HTTP_CLIENT: InjectionKey<Client>`
99
+ ## Notes
109
100
 
110
- Public injection key for native subtree providers.
101
+ - `Client` is a function. `injectClient()` returns that same function. Pass it straight to `createClientPlugin` or `provide`. Do not pass it to `watch` or `computed` as the source: Vue calls a function source. Do not wrap it in `ref` or `reactive`; the plugin stores the function as-is.
102
+ - Create request-specific clients (SSR data with credentials, cookies, or tenant state) at the application boundary.
103
+ - The owner that creates a client also owns its requests, SSE streams, and WebSocket sessions. App unmount does not clean them up.
104
+ - Import `createClient`, `withEndpoint`, `withInterceptors`, and other client options from `@defjs/core`.
111
105
 
112
- ## Notes
106
+ ## Documentation
113
107
 
114
- - Create request-specific clients at the application boundary for SSR data that contains credentials, cookies, or tenant state.
115
- - The owner that creates a client also owns all requests, SSE streams, and WebSocket sessions started through it. App unmount does not clean them up automatically.
116
- - Import `createClient`, `withEndpoint`, `withInterceptors`, and all other client options from `@defjs/core`.
108
+ - [Vue API](https://defjs.lyz.cloud/api/vue) · [Vue guide](https://defjs.lyz.cloud/docs/integrations/vue)
117
109
 
118
110
  ## License
119
111
 
120
- MIT License.
112
+ MIT.
package/index.d.ts CHANGED
@@ -1,36 +1,50 @@
1
1
  import { InjectionKey, Plugin } from "vue";
2
2
  import { Client } from "@defjs/core";
3
- //#region src/core.d.ts
4
3
  /**
5
4
  * Vue injection key for the Defjs {@link Client} provided by {@link createClientPlugin}.
6
5
  *
7
- * Prefer {@link injectClient} over calling `inject(HTTP_CLIENT)` directly.
6
+ * Prefer {@link injectClient} over calling `inject(HTTP_CLIENT)` directly. `inject(HTTP_CLIENT)` returns `undefined` when nothing was provided. Override a subtree with `provide(HTTP_CLIENT, childClient)`.
7
+ *
8
+ * @group vue
9
+ * @see {@link Client}
10
+ * @see {@link injectClient}
8
11
  */
9
12
  export declare const HTTP_CLIENT: InjectionKey<Client>;
10
13
  /**
11
14
  * Create a Vue plugin that provides an existing Defjs client via {@link HTTP_CLIENT}.
12
15
  *
13
- * Does not create, cache, or dispose the client — pass an instance from `createClient`.
16
+ * Does not create, cache, or dispose the client — pass the function from `createClient`. Installing it calls `app.provide(HTTP_CLIENT, client)`, so components read the client with `injectClient()`. The client is stored as that function: it is not wrapped in `ref`, `reactive`, or `markRaw`.
14
17
  *
15
- * @param client - The Client instance to provide to the app.
18
+ * @param client - The client function to provide to the app.
16
19
  * @returns A Vue `Plugin` for `app.use(...)`.
17
20
  *
18
- * @example
19
- * ```ts
20
- * app.use(createClientPlugin(client))
21
- * ```
21
+ * @group vue
22
+ * @see {@link Client}
23
+ * @exampleFile examples/api/create-client-plugin.ts#example
22
24
  */
23
25
  export declare function createClientPlugin(client: Client): Plugin;
24
26
  /**
25
- * Inject the Defjs client provided by {@link createClientPlugin}.
27
+ * Vue composable that injects the Defjs client for a key, defaulting to {@link HTTP_CLIENT}.
28
+ *
29
+ * `injectClient(key)` reads the nearest provider for that key; omitted or `undefined` uses `HTTP_CLIENT`. Call in a valid Vue injection context: synchronous `setup()`, compiler-restored `<script setup>` after top-level `await`, or a synchronous `app.runWithContext()` callback (Vue 3.3+). `app.runWithContext()` supplies only synchronous app-level context, not subtree overrides or context across ordinary `await`.
30
+ *
31
+ * For a custom `InjectionKey<Client>`, use `app.provide(key, client)` or an ancestor’s `provide(key, client)`. Share the same `Symbol` object; matching descriptions do not make keys equal. `createClientPlugin(client)` still takes only the client and provides `HTTP_CLIENT`.
32
+ *
33
+ * It returns the exact client function provided for the selected key, and throws an `Error` without an active injection context or a client for the selected key. Installing the plugin alone does not establish an injection context.
34
+ *
35
+ * `Client` is callable. Pass it to `provide` as-is. Do not pass it to `watch` or `computed` as the source: Vue calls a function source. Do not wrap it in `ref` or `reactive`.
26
36
  *
27
- * @returns The injected `Client` instance.
28
- * @throws If no client was provided (plugin not installed).
37
+ * @param key - Injection key; use the same object with `app.provide` or `provide`.
38
+ * Defaults to `HTTP_CLIENT`, as provided by {@link createClientPlugin}.
39
+ * @returns The injected client function.
40
+ * @throws If called outside a Vue injection context or no client was provided for
41
+ * the requested key. A missing custom key does not fall back to `HTTP_CLIENT`.
29
42
  *
30
43
  * @example
31
44
  * ```ts
32
45
  * const client = injectClient()
33
46
  * ```
47
+ * @group vue
48
+ * @see {@link Client}
34
49
  */
35
- export declare function injectClient(): Client;
36
- //#endregion
50
+ export declare function injectClient(key?: InjectionKey<Client>): Client;
package/index.js CHANGED
@@ -1,23 +1,26 @@
1
1
  import { inject } from "vue";
2
- //#region src/core.ts
2
+ // src/core.ts
3
3
  /**
4
4
  * Vue injection key for the Defjs {@link Client} provided by {@link createClientPlugin}.
5
5
  *
6
- * Prefer {@link injectClient} over calling `inject(HTTP_CLIENT)` directly.
6
+ * Prefer {@link injectClient} over calling `inject(HTTP_CLIENT)` directly. `inject(HTTP_CLIENT)` returns `undefined` when nothing was provided. Override a subtree with `provide(HTTP_CLIENT, childClient)`.
7
+ *
8
+ * @group vue
9
+ * @see {@link Client}
10
+ * @see {@link injectClient}
7
11
  */
8
12
  const HTTP_CLIENT = Symbol("HTTP_CLIENT");
9
13
  /**
10
14
  * Create a Vue plugin that provides an existing Defjs client via {@link HTTP_CLIENT}.
11
15
  *
12
- * Does not create, cache, or dispose the client — pass an instance from `createClient`.
16
+ * Does not create, cache, or dispose the client — pass the function from `createClient`. Installing it calls `app.provide(HTTP_CLIENT, client)`, so components read the client with `injectClient()`. The client is stored as that function: it is not wrapped in `ref`, `reactive`, or `markRaw`.
13
17
  *
14
- * @param client - The Client instance to provide to the app.
18
+ * @param client - The client function to provide to the app.
15
19
  * @returns A Vue `Plugin` for `app.use(...)`.
16
20
  *
17
- * @example
18
- * ```ts
19
- * app.use(createClientPlugin(client))
20
- * ```
21
+ * @group vue
22
+ * @see {@link Client}
23
+ * @exampleFile examples/api/create-client-plugin.ts#example
21
24
  */
22
25
  function createClientPlugin(client) {
23
26
  return { install(app) {
@@ -25,20 +28,32 @@ function createClientPlugin(client) {
25
28
  } };
26
29
  }
27
30
  /**
28
- * Inject the Defjs client provided by {@link createClientPlugin}.
31
+ * Vue composable that injects the Defjs client for a key, defaulting to {@link HTTP_CLIENT}.
32
+ *
33
+ * `injectClient(key)` reads the nearest provider for that key; omitted or `undefined` uses `HTTP_CLIENT`. Call in a valid Vue injection context: synchronous `setup()`, compiler-restored `<script setup>` after top-level `await`, or a synchronous `app.runWithContext()` callback (Vue 3.3+). `app.runWithContext()` supplies only synchronous app-level context, not subtree overrides or context across ordinary `await`.
34
+ *
35
+ * For a custom `InjectionKey<Client>`, use `app.provide(key, client)` or an ancestor’s `provide(key, client)`. Share the same `Symbol` object; matching descriptions do not make keys equal. `createClientPlugin(client)` still takes only the client and provides `HTTP_CLIENT`.
36
+ *
37
+ * It returns the exact client function provided for the selected key, and throws an `Error` without an active injection context or a client for the selected key. Installing the plugin alone does not establish an injection context.
38
+ *
39
+ * `Client` is callable. Pass it to `provide` as-is. Do not pass it to `watch` or `computed` as the source: Vue calls a function source. Do not wrap it in `ref` or `reactive`.
29
40
  *
30
- * @returns The injected `Client` instance.
31
- * @throws If no client was provided (plugin not installed).
41
+ * @param key - Injection key; use the same object with `app.provide` or `provide`.
42
+ * Defaults to `HTTP_CLIENT`, as provided by {@link createClientPlugin}.
43
+ * @returns The injected client function.
44
+ * @throws If called outside a Vue injection context or no client was provided for
45
+ * the requested key. A missing custom key does not fall back to `HTTP_CLIENT`.
32
46
  *
33
47
  * @example
34
48
  * ```ts
35
49
  * const client = injectClient()
36
50
  * ```
51
+ * @group vue
52
+ * @see {@link Client}
37
53
  */
38
- function injectClient() {
39
- const client = inject(HTTP_CLIENT);
40
- if (!client) throw new Error("No Defjs client provided. Did you forget to call app.use(createClientPlugin(client))?");
54
+ function injectClient(key = HTTP_CLIENT) {
55
+ const client = inject(key);
56
+ if (!client) throw new Error(key === HTTP_CLIENT ? "No Defjs client available. Call injectClient() in a Vue injection context (such as synchronous setup() or app.runWithContext()) and provide a client with app.use(createClientPlugin(client)) or provide(HTTP_CLIENT, client)." : "No Defjs client available for the requested injection key. Call injectClient(key) in a Vue injection context and provide a client with app.provide(key, client) or provide(key, client). Use the same key object when providing and injecting.");
41
57
  return client;
42
58
  }
43
- //#endregion
44
59
  export { HTTP_CLIENT, createClientPlugin, injectClient };
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@defjs/vue",
3
- "version": "0.0.1-beta.0",
3
+ "version": "0.0.2",
4
+ "description": "Provide an existing Defjs client to a Vue application.",
4
5
  "bugs": {
5
6
  "url": "https://github.com/defjs/defjs/issues"
6
7
  },
@@ -13,7 +14,7 @@
13
14
  "main": "./index.js",
14
15
  "types": "./index.d.ts",
15
16
  "peerDependencies": {
16
- "@defjs/core": "0.4.0-beta.0",
17
+ "@defjs/core": "^0.5.0",
17
18
  "vue": ">=3.0.0"
18
19
  },
19
20
  "module": "./index.js",