@jskit-ai/users-web 0.1.172 → 0.1.174

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 (112) hide show
  1. package/package.json +18 -149
  2. package/src/client/composables/account-settings/accountSettingsAvatarUploadRuntime.js +2 -2
  3. package/src/client/composables/useAccountSettingsRuntime.js +3 -3
  4. package/src/client/index.js +0 -11
  5. package/test/exportsContract.test.js +3 -29
  6. package/test/settingsPlacementContract.test.js +10 -0
  7. package/fixtures/crud-list-date-filters/App.vue +0 -107
  8. package/fixtures/crud-list-date-filters/index.html +0 -12
  9. package/fixtures/crud-list-date-filters/main.js +0 -24
  10. package/fixtures/crud-list-date-filters/vite.config.mjs +0 -18
  11. package/src/client/bulkActions.js +0 -47
  12. package/src/client/components/CrudAddEditScreen.vue +0 -186
  13. package/src/client/components/CrudDeleteAction.vue +0 -93
  14. package/src/client/components/CrudListBulkActionSurface.vue +0 -126
  15. package/src/client/components/CrudListDateFilterControl.vue +0 -188
  16. package/src/client/components/CrudListFilterSurface.vue +0 -388
  17. package/src/client/components/CrudListRecordActionMenu.vue +0 -120
  18. package/src/client/components/CrudListScreen.vue +0 -501
  19. package/src/client/components/CrudViewScreen.vue +0 -197
  20. package/src/client/composables/crud/crudBindingSupport.js +0 -75
  21. package/src/client/composables/crud/crudHttpClientSupport.js +0 -57
  22. package/src/client/composables/crud/crudJsonApiTransportSupport.js +0 -145
  23. package/src/client/composables/crud/crudLookupFieldLabelSupport.js +0 -151
  24. package/src/client/composables/crud/crudLookupFieldRuntime.js +0 -251
  25. package/src/client/composables/crud/crudSchemaFormHelpers.js +0 -464
  26. package/src/client/composables/internal/crudListFilterLookupSupport.js +0 -161
  27. package/src/client/composables/internal/crudListParentTitleSupport.js +0 -171
  28. package/src/client/composables/internal/useOperationScope.js +0 -144
  29. package/src/client/composables/records/useAddEdit.js +0 -224
  30. package/src/client/composables/records/useCrudAddEdit.js +0 -227
  31. package/src/client/composables/records/useCrudList.js +0 -101
  32. package/src/client/composables/records/useCrudView.js +0 -47
  33. package/src/client/composables/records/useList.js +0 -500
  34. package/src/client/composables/records/useView.js +0 -164
  35. package/src/client/composables/runtime/addEditUiRuntime.js +0 -130
  36. package/src/client/composables/runtime/listUiRuntime.js +0 -123
  37. package/src/client/composables/runtime/modelStateHelpers.js +0 -90
  38. package/src/client/composables/runtime/operationAdapters.js +0 -34
  39. package/src/client/composables/runtime/operationUiHelpers.js +0 -125
  40. package/src/client/composables/runtime/operationValidationHelpers.js +0 -51
  41. package/src/client/composables/runtime/useAddEditCore.js +0 -112
  42. package/src/client/composables/runtime/useCommandCore.js +0 -123
  43. package/src/client/composables/runtime/useEndpointResource.js +0 -199
  44. package/src/client/composables/runtime/useFieldErrorBag.js +0 -61
  45. package/src/client/composables/runtime/useListCore.js +0 -112
  46. package/src/client/composables/runtime/useUiFeedback.js +0 -98
  47. package/src/client/composables/runtime/useViewCore.js +0 -93
  48. package/src/client/composables/runtime/viewUiRuntime.js +0 -96
  49. package/src/client/composables/support/errorMessageHelpers.js +0 -66
  50. package/src/client/composables/support/listQueryParamSupport.js +0 -473
  51. package/src/client/composables/support/listSearchSupport.js +0 -70
  52. package/src/client/composables/support/refValueHelpers.js +0 -19
  53. package/src/client/composables/support/requestQueryRuntimeSupport.js +0 -141
  54. package/src/client/composables/support/resourceLoadStateHelpers.js +0 -208
  55. package/src/client/composables/support/routeTemplateHelpers.js +0 -285
  56. package/src/client/composables/support/scopeHelpers.js +0 -145
  57. package/src/client/composables/useAccess.js +0 -109
  58. package/src/client/composables/useCommand.js +0 -118
  59. package/src/client/composables/useCrudAddEditScreen.js +0 -88
  60. package/src/client/composables/useCrudDeleteAction.js +0 -160
  61. package/src/client/composables/useCrudListBulkActions.js +0 -147
  62. package/src/client/composables/useCrudListFilterLookups.js +0 -146
  63. package/src/client/composables/useCrudListFilters.js +0 -339
  64. package/src/client/composables/useCrudListParentTitle.js +0 -151
  65. package/src/client/composables/useCrudListRowActions.js +0 -144
  66. package/src/client/composables/useCrudListScreen.js +0 -237
  67. package/src/client/composables/useCrudViewScreen.js +0 -77
  68. package/src/client/composables/usePagedCollection.js +0 -181
  69. package/src/client/composables/useRealtimeQueryInvalidation.js +0 -156
  70. package/src/client/composables/useScopeRuntime.js +0 -135
  71. package/src/client/filters.js +0 -15
  72. package/src/client/lib/httpClient.js +0 -47
  73. package/src/client/lib/permissions.js +0 -34
  74. package/src/client/rowActions.js +0 -47
  75. package/src/client/support/contractGuards.js +0 -34
  76. package/src/client/support/crudListDateFilterSupport.js +0 -91
  77. package/test/addEditUiRuntime.test.js +0 -110
  78. package/test/crudBindingSupport.test.js +0 -110
  79. package/test/crudHttpClientSupport.test.js +0 -77
  80. package/test/crudJsonApiTransportSupport.test.js +0 -179
  81. package/test/crudListBulkActionSurface.test.js +0 -27
  82. package/test/crudListDateFilterSupport.test.js +0 -92
  83. package/test/crudListDateFilterSurface.browser.test.js +0 -182
  84. package/test/crudListFilterSurface.test.js +0 -90
  85. package/test/crudLookupFieldRuntime.test.js +0 -264
  86. package/test/crudScreenComponents.test.js +0 -117
  87. package/test/errorIntentContract.test.js +0 -31
  88. package/test/errorMessageHelpers.test.js +0 -28
  89. package/test/listQueryParamSupport.test.js +0 -223
  90. package/test/listUiRuntime.test.js +0 -102
  91. package/test/operationValidationHelpers.test.js +0 -64
  92. package/test/permissions.test.js +0 -35
  93. package/test/refValueHelpers.test.js +0 -14
  94. package/test/requestTransportOptions.test.js +0 -457
  95. package/test/resourceLoadStateHelpers.test.js +0 -189
  96. package/test/routeTemplateHelpers.test.js +0 -85
  97. package/test/scopeHelpers.test.js +0 -57
  98. package/test/useAddEditCore.test.js +0 -124
  99. package/test/useAddEditRequestQueryParams.test.js +0 -190
  100. package/test/useCrudAddEdit.test.js +0 -415
  101. package/test/useCrudDeleteAction.test.js +0 -139
  102. package/test/useCrudListBulkActions.test.js +0 -65
  103. package/test/useCrudListFilterLookups.test.js +0 -114
  104. package/test/useCrudListFilters.test.js +0 -293
  105. package/test/useCrudListParentTitle.test.js +0 -262
  106. package/test/useCrudListRowActions.test.js +0 -77
  107. package/test/useListRouteInitialization.test.js +0 -337
  108. package/test/useListSearchSupport.test.js +0 -61
  109. package/test/usePagedCollection.test.js +0 -53
  110. package/test/useViewRequestQueryParams.test.js +0 -20
  111. package/test/viewCoreLoading.test.js +0 -44
  112. package/test/viewUiRuntime.test.js +0 -95
@@ -1,457 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import { QueryClient, VueQueryPlugin } from "@tanstack/vue-query";
4
- import { createSSRApp, h } from "vue";
5
- import { renderToString } from "vue/server-renderer";
6
-
7
- import {
8
- buildEndpointReadRequestOptions,
9
- buildEndpointWriteRequestOptions,
10
- useEndpointResource
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";
17
- import { buildListRequestOptions } from "../src/client/composables/runtime/useListCore.js";
18
- import {
19
- resolveOperationRealtimeOptions
20
- } from "../src/client/composables/useRealtimeQueryInvalidation.js";
21
-
22
- test("endpoint read request options include transport only when provided", () => {
23
- assert.deepEqual(
24
- buildEndpointReadRequestOptions({
25
- method: "get"
26
- }),
27
- {
28
- method: "GET"
29
- }
30
- );
31
-
32
- assert.deepEqual(
33
- buildEndpointReadRequestOptions({
34
- method: "get",
35
- transport: {
36
- kind: "jsonapi-resource",
37
- responseType: "user-settings",
38
- responseKind: "record"
39
- }
40
- }),
41
- {
42
- method: "GET",
43
- transport: {
44
- kind: "jsonapi-resource",
45
- responseType: "user-settings",
46
- responseKind: "record"
47
- }
48
- }
49
- );
50
- });
51
-
52
- test("endpoint write request options preserve body/options and append transport", () => {
53
- assert.deepEqual(
54
- buildEndpointWriteRequestOptions({
55
- method: "patch",
56
- body: {
57
- theme: "dark"
58
- },
59
- options: {
60
- headers: {
61
- "x-demo": "1"
62
- }
63
- },
64
- transport: {
65
- kind: "jsonapi-resource",
66
- requestType: "user-preferences",
67
- responseType: "user-settings",
68
- responseKind: "record"
69
- }
70
- }),
71
- {
72
- method: "PATCH",
73
- headers: {
74
- "x-demo": "1"
75
- },
76
- body: {
77
- theme: "dark"
78
- },
79
- transport: {
80
- kind: "jsonapi-resource",
81
- requestType: "user-preferences",
82
- responseType: "user-settings",
83
- responseKind: "record"
84
- }
85
- }
86
- );
87
- });
88
-
89
- test("list request options stay GET and carry transport when provided", () => {
90
- assert.deepEqual(
91
- buildListRequestOptions({
92
- requestOptions: {
93
- headers: {
94
- "x-demo": "1"
95
- }
96
- },
97
- pageParam: "cursor_2",
98
- transport: {
99
- kind: "jsonapi-resource",
100
- responseType: "contacts",
101
- responseKind: "collection"
102
- }
103
- }),
104
- {
105
- method: "GET",
106
- headers: {
107
- "x-demo": "1"
108
- },
109
- query: {
110
- limit: 20,
111
- cursor: "cursor_2"
112
- },
113
- transport: {
114
- kind: "jsonapi-resource",
115
- responseType: "contacts",
116
- responseKind: "collection"
117
- }
118
- }
119
- );
120
- });
121
-
122
- test("list request options preserve explicit limit values", () => {
123
- assert.deepEqual(
124
- buildListRequestOptions({
125
- requestOptions: {
126
- query: {
127
- limit: 50
128
- }
129
- }
130
- }),
131
- {
132
- method: "GET",
133
- query: {
134
- limit: 50
135
- }
136
- }
137
- );
138
-
139
- assert.deepEqual(
140
- buildListRequestOptions({
141
- requestOptions: {
142
- query: {
143
- "page[limit]": "75"
144
- }
145
- }
146
- }),
147
- {
148
- method: "GET",
149
- query: {
150
- "page[limit]": "75"
151
- }
152
- }
153
- );
154
- });
155
-
156
- test("operation realtime options use fallback events unless explicitly overridden", () => {
157
- const fallbackRealtime = {
158
- events: ["contacts.record.changed"]
159
- };
160
-
161
- assert.deepEqual(
162
- resolveOperationRealtimeOptions({
163
- fallbackRealtime
164
- }),
165
- {
166
- events: ["contacts.record.changed"]
167
- }
168
- );
169
-
170
- assert.deepEqual(
171
- resolveOperationRealtimeOptions({
172
- realtime: {
173
- enabled: false
174
- },
175
- fallbackRealtime
176
- }),
177
- {
178
- events: ["contacts.record.changed"],
179
- enabled: false
180
- }
181
- );
182
-
183
- assert.deepEqual(
184
- resolveOperationRealtimeOptions({
185
- realtime: {
186
- event: "contacts.custom.changed"
187
- },
188
- fallbackRealtime
189
- }),
190
- {
191
- event: "contacts.custom.changed"
192
- }
193
- );
194
-
195
- assert.equal(
196
- resolveOperationRealtimeOptions({
197
- realtime: false,
198
- fallbackRealtime
199
- }),
200
- null
201
- );
202
- });
203
-
204
- test("endpoint resources invalidate their query key from configured realtime events", async () => {
205
- const queryClient = new QueryClient();
206
- const invalidations = [];
207
- const socketHandlers = new Map();
208
- const socket = {
209
- on(eventName, handler) {
210
- socketHandlers.set(eventName, handler);
211
- },
212
- off(eventName, handler) {
213
- if (socketHandlers.get(eventName) === handler) {
214
- socketHandlers.delete(eventName);
215
- }
216
- }
217
- };
218
- queryClient.invalidateQueries = async (options = {}) => {
219
- invalidations.push(options);
220
- };
221
- const app = createSSRApp({
222
- setup() {
223
- useEndpointResource({
224
- queryKey: ["today-workout-detail", "/api/today/workouts/2026-05-06"],
225
- path: "/api/today/workouts/2026-05-06",
226
- client: {
227
- async request() {
228
- return {};
229
- }
230
- },
231
- realtime: {
232
- event: "workout_set_logs.record.changed"
233
- }
234
- });
235
- return () => h("div");
236
- }
237
- });
238
- app.use(VueQueryPlugin, {
239
- queryClient
240
- });
241
- app.provide("jskit.realtime.runtime.client.socket", socket);
242
- await renderToString(app);
243
-
244
- const handler = socketHandlers.get("workout_set_logs.record.changed");
245
- assert.equal(typeof handler, "function");
246
- handler({
247
- entityId: "42"
248
- });
249
- await new Promise((resolve) => setImmediate(resolve));
250
-
251
- assert.deepEqual(invalidations, [
252
- {
253
- queryKey: ["today-workout-detail", "/api/today/workouts/2026-05-06"]
254
- }
255
- ]);
256
- });
257
-
258
- test("endpoint resource reads attach request recovery metadata to query options", async () => {
259
- const queryClient = new QueryClient();
260
- const queryKey = ["project-access", "beepollen"];
261
- const app = createSSRApp({
262
- setup() {
263
- useEndpointResource({
264
- queryKey,
265
- path: "/api/project-access",
266
- client: {
267
- async request() {
268
- return {};
269
- }
270
- },
271
- requestRecovery: {
272
- label: "Project access",
273
- source: "project-access.panel",
274
- dedupeKey: "project-access"
275
- }
276
- });
277
- return () => h("div");
278
- }
279
- });
280
- app.use(VueQueryPlugin, {
281
- queryClient
282
- });
283
- await renderToString(app);
284
-
285
- const query = queryClient.getQueryCache().find({
286
- queryKey
287
- });
288
- assert.deepEqual(query?.meta?.jskit, {
289
- requestRecoveryLabel: "Project access",
290
- requestRecoverySource: "project-access.panel",
291
- requestRecoveryDedupeKey: "project-access",
292
- requestRecoveryMethod: "GET"
293
- });
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
- });
406
-
407
- test("commands use public CRUD resource access without a CSRF session preflight", async () => {
408
- const queryClient = new QueryClient();
409
- const calls = [];
410
- let command = null;
411
- configureUsersWebHttpClient({
412
- fetchImpl: async (url, options) => {
413
- calls.push([url, options]);
414
- return {
415
- ok: true,
416
- status: 204,
417
- headers: {
418
- get() {
419
- return "";
420
- }
421
- },
422
- async json() {
423
- return {};
424
- }
425
- };
426
- }
427
- });
428
-
429
- try {
430
- const app = createSSRApp({
431
- setup() {
432
- command = useCommand({
433
- access: "always",
434
- apiSuffix: "/books/1",
435
- writeMethod: "DELETE",
436
- resource: {
437
- apiAccess: "public"
438
- }
439
- });
440
- return () => h("div");
441
- }
442
- });
443
- app.use(VueQueryPlugin, {
444
- queryClient
445
- });
446
- await renderToString(app);
447
-
448
- await command.run();
449
-
450
- assert.equal(calls.length, 1);
451
- assert.equal(calls[0][0], "/api/books/1");
452
- assert.equal(calls[0][1].method, "DELETE");
453
- assert.equal(Object.hasOwn(calls[0][1], "csrf"), false);
454
- } finally {
455
- resetUsersWebHttpClientForTests();
456
- }
457
- });
@@ -1,189 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import { ref } from "vue";
4
- import {
5
- buildRequestRecoveryMeta,
6
- hasResolvedQueryData,
7
- mergeQueryMeta,
8
- mergeRequestRecoveryQueryMeta
9
- } from "../src/client/composables/support/resourceLoadStateHelpers.js";
10
-
11
- test("hasResolvedQueryData returns true when the query succeeded", () => {
12
- const query = {
13
- isSuccess: ref(true)
14
- };
15
-
16
- assert.equal(hasResolvedQueryData({
17
- query,
18
- data: ref(null)
19
- }), true);
20
- });
21
-
22
- test("hasResolvedQueryData returns true when data payload is available", () => {
23
- const query = {
24
- isSuccess: ref(false)
25
- };
26
-
27
- assert.equal(hasResolvedQueryData({
28
- query,
29
- data: ref({
30
- id: 2971
31
- })
32
- }), true);
33
- });
34
-
35
- test("hasResolvedQueryData returns false when query and payload are unresolved", () => {
36
- const query = {
37
- isSuccess: ref(false)
38
- };
39
-
40
- assert.equal(hasResolvedQueryData({
41
- query,
42
- data: ref(null)
43
- }), false);
44
- });
45
-
46
- test("mergeQueryMeta preserves caller metadata while adding JSKIT refresh policy", () => {
47
- assert.deepEqual(
48
- mergeQueryMeta(
49
- {
50
- staleTime: 1000,
51
- meta: {
52
- owner: "contacts",
53
- jskit: {
54
- feature: "list"
55
- }
56
- }
57
- },
58
- {
59
- jskit: {
60
- refreshOnPull: true
61
- }
62
- }
63
- ),
64
- {
65
- staleTime: 1000,
66
- meta: {
67
- owner: "contacts",
68
- jskit: {
69
- feature: "list",
70
- refreshOnPull: true
71
- }
72
- }
73
- }
74
- );
75
- });
76
-
77
- test("request recovery query metadata supports labels and disabling recovery", () => {
78
- assert.deepEqual(
79
- buildRequestRecoveryMeta("Project access"),
80
- {
81
- jskit: {
82
- requestRecoveryLabel: "Project access"
83
- }
84
- }
85
- );
86
-
87
- assert.deepEqual(
88
- buildRequestRecoveryMeta(false),
89
- {
90
- jskit: {
91
- requestRecovery: false
92
- }
93
- }
94
- );
95
- });
96
-
97
- test("mergeRequestRecoveryQueryMeta preserves caller metadata while adding recovery hints", () => {
98
- assert.deepEqual(
99
- mergeRequestRecoveryQueryMeta(
100
- {
101
- staleTime: 5000,
102
- meta: {
103
- owner: "project-access",
104
- jskit: {
105
- refreshOnPull: true
106
- }
107
- }
108
- },
109
- {
110
- label: "Project access",
111
- source: "app.project-access",
112
- dedupeKey: "project-access",
113
- method: "get",
114
- dedupeWindowMs: 100
115
- }
116
- ),
117
- {
118
- staleTime: 5000,
119
- meta: {
120
- owner: "project-access",
121
- jskit: {
122
- refreshOnPull: true,
123
- requestRecoveryLabel: "Project access",
124
- requestRecoverySource: "app.project-access",
125
- requestRecoveryDedupeKey: "project-access",
126
- requestRecoveryMethod: "GET",
127
- requestRecoveryDedupeWindowMs: 100
128
- }
129
- }
130
- }
131
- );
132
- });
133
-
134
- test("mergeRequestRecoveryQueryMeta does not overwrite explicit query recovery labels with defaults", () => {
135
- assert.deepEqual(
136
- mergeRequestRecoveryQueryMeta(
137
- {
138
- meta: {
139
- jskit: {
140
- requestRecoveryLabel: "Explicit label",
141
- requestRecoveryMethod: "HEAD",
142
- requestRecoveryDedupeWindowMs: 0
143
- }
144
- }
145
- },
146
- null,
147
- {
148
- label: "Default label",
149
- method: "GET",
150
- dedupeWindowMs: 5000
151
- }
152
- ),
153
- {
154
- meta: {
155
- jskit: {
156
- requestRecoveryLabel: "Explicit label",
157
- requestRecoveryMethod: "HEAD",
158
- requestRecoveryDedupeWindowMs: 0
159
- }
160
- }
161
- }
162
- );
163
- });
164
-
165
- test("mergeRequestRecoveryQueryMeta preserves disabled recovery metadata", () => {
166
- assert.deepEqual(
167
- mergeRequestRecoveryQueryMeta(
168
- {
169
- meta: {
170
- jskit: {
171
- requestRecovery: false
172
- }
173
- }
174
- },
175
- null,
176
- {
177
- label: "Default label",
178
- method: "GET"
179
- }
180
- ),
181
- {
182
- meta: {
183
- jskit: {
184
- requestRecovery: false
185
- }
186
- }
187
- }
188
- );
189
- });
@@ -1,85 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import {
4
- extractRouteParamNames,
5
- resolveScopedRoutePathname,
6
- resolveRouteParamNamesInOrder
7
- } from "../src/client/composables/support/routeTemplateHelpers.js";
8
-
9
- test("extractRouteParamNames reads dynamic params from route templates", () => {
10
- assert.deepEqual(
11
- extractRouteParamNames("/w/:workspaceSlug/admin/contacts/:contactId/addresses/:addressId"),
12
- ["workspaceSlug", "contactId", "addressId"]
13
- );
14
- });
15
-
16
- test("resolveRouteParamNamesInOrder prefers matched route templates", () => {
17
- const route = {
18
- matched: [
19
- { path: "/w/:workspaceSlug/admin" },
20
- { path: "/contacts/:contactId/addresses/:addressId" }
21
- ],
22
- params: {
23
- workspaceSlug: "acme",
24
- contactId: "7",
25
- addressId: "42"
26
- }
27
- };
28
-
29
- assert.deepEqual(resolveRouteParamNamesInOrder(route), ["workspaceSlug", "contactId", "addressId"]);
30
- });
31
-
32
- test("resolveScopedRoutePathname supports at/before/after anchors", () => {
33
- const currentPathname = "/w/dogandgroom/admin/contacts/541841/pets/715528/edit/advanced";
34
- const params = {
35
- workspaceSlug: "dogandgroom",
36
- contactId: "541841",
37
- petId: "715528"
38
- };
39
- const orderedParamNames = ["workspaceSlug", "contactId", "petId"];
40
-
41
- assert.equal(
42
- resolveScopedRoutePathname({
43
- currentPathname,
44
- params,
45
- orderedParamNames,
46
- anchorParamName: "contactId",
47
- anchorMode: "at"
48
- }),
49
- "/w/dogandgroom/admin/contacts/541841"
50
- );
51
- assert.equal(
52
- resolveScopedRoutePathname({
53
- currentPathname,
54
- params,
55
- orderedParamNames,
56
- anchorParamName: "petId",
57
- anchorMode: "before"
58
- }),
59
- "/w/dogandgroom/admin/contacts/541841/pets"
60
- );
61
- assert.equal(
62
- resolveScopedRoutePathname({
63
- currentPathname,
64
- params,
65
- orderedParamNames,
66
- anchorParamName: "petId",
67
- anchorMode: "after"
68
- }),
69
- "/w/dogandgroom/admin/contacts/541841/pets/715528/edit"
70
- );
71
- });
72
-
73
- test("resolveScopedRoutePathname falls back to direct value matching", () => {
74
- assert.equal(
75
- resolveScopedRoutePathname({
76
- currentPathname: "/contacts/abc%20123/notes",
77
- params: {},
78
- orderedParamNames: [],
79
- anchorParamName: "contactId",
80
- anchorParamValue: "abc 123",
81
- anchorMode: "at"
82
- }),
83
- "/contacts/abc%20123"
84
- );
85
- });