@hostlink/nuxt-light 1.75.0 → 1.76.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.
package/README.md CHANGED
@@ -55,6 +55,114 @@ export default defineNuxtConfig({
55
55
 
56
56
  That's it! You can now use nuxt-light in your Nuxt app ✨
57
57
 
58
+ ## API clients
59
+
60
+ `nuxt-light` supports multiple Light API endpoints. The client named `auth` is
61
+ always the default: when a component or composable does not specify a client,
62
+ the request is sent to `auth`.
63
+
64
+ Configure named clients in `nuxt.config.ts`:
65
+
66
+ ```ts
67
+ export default defineNuxtConfig({
68
+ runtimeConfig: {
69
+ public: {
70
+ light: {
71
+ clients: {
72
+ auth: {
73
+ baseURL: 'https://auth.example.com/graphql',
74
+ },
75
+ business: {
76
+ baseURL: 'https://business.example.com/graphql',
77
+ },
78
+ },
79
+ },
80
+ },
81
+ },
82
+ modules: [
83
+ '@hostlink/nuxt-light',
84
+ ],
85
+ })
86
+ ```
87
+
88
+ A client can also be configured with a URL string:
89
+
90
+ ```ts
91
+ clients: {
92
+ auth: '/auth-api/',
93
+ business: '/business-api/',
94
+ }
95
+ ```
96
+
97
+ ### Backwards-compatible single endpoint
98
+
99
+ The existing `public.apiBase` setting is still supported. When no named
100
+ `auth` client is configured, `apiBase` is registered as the `auth` client:
101
+
102
+ ```ts
103
+ export default defineNuxtConfig({
104
+ runtimeConfig: {
105
+ public: {
106
+ apiBase: '/api/',
107
+ },
108
+ },
109
+ })
110
+ ```
111
+
112
+ If neither setting is provided, the default Auth API URL is `/api/`.
113
+
114
+ ### Selecting a client
115
+
116
+ Use `useLightClient()` without an argument to get the Auth API client:
117
+
118
+ ```ts
119
+ const auth = useLightClient()
120
+ const business = useLightClient('business')
121
+
122
+ await auth.auth.login(username, password)
123
+ await business.query({
124
+ app: {
125
+ orders: {
126
+ order_id: true,
127
+ },
128
+ },
129
+ })
130
+ ```
131
+
132
+ The standard composables also default to `auth`:
133
+
134
+ ```ts
135
+ await q(query) // auth
136
+ await q(query, 'business') // business
137
+
138
+ model('User') // auth
139
+ model('Order', 'business') // business
140
+
141
+ collect('User', fields) // auth
142
+ collect('Order', fields, 'business') // business
143
+
144
+ await m('updateUser', args, fields) // auth
145
+ await m('updateOrder', args, fields, 'business') // business
146
+ ```
147
+
148
+ `<L-Table>` uses `auth` unless its `client` prop is provided:
149
+
150
+ ```vue
151
+ <template>
152
+ <!-- Uses the default auth client -->
153
+ <L-Table model-name="User" />
154
+
155
+ <!-- Uses the business client -->
156
+ <L-Table
157
+ client="business"
158
+ model-name="Order"
159
+ />
160
+ </template>
161
+ ```
162
+
163
+ An unknown client name throws an explicit configuration error instead of
164
+ silently sending the request to another endpoint.
165
+
58
166
  ## Development
59
167
 
60
168
  ```bash
@@ -119,4 +227,4 @@ nuxt.config.ts
119
227
  ]
120
228
  }
121
229
  }
122
- ```
230
+ ```
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "light",
3
3
  "configKey": "light",
4
- "version": "1.75.0",
4
+ "version": "1.76.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -220,7 +220,6 @@ const module$1 = defineNuxtModule({
220
220
  });
221
221
  addImports({ name: "isGranted", from: "@hostlink/light" });
222
222
  addImports({ name: "getGrantedRights", from: "@hostlink/light" });
223
- addImports({ name: "query", as: "q", from: "@hostlink/light" });
224
223
  addImports({ name: "mutation", from: "@hostlink/light" });
225
224
  addImports({ name: "query", from: "@hostlink/light" });
226
225
  await addComponentsDir({
@@ -27,6 +27,7 @@ export type LTableColumn = QTableColumn & {
27
27
  autoWidth?: boolean;
28
28
  };
29
29
  export type LTableProps = QTableProps & {
30
+ client?: string;
30
31
  columns?: Array<LTableColumn>;
31
32
  actions?: Array<'view' | 'edit' | 'delete' | 'update'>;
32
33
  sortBy?: string;
@@ -127,6 +128,7 @@ declare const __VLS_base: import("vue").DefineComponent<LTableProps, {
127
128
  rowsPerPageLabel: string;
128
129
  rowsPerPageOptions: readonly any[];
129
130
  selection: "none" | "single" | "multiple";
131
+ client: string;
130
132
  searchable: boolean;
131
133
  canExpandRow: (row: any) => boolean;
132
134
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -5,8 +5,9 @@ import { ref, computed, onMounted, useSlots, watch, useAttrs } from "vue";
5
5
  import useLight from "../../composables/useLight";
6
6
  import { useLightTableDefaults } from "../../composables/useLightProps";
7
7
  import model from "../../composables/model";
8
+ import useLightClient from "../../composables/useLightClient";
8
9
  import { toQuery } from "@hostlink/light";
9
- import { list, navigateTo } from "#imports";
10
+ import { navigateTo } from "#imports";
10
11
  import { useI18n } from "vue-i18n";
11
12
  import { useStorage, useSessionStorage } from "@vueuse/core";
12
13
  import { useRoute } from "#imports";
@@ -98,6 +99,7 @@ const props = defineProps({
98
99
  "onUpdate:selected": { type: Function, required: false },
99
100
  "onUpdate:expanded": { type: Function, required: false },
100
101
  onVirtualScroll: { type: Function, required: false },
102
+ client: { type: String, required: false, default: "auth" },
101
103
  actions: { type: Array, required: false, default: () => [] },
102
104
  sortBy: { type: String, required: false },
103
105
  modelName: { type: null, required: false },
@@ -138,7 +140,7 @@ if (!saveFilters.value) {
138
140
  defineOptions({ inheritAttrs: false });
139
141
  const light = useLight();
140
142
  const vAttrs = useAttrs();
141
- const L_KEYS = ["actions", "sortBy", "modelName", "searchable", "onRequestData", "addComponent", "addComponentProps", "name", "searchStyle", "canExpandRow"];
143
+ const L_KEYS = ["client", "actions", "sortBy", "modelName", "searchable", "onRequestData", "addComponent", "addComponentProps", "name", "searchStyle", "canExpandRow"];
142
144
  const base = useLightTableDefaults(props, vAttrs, L_KEYS);
143
145
  const pagination = ref(props.pagination);
144
146
  if (props.rowsPerPageOptions[0] == 0) {
@@ -342,7 +344,7 @@ const onLocalRequest = async (p) => {
342
344
  }
343
345
  loading.value = true;
344
346
  try {
345
- let l = list(model2, localFields);
347
+ let l = useLightClient(props.client).list(model2, localFields);
346
348
  l = l.filters(localFilters);
347
349
  if (sort) {
348
350
  l = l.sort(sort);
@@ -431,7 +433,7 @@ const ss = computed(() => Object.keys(slots));
431
433
  const onDelete = async (id) => {
432
434
  if (modelName.value == null) return;
433
435
  try {
434
- await model(modelName.value).delete(id);
436
+ await model(modelName.value, props.client).delete(id);
435
437
  } catch (e) {
436
438
  $q.notify({
437
439
  message: e.message,
@@ -27,6 +27,7 @@ export type LTableColumn = QTableColumn & {
27
27
  autoWidth?: boolean;
28
28
  };
29
29
  export type LTableProps = QTableProps & {
30
+ client?: string;
30
31
  columns?: Array<LTableColumn>;
31
32
  actions?: Array<'view' | 'edit' | 'delete' | 'update'>;
32
33
  sortBy?: string;
@@ -127,6 +128,7 @@ declare const __VLS_base: import("vue").DefineComponent<LTableProps, {
127
128
  rowsPerPageLabel: string;
128
129
  rowsPerPageOptions: readonly any[];
129
130
  selection: "none" | "single" | "multiple";
131
+ client: string;
130
132
  searchable: boolean;
131
133
  canExpandRow: (row: any) => boolean;
132
134
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -1,2 +1,2 @@
1
- declare const _default: (name: string, fields: Object) => any;
1
+ declare const _default: (name: string, fields: Object, client?: string) => any;
2
2
  export default _default;
@@ -1,5 +1,4 @@
1
- import { getApiClient } from "@hostlink/light";
2
- export default (name, fields) => {
3
- const client = getApiClient();
4
- return client.collect(name, fields);
1
+ import useLightClient from "./useLightClient.js";
2
+ export default (name, fields, client = "auth") => {
3
+ return useLightClient(client).collect(name, fields);
5
4
  };
@@ -1,3 +1,3 @@
1
1
  export default function (operation: string, args?: {
2
2
  [key: string]: any;
3
- }, fields?: any): Promise<any>;
3
+ }, fields?: any, client?: string): Promise<any>;
@@ -1,4 +1,4 @@
1
- import { mutation } from "@hostlink/light";
1
+ import useLightClient from "./useLightClient.js";
2
2
  const removeUndefinedValues = (obj) => {
3
3
  for (const key in obj) {
4
4
  if (obj[key] instanceof File) {
@@ -13,7 +13,7 @@ const removeUndefinedValues = (obj) => {
13
13
  }
14
14
  return obj;
15
15
  };
16
- export default function(operation, args, fields = []) {
16
+ export default function(operation, args, fields = [], client = "auth") {
17
17
  if (args) {
18
18
  args = removeUndefinedValues(args);
19
19
  }
@@ -29,7 +29,7 @@ export default function(operation, args, fields = []) {
29
29
  if (Object.keys(q[operation]).length === 0) {
30
30
  q[operation] = true;
31
31
  }
32
- return mutation(q).then((res) => {
32
+ return useLightClient(client).mutation(q).then((res) => {
33
33
  return res[operation];
34
34
  });
35
35
  }
@@ -1,5 +1,5 @@
1
1
  import type { LTableColumn } from "../components/L/Table.vue.js";
2
- declare const _default: (name: string) => Omit<{
2
+ declare const _default: (name: string, client?: string) => Omit<{
3
3
  field: (f: string) => import("@hostlink/light").Field | null;
4
4
  $fields: Record<string, import("@hostlink/light").Field>;
5
5
  setDataPath(path: string): string;
@@ -1,7 +1,7 @@
1
- import { getModel } from "@hostlink/light";
1
+ import useLightClient from "./useLightClient.js";
2
2
  import defu from "defu";
3
- export default (name) => {
4
- const m = getModel(name);
3
+ export default (name, client = "auth") => {
4
+ const m = useLightClient(client).model(name);
5
5
  return defu(m, {
6
6
  columns(fields) {
7
7
  let columns = [];
@@ -0,0 +1,2 @@
1
+ import type { GraphQLQuery } from '@hostlink/light';
2
+ export default function q(query: GraphQLQuery, client?: string): Promise<any>;
@@ -0,0 +1,4 @@
1
+ import useLightClient from "./useLightClient.js";
2
+ export default function q(query, client = "auth") {
3
+ return useLightClient(client).query(query);
4
+ }
@@ -0,0 +1,4 @@
1
+ import type { LightClient } from '@hostlink/light';
2
+ export declare function registerLightClient(name: string, client: LightClient): void;
3
+ export declare function clearLightClients(): void;
4
+ export default function useLightClient(name?: string): LightClient;
@@ -0,0 +1,12 @@
1
+ const clients = /* @__PURE__ */ new Map();
2
+ export function registerLightClient(name, client) {
3
+ clients.set(name, client);
4
+ }
5
+ export function clearLightClients() {
6
+ clients.clear();
7
+ }
8
+ export default function useLightClient(name = "auth") {
9
+ const client = clients.get(name);
10
+ if (!client) throw new Error(`Light client "${name}" is not configured`);
11
+ return client;
12
+ }
@@ -12,10 +12,22 @@ import { createLightPlugin } from "./formkit/index.js";
12
12
  import { plugin, defaultConfig } from "@formkit/vue";
13
13
  import getApiBase from "./composables/getApiBase.js";
14
14
  import useLight from "./composables/useLight.js";
15
+ import useLightClient, { clearLightClients, registerLightClient } from "./composables/useLightClient.js";
15
16
  import { zhTW } from "@formkit/i18n";
16
17
  export default defineNuxtPlugin((nuxtApp) => {
17
- const client = createClient(getApiBase());
18
- setApiClient(client);
18
+ const runtimeConfig = useRuntimeConfig();
19
+ const lightConfig = runtimeConfig.public.light;
20
+ const configuredClients = lightConfig?.clients ?? {};
21
+ clearLightClients();
22
+ for (const [name, config] of Object.entries(configuredClients)) {
23
+ const baseURL = typeof config === "string" ? config : config.baseURL;
24
+ if (!baseURL) throw new Error(`Light client "${name}" requires a baseURL`);
25
+ registerLightClient(name, createClient(baseURL));
26
+ }
27
+ if (!configuredClients.auth) {
28
+ registerLightClient("auth", createClient(getApiBase()));
29
+ }
30
+ setApiClient(useLightClient());
19
31
  defineModel("Permission", {}).setDataPath("app.listPermission");
20
32
  defineModel("SystemValue", {}).setDataPath("app.listSystemValue");
21
33
  defineModel("Config", {}).setDataPath("app.listConfig");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hostlink/nuxt-light",
3
- "version": "1.75.0",
3
+ "version": "1.76.0",
4
4
  "description": "HostLink Nuxt Light Framework",
5
5
  "repository": {
6
6
  "type": "git",
@@ -38,7 +38,7 @@
38
38
  "@formkit/inputs": "^2.1.2",
39
39
  "@formkit/validation": "^2.1.2",
40
40
  "@formkit/vue": "^2.1.2",
41
- "@hostlink/light": "^3.2.7",
41
+ "@hostlink/light": "^3.3.1",
42
42
  "@nuxt/module-builder": "^1.0.1",
43
43
  "@quasar/extras": "^2.0.2",
44
44
  "@quasar/quasar-ui-qmarkdown": "^3.0.1",