svelte-ag 1.2.7 → 1.3.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.
@@ -1,5 +1,13 @@
1
1
  import { stringify } from 'devalue';
2
- import type { ApiEndpoints, ApiInput, ApiRequestFunction, ApiSuccessBody, ApiErrorBody, ApiResponse } from 'ts-ag';
2
+ import type {
3
+ ApiEndpointContract,
4
+ ApiEndpoints,
5
+ ApiInput,
6
+ ApiRequestFunction,
7
+ ApiSuccessBody,
8
+ ApiErrorBody,
9
+ ApiResponse
10
+ } from 'ts-ag';
3
11
 
4
12
  import type { Cache } from './cache.svelte';
5
13
  import type { BatchDetails } from './entrypoint.svelte';
@@ -17,8 +25,7 @@ export class Query<
17
25
  #TIMEOUT = 1000 * 60 * 5; // 5 minutes
18
26
 
19
27
  // -------- Set in constructor --------
20
- #path: Path;
21
- #method: Method;
28
+ #endpoint: ApiEndpointContract<API, Path, Method>;
22
29
  #input: ApiInput<API, Path, Method>;
23
30
  #inputString: string;
24
31
  #cacheKey: string;
@@ -37,15 +44,13 @@ export class Query<
37
44
 
38
45
  // -------- Functions --------
39
46
  constructor({
40
- path,
41
- method,
47
+ endpoint,
42
48
  input,
43
49
  requestor,
44
50
  cache,
45
51
  opts
46
52
  }: {
47
- path: Path;
48
- method: Method;
53
+ endpoint: ApiEndpointContract<API, Path, Method>;
49
54
  input: ApiInput<API, Path, Method>;
50
55
  requestor: Requestor<API, Path, Method>;
51
56
  cache: Cache;
@@ -56,14 +61,13 @@ export class Query<
56
61
  this.#requestor = requestor;
57
62
  this.#cache = cache;
58
63
 
59
- this.#path = path;
60
- this.#method = method;
64
+ this.#endpoint = endpoint;
61
65
 
62
66
  // if (this.#cachekey) this.#cache.deregister(this.#cachekey);
63
67
 
64
68
  this.#input = input;
65
69
  this.#inputString = stringify(input);
66
- this.#cacheKey = cacheKey(path, method, input);
70
+ this.#cacheKey = cacheKey(endpoint, input);
67
71
 
68
72
  this.#cache.register(this.#cacheKey, opts?.cache ?? { timeout: this.#TIMEOUT });
69
73
  }
@@ -141,8 +145,7 @@ export class Requestor<
141
145
  #batchDelay = 100;
142
146
 
143
147
  // -------- Set in constructor --------
144
- #path: Path;
145
- #method: Method;
148
+ #endpoint: ApiEndpointContract<API, Path, Method>;
146
149
  #request: ApiRequestFunction<API>;
147
150
 
148
151
  #canBatch: BatchDetails<API, Path, Method>['canBatch'];
@@ -164,14 +167,12 @@ export class Requestor<
164
167
  #batchTimers: Record<string, NodeJS.Timeout | null> = {};
165
168
 
166
169
  constructor(
167
- path: Path,
168
- method: Method,
170
+ endpoint: ApiEndpointContract<API, Path, Method>,
169
171
  request: ApiRequestFunction<API>,
170
172
  _cache: Cache,
171
173
  batchDetails?: BatchDetails<API, Path, Method>
172
174
  ) {
173
- this.#path = path;
174
- this.#method = method;
175
+ this.#endpoint = endpoint;
175
176
  this.#request = request;
176
177
  this.#limiter = new RateLimiter();
177
178
  // this.#cache = cache;
@@ -187,7 +188,7 @@ export class Requestor<
187
188
  // if ('PUBLIC_ENVIRONMENT' in env && env.PUBLIC_ENVIRONMENT === 'development') {
188
189
  // await sleep(1000);
189
190
  // }
190
- return await this.#limiter.add(() => this.#request(this.#path, this.#method, input));
191
+ return await this.#limiter.add(() => this.#request(this.#endpoint, input));
191
192
  }
192
193
 
193
194
  /**
@@ -1,5 +1,5 @@
1
1
  import { stringify } from 'devalue';
2
- import { createApiRequest, type ApiEndpoints } from 'ts-ag';
2
+ import { createApiRequest, type ApiEndpointContract, type ApiEndpoints } from 'ts-ag';
3
3
  import * as v from 'valibot';
4
4
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
5
5
 
@@ -30,17 +30,17 @@ type BatchedUsersApi = {
30
30
 
31
31
  const API_URL = 'https://api.example.test';
32
32
 
33
- const plainSchemas = {
34
- '/users': {
35
- GET: v.object({ id: v.number() })
36
- }
37
- };
33
+ const plainUsers_GET = {
34
+ path: '/users',
35
+ method: 'GET',
36
+ schema: v.object({ id: v.number() })
37
+ } satisfies ApiEndpointContract<PlainUsersApi, '/users', 'GET'>;
38
38
 
39
- const batchedSchemas = {
40
- '/users': {
41
- POST: v.union([v.object({ id: v.number(), group: v.optional(v.string()) }), v.object({ ids: v.array(v.number()) })])
42
- }
43
- };
39
+ const batchedUsers_POST = {
40
+ path: '/users',
41
+ method: 'POST',
42
+ schema: v.union([v.object({ id: v.number(), group: v.optional(v.string()) }), v.object({ ids: v.array(v.number()) })])
43
+ } satisfies ApiEndpointContract<BatchedUsersApi, '/users', 'POST'>;
44
44
 
45
45
  function getSingleId(input: BatchedUsersApi['requestInput']): number {
46
46
  return 'id' in input ? input.id : input.ids[0]!;
@@ -97,23 +97,22 @@ function deferred<T>() {
97
97
  }
98
98
 
99
99
  function createPlainRequest() {
100
- return createApiRequest<PlainUsersApi>(plainSchemas, API_URL, 'test');
100
+ return createApiRequest<PlainUsersApi>(API_URL, 'test');
101
101
  }
102
102
 
103
103
  function createBatchedRequest() {
104
- return createApiRequest<BatchedUsersApi>(batchedSchemas, API_URL, 'test');
104
+ return createApiRequest<BatchedUsersApi>(API_URL, 'test');
105
105
  }
106
106
 
107
107
  function createPlainRequestor() {
108
- return new Requestor<PlainUsersApi, '/users', 'GET'>('/users', 'GET', createPlainRequest(), new Cache());
108
+ return new Requestor<PlainUsersApi, '/users', 'GET'>(plainUsers_GET, createPlainRequest(), new Cache());
109
109
  }
110
110
 
111
111
  function createBatchedRequestor(
112
- batchDetails?: ConstructorParameters<typeof Requestor<BatchedUsersApi, '/users', 'POST'>>[4]
112
+ batchDetails?: ConstructorParameters<typeof Requestor<BatchedUsersApi, '/users', 'POST'>>[3]
113
113
  ) {
114
114
  return new Requestor<BatchedUsersApi, '/users', 'POST'>(
115
- '/users',
116
- 'POST',
115
+ batchedUsers_POST,
117
116
  createBatchedRequest(),
118
117
  new Cache(),
119
118
  batchDetails
@@ -355,8 +354,7 @@ describe('Query', () => {
355
354
  const fetchMock = vi.fn().mockReturnValue(pending.promise);
356
355
  vi.stubGlobal('fetch', fetchMock);
357
356
  const query = new Query<PlainUsersApi, '/users', 'GET'>({
358
- path: '/users',
359
- method: 'GET',
357
+ endpoint: plainUsers_GET,
360
358
  input: { id: 1 },
361
359
  requestor: createPlainRequestor(),
362
360
  cache: new Cache()
@@ -378,8 +376,7 @@ describe('Query', () => {
378
376
  const fetchMock = vi.fn(async () => jsonFetchResponse({ id: 1, name: 'Ada' }));
379
377
  vi.stubGlobal('fetch', fetchMock);
380
378
  const query = new Query<PlainUsersApi, '/users', 'GET'>({
381
- path: '/users',
382
- method: 'GET',
379
+ endpoint: plainUsers_GET,
383
380
  input: { id: 1 },
384
381
  requestor: createPlainRequestor(),
385
382
  cache: new Cache()
@@ -400,8 +397,7 @@ describe('Query', () => {
400
397
  );
401
398
  vi.stubGlobal('fetch', fetchMock);
402
399
  const query = new Query<PlainUsersApi, '/users', 'GET'>({
403
- path: '/users',
404
- method: 'GET',
400
+ endpoint: plainUsers_GET,
405
401
  input: { id: 1 },
406
402
  requestor: createPlainRequestor(),
407
403
  cache: new Cache()
@@ -430,8 +426,7 @@ describe('Query', () => {
430
426
  const fetchMock = vi.fn(async () => withResponseOverrides(jsonFetchResponse({ id: 1 })));
431
427
  vi.stubGlobal('fetch', fetchMock);
432
428
  const query = new Query<PlainUsersApi, '/users', 'GET'>({
433
- path: '/users',
434
- method: 'GET',
429
+ endpoint: plainUsers_GET,
435
430
  input: { id: 1 },
436
431
  requestor: createPlainRequestor(),
437
432
  cache: new Cache()
@@ -457,8 +452,7 @@ describe('Query', () => {
457
452
  const fetchMock = vi.fn(async () => jsonFetchResponse({ id: 1, active: true }));
458
453
  vi.stubGlobal('fetch', fetchMock);
459
454
  const query = new Query<PlainUsersApi, '/users', 'GET'>({
460
- path: '/users',
461
- method: 'GET',
455
+ endpoint: plainUsers_GET,
462
456
  input: { id: 1 },
463
457
  requestor: createPlainRequestor(),
464
458
  cache: new Cache()
@@ -476,8 +470,7 @@ describe('Query', () => {
476
470
  const fetchMock = vi.fn(async () => jsonFetchResponse({ message: 'missing' }, 404));
477
471
  vi.stubGlobal('fetch', fetchMock);
478
472
  const query = new Query<PlainUsersApi, '/users', 'GET'>({
479
- path: '/users',
480
- method: 'GET',
473
+ endpoint: plainUsers_GET,
481
474
  input: { id: 99 },
482
475
  requestor: createPlainRequestor(),
483
476
  cache: new Cache()
@@ -505,8 +498,7 @@ describe('Query', () => {
505
498
  });
506
499
  vi.stubGlobal('fetch', fetchMock);
507
500
  const query = new Query<PlainUsersApi, '/users', 'GET'>({
508
- path: '/users',
509
- method: 'GET',
501
+ endpoint: plainUsers_GET,
510
502
  input: { id: 1 },
511
503
  requestor: createPlainRequestor(),
512
504
  cache: new Cache()
@@ -532,8 +524,7 @@ describe('Query', () => {
532
524
  });
533
525
  vi.stubGlobal('fetch', fetchMock);
534
526
  const query = new Query<PlainUsersApi, '/users', 'GET'>({
535
- path: '/users',
536
- method: 'GET',
527
+ endpoint: plainUsers_GET,
537
528
  input: { id: 1 },
538
529
  requestor: createPlainRequestor(),
539
530
  cache: new Cache()
@@ -558,8 +549,7 @@ describe('Query', () => {
558
549
  });
559
550
  vi.stubGlobal('fetch', fetchMock);
560
551
  const query = new Query<PlainUsersApi, '/users', 'GET'>({
561
- path: '/users',
562
- method: 'GET',
552
+ endpoint: plainUsers_GET,
563
553
  input: { id: 1 },
564
554
  requestor: createPlainRequestor(),
565
555
  cache: new Cache(),
@@ -1,9 +1,10 @@
1
1
  import { stringify } from 'devalue';
2
+ import { endpointKey } from 'ts-ag';
2
3
 
3
- export function batchQueryKey(path: string, method: string) {
4
- return `${path}_${method}`;
4
+ export function batchQueryKey(endpoint: { path: string; method: string }) {
5
+ return endpointKey(endpoint);
5
6
  }
6
7
 
7
- export function cacheKey(path: string, method: string, input: any) {
8
- return `${path}_${method}_${stringify(input)}`;
8
+ export function cacheKey(endpoint: { path: string; method: string }, input: any) {
9
+ return `${endpointKey(endpoint)} ${stringify(input)}`;
9
10
  }