@jskit-ai/users-web 0.1.106 → 0.1.107

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.
@@ -3,7 +3,7 @@ import { HOME_COG_OUTLET } from "./src/shared/toolsOutletContracts.js";
3
3
  export default Object.freeze({
4
4
  packageVersion: 1,
5
5
  packageId: "@jskit-ai/users-web",
6
- version: "0.1.106",
6
+ version: "0.1.107",
7
7
  kind: "runtime",
8
8
  description: "Users web module: account/profile UI plus shared users web widgets.",
9
9
  dependsOn: [
@@ -278,12 +278,12 @@ export default Object.freeze({
278
278
  dependencies: {
279
279
  runtime: {
280
280
  "@mdi/js": "^7.4.47",
281
- "@jskit-ai/http-runtime": "0.1.90",
282
- "@jskit-ai/realtime": "0.1.90",
283
- "@jskit-ai/kernel": "0.1.91",
284
- "@jskit-ai/shell-web": "0.1.90",
285
- "@jskit-ai/uploads-image-web": "0.1.69",
286
- "@jskit-ai/users-core": "0.1.101"
281
+ "@jskit-ai/http-runtime": "0.1.91",
282
+ "@jskit-ai/realtime": "0.1.91",
283
+ "@jskit-ai/kernel": "0.1.92",
284
+ "@jskit-ai/shell-web": "0.1.91",
285
+ "@jskit-ai/uploads-image-web": "0.1.70",
286
+ "@jskit-ai/users-core": "0.1.102"
287
287
  },
288
288
  dev: {}
289
289
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/users-web",
3
- "version": "0.1.106",
3
+ "version": "0.1.107",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "node --test"
@@ -44,12 +44,12 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@mdi/js": "^7.4.47",
47
- "@jskit-ai/http-runtime": "0.1.90",
48
- "@jskit-ai/kernel": "0.1.91",
49
- "@jskit-ai/realtime": "0.1.90",
50
- "@jskit-ai/shell-web": "0.1.90",
51
- "@jskit-ai/uploads-image-web": "0.1.69",
52
- "@jskit-ai/users-core": "0.1.101"
47
+ "@jskit-ai/http-runtime": "0.1.91",
48
+ "@jskit-ai/kernel": "0.1.92",
49
+ "@jskit-ai/realtime": "0.1.91",
50
+ "@jskit-ai/shell-web": "0.1.91",
51
+ "@jskit-ai/uploads-image-web": "0.1.70",
52
+ "@jskit-ai/users-core": "0.1.102"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "@tanstack/vue-query": "^5.90.5",
@@ -29,6 +29,7 @@ function useAddEdit({
29
29
  readMethod = "GET",
30
30
  readEnabled = true,
31
31
  writeMethod = "PATCH",
32
+ client = null,
32
33
  transport = null,
33
34
  requestRecovery = null,
34
35
  requestRecoveryLabel = "Resource",
@@ -119,6 +120,7 @@ function useAddEdit({
119
120
  queryKey: requestQueryRuntime.queryKey,
120
121
  path: operationScope.apiPath,
121
122
  enabled: queryCanRun,
123
+ client,
122
124
  readMethod,
123
125
  writeMethod,
124
126
  readQuery: requestQueryRuntime.requestQuery,
@@ -43,6 +43,7 @@ function useList({
43
43
  initialPageParam = null,
44
44
  getNextPageParam,
45
45
  selectItems,
46
+ client = null,
46
47
  transport = null,
47
48
  requestOptions,
48
49
  queryOptions,
@@ -224,6 +225,7 @@ function useList({
224
225
  queryKey: listQueryKey,
225
226
  path: listPath,
226
227
  enabled: operationScope.queryCanRun(canView),
228
+ client,
227
229
  transport,
228
230
  initialPageParam,
229
231
  getNextPageParam,
@@ -20,6 +20,7 @@ function useView({
20
20
  viewPermissions = [],
21
21
  readMethod = "GET",
22
22
  readEnabled = true,
23
+ client = null,
23
24
  transport = null,
24
25
  requestRecovery = null,
25
26
  requestRecoveryLabel = "Resource",
@@ -103,6 +104,7 @@ function useView({
103
104
  queryKey: requestQueryRuntime.queryKey,
104
105
  path: operationScope.apiPath,
105
106
  enabled: operationScope.queryCanRun(canView),
107
+ client,
106
108
  readMethod,
107
109
  readQuery: requestQueryRuntime.requestQuery,
108
110
  transport,
@@ -1,6 +1,6 @@
1
1
  import { computed, unref } from "vue";
2
2
  import { useMutation, useQuery } from "@tanstack/vue-query";
3
- import { usersWebHttpClient } from "../../lib/httpClient.js";
3
+ import { getUsersWebHttpClient } from "../../lib/httpClient.js";
4
4
  import { asPlainObject } from "../support/scopeHelpers.js";
5
5
  import { resolveEnabledRef, resolveTextRef } from "../support/refValueHelpers.js";
6
6
  import { toQueryErrorMessage } from "../support/errorMessageHelpers.js";
@@ -67,7 +67,7 @@ function useEndpointResource({
67
67
  queryKey,
68
68
  path = "",
69
69
  enabled = true,
70
- client = usersWebHttpClient,
70
+ client = null,
71
71
  readMethod = "GET",
72
72
  writeMethod = "PATCH",
73
73
  readQuery = null,
@@ -81,7 +81,8 @@ function useEndpointResource({
81
81
  fallbackLoadError = "Unable to load resource.",
82
82
  fallbackSaveError = "Unable to save resource."
83
83
  } = {}) {
84
- if (!client || typeof client.request !== "function") {
84
+ const activeClient = client || getUsersWebHttpClient();
85
+ if (!activeClient || typeof activeClient.request !== "function") {
85
86
  throw new TypeError("useEndpointResource requires a client with request().");
86
87
  }
87
88
 
@@ -96,7 +97,7 @@ function useEndpointResource({
96
97
  throw new Error("Resource path is required.");
97
98
  }
98
99
 
99
- return client.request(requestPath, {
100
+ return activeClient.request(requestPath, {
100
101
  ...buildEndpointReadRequestOptions({
101
102
  method: readMethod,
102
103
  query: readQuery,
@@ -137,7 +138,7 @@ function useEndpointResource({
137
138
  const method = String(options.method || writeMethod || "PATCH").toUpperCase();
138
139
  const hasBody = Object.hasOwn(options, "body");
139
140
  const body = hasBody ? options.body : options.payload;
140
- return client.request(
141
+ return activeClient.request(
141
142
  requestPath,
142
143
  buildEndpointWriteRequestOptions({
143
144
  method,
@@ -1,5 +1,5 @@
1
1
  import { computed, unref } from "vue";
2
- import { usersWebHttpClient } from "../../lib/httpClient.js";
2
+ import { getUsersWebHttpClient } from "../../lib/httpClient.js";
3
3
  import { asPlainObject } from "../support/scopeHelpers.js";
4
4
  import { resolveEnabledRef, resolveTextRef } from "../support/refValueHelpers.js";
5
5
  import { usePagedCollection } from "../usePagedCollection.js";
@@ -56,7 +56,7 @@ function useListCore({
56
56
  queryKey,
57
57
  path = "",
58
58
  enabled = true,
59
- client = usersWebHttpClient,
59
+ client = null,
60
60
  transport = null,
61
61
  initialPageParam = null,
62
62
  getNextPageParam,
@@ -67,7 +67,8 @@ function useListCore({
67
67
  requestRecoveryLabel = "List",
68
68
  fallbackLoadError = "Unable to load list."
69
69
  } = {}) {
70
- if (!client || typeof client.request !== "function") {
70
+ const activeClient = client || getUsersWebHttpClient();
71
+ if (!activeClient || typeof activeClient.request !== "function") {
71
72
  throw new TypeError("useListCore requires a client with request().");
72
73
  }
73
74
 
@@ -84,7 +85,7 @@ function useListCore({
84
85
  throw new Error("List path is required.");
85
86
  }
86
87
 
87
- return client.request(
88
+ return activeClient.request(
88
89
  requestPath,
89
90
  buildListRequestOptions({
90
91
  requestOptions,
@@ -17,6 +17,7 @@ function useCommand({
17
17
  apiSuffix = "",
18
18
  runPermissions = [],
19
19
  writeMethod = "POST",
20
+ client = null,
20
21
  transport = null,
21
22
  placementSource = "users-web.command",
22
23
  fallbackRunError = "Unable to complete action.",
@@ -52,6 +53,7 @@ function useCommand({
52
53
  const resource = useEndpointResource({
53
54
  path: operationScope.apiPath,
54
55
  enabled: false,
56
+ client,
55
57
  writeMethod,
56
58
  transport,
57
59
  fallbackSaveError: fallbackRunError
@@ -1,10 +1,47 @@
1
1
  import { createTransientRetryHttpClient } from "@jskit-ai/http-runtime/client";
2
2
 
3
- const usersWebHttpClient = createTransientRetryHttpClient({
4
- credentials: "include",
5
- csrf: {
6
- sessionPath: "/api/session"
7
- }
8
- });
9
-
10
- export { usersWebHttpClient };
3
+ function normalizeOptions(value = null) {
4
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
5
+ }
6
+
7
+ function createUsersWebHttpClient(options = {}) {
8
+ const source = normalizeOptions(options);
9
+ const sourceCsrf = normalizeOptions(source.csrf);
10
+
11
+ return createTransientRetryHttpClient({
12
+ ...source,
13
+ credentials: source.credentials ?? "include",
14
+ csrf: {
15
+ sessionPath: "/api/session",
16
+ ...sourceCsrf
17
+ }
18
+ });
19
+ }
20
+
21
+ let usersWebHttpClient = createUsersWebHttpClient();
22
+
23
+ function configureUsersWebHttpClient(optionsOrClient = {}) {
24
+ const source = normalizeOptions(optionsOrClient);
25
+ usersWebHttpClient =
26
+ typeof source.request === "function"
27
+ ? source
28
+ : createUsersWebHttpClient(source);
29
+ return usersWebHttpClient;
30
+ }
31
+
32
+ function getUsersWebHttpClient() {
33
+ return usersWebHttpClient;
34
+ }
35
+
36
+ function resetUsersWebHttpClientForTests() {
37
+ usersWebHttpClient = createUsersWebHttpClient();
38
+ return usersWebHttpClient;
39
+ }
40
+
41
+ export {
42
+ configureUsersWebHttpClient,
43
+ createUsersWebHttpClient,
44
+ getUsersWebHttpClient,
45
+ resetUsersWebHttpClientForTests,
46
+ usersWebHttpClient
47
+ };
@@ -9,6 +9,11 @@ import {
9
9
  buildEndpointWriteRequestOptions,
10
10
  useEndpointResource
11
11
  } from "../src/client/composables/runtime/useEndpointResource.js";
12
+ import { useCommand } from "../src/client/composables/useCommand.js";
13
+ import {
14
+ configureUsersWebHttpClient,
15
+ resetUsersWebHttpClientForTests
16
+ } from "../src/client/lib/httpClient.js";
12
17
  import { buildListRequestOptions } from "../src/client/composables/runtime/useListCore.js";
13
18
  import {
14
19
  resolveOperationRealtimeOptions
@@ -287,3 +292,114 @@ test("endpoint resource reads attach request recovery metadata to query options"
287
292
  requestRecoveryMethod: "GET"
288
293
  });
289
294
  });
295
+
296
+ test("endpoint resources use the configured users-web HTTP client by default", async () => {
297
+ const queryClient = new QueryClient();
298
+ const calls = [];
299
+ let resource = null;
300
+ configureUsersWebHttpClient({
301
+ csrf: {
302
+ enabled: false
303
+ },
304
+ resolveRequestUrl(url) {
305
+ return url.replace(/^\/api\//u, "/api/app/beepollen/");
306
+ },
307
+ fetchImpl: async (url, options) => {
308
+ calls.push([url, options]);
309
+ return {
310
+ ok: true,
311
+ status: 200,
312
+ headers: {
313
+ get(name) {
314
+ return String(name || "").toLowerCase() === "content-type"
315
+ ? "application/json; charset=utf-8"
316
+ : "";
317
+ }
318
+ },
319
+ async json() {
320
+ return {
321
+ ok: true
322
+ };
323
+ }
324
+ };
325
+ }
326
+ });
327
+
328
+ try {
329
+ const app = createSSRApp({
330
+ setup() {
331
+ resource = useEndpointResource({
332
+ queryKey: ["vibe64-sessions"],
333
+ path: "/api/vibe64/sessions"
334
+ });
335
+ return () => h("div");
336
+ }
337
+ });
338
+ app.use(VueQueryPlugin, {
339
+ queryClient
340
+ });
341
+ await renderToString(app);
342
+
343
+ await resource.reload();
344
+
345
+ assert.equal(calls.at(-1)?.[0], "/api/app/beepollen/vibe64/sessions");
346
+ } finally {
347
+ resetUsersWebHttpClientForTests();
348
+ }
349
+ });
350
+
351
+ test("commands use the configured users-web HTTP client by default", async () => {
352
+ const queryClient = new QueryClient();
353
+ const calls = [];
354
+ let command = null;
355
+ configureUsersWebHttpClient({
356
+ csrf: {
357
+ enabled: false
358
+ },
359
+ resolveRequestUrl(url) {
360
+ return url.replace(/^\/api\//u, "/api/app/beepollen/");
361
+ },
362
+ fetchImpl: async (url, options) => {
363
+ calls.push([url, options]);
364
+ return {
365
+ ok: true,
366
+ status: 200,
367
+ headers: {
368
+ get(name) {
369
+ return String(name || "").toLowerCase() === "content-type"
370
+ ? "application/json; charset=utf-8"
371
+ : "";
372
+ }
373
+ },
374
+ async json() {
375
+ return {
376
+ ok: true
377
+ };
378
+ }
379
+ };
380
+ }
381
+ });
382
+
383
+ try {
384
+ const app = createSSRApp({
385
+ setup() {
386
+ command = useCommand({
387
+ access: "always",
388
+ apiSuffix: "/vibe64/sessions"
389
+ });
390
+ return () => h("div");
391
+ }
392
+ });
393
+ app.use(VueQueryPlugin, {
394
+ queryClient
395
+ });
396
+ await renderToString(app);
397
+
398
+ await command.run();
399
+
400
+ assert.equal(calls.at(-1)?.[0], "/api/app/beepollen/vibe64/sessions");
401
+ assert.equal(calls.at(-1)?.[1]?.method, "POST");
402
+ } finally {
403
+ resetUsersWebHttpClientForTests();
404
+ }
405
+ });