@tanglemedia/svelte-starter-toolbelt 2.0.0-next.2 → 2.0.0-next.3

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
@@ -1,58 +1,63 @@
1
- # Svelte library
1
+ # @tanglemedia/svelte-starter-toolbelt
2
2
 
3
- Everything you need to build a Svelte library, powered by [`sv`](https://npmjs.com/package/sv).
3
+ Shared service, query, mutation, proxy, and utility helpers used across the Svelte Starter.
4
4
 
5
- Read more about creating a library [in the docs](https://svelte.dev/docs/kit/packaging).
5
+ ## Service providers
6
6
 
7
- ## Creating a project
7
+ `createServiceFactory` builds typed collection services on top of a provider:
8
8
 
9
- If you're seeing this, you've probably already done this step. Congrats!
9
+ - `createDirectusServiceProvider` for Directus-backed collections
10
+ - `createFetchServiceProvider` for generic REST APIs
11
+ - `createFixtureServiceProvider` for local JSON fixtures served through core's `fixture` adapter
10
12
 
11
- ```bash
12
- # create a new project in the current directory
13
- npx sv create
13
+ ### Fixture provider example
14
14
 
15
- # create a new project in my-app
16
- npx sv create my-app
17
- ```
15
+ ```typescript
16
+ import {
17
+ createFixtureServiceProvider,
18
+ createServiceFactory
19
+ } from '@tanglemedia/svelte-starter-toolbelt';
20
+ import configuredApp from '$boot';
18
21
 
19
- ## Developing
22
+ type User = {
23
+ id: number;
24
+ name: string;
25
+ };
20
26
 
21
- Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
27
+ type Schema = {
28
+ users: User;
29
+ };
22
30
 
23
- ```bash
24
- npm run dev
31
+ export const createService = createServiceFactory<Schema, typeof createFixtureServiceProvider>(
32
+ configuredApp,
33
+ createFixtureServiceProvider
34
+ );
25
35
 
26
- # or start the server and open the app in a new browser tab
27
- npm run dev -- --open
36
+ export const usersService = createService('users');
37
+ export const { findUsers, findUsersById } = usersService;
28
38
  ```
29
39
 
30
- Everything inside `src/lib` is part of your library, everything inside `src/routes` can be used as a showcase or preview app.
31
-
32
- ## Building
40
+ `createFixtureServiceProvider` defaults `adapterKey` to `'fixture'`, so it works with this
41
+ `api.yml` setup:
33
42
 
34
- To build your library:
43
+ ```yaml
44
+ default: 'fixture'
35
45
 
36
- ```bash
37
- npm run package
46
+ adapters:
47
+ fixture:
48
+ adapter: fixture
49
+ configuration: {}
38
50
  ```
39
51
 
40
- To create a production version of your showcase app:
52
+ If you need a different adapter key:
41
53
 
42
- ```bash
43
- npm run build
54
+ ```typescript
55
+ export const tenantUsersService = createService('users', {
56
+ adapterKey: 'tenant-fixture'
57
+ });
44
58
  ```
45
59
 
46
- You can preview the production build with `npm run preview`.
47
-
48
- > To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
49
-
50
- ## Publishing
60
+ ## More docs
51
61
 
52
- Go into the `package.json` and give your package the desired name through the `"name"` option. Also consider adding a `"license"` field and point it to a `LICENSE` file which you can create from a template (one popular option is the [MIT license](https://opensource.org/license/mit/)).
53
-
54
- To publish your library to [npm](https://www.npmjs.com):
55
-
56
- ```bash
57
- npm publish
58
- ```
62
+ - Package docs: `docs/packages/toolbelt.md`
63
+ - Service-focused guide: `docs/packages/toolbelt-services.md`
@@ -1,3 +1,4 @@
1
1
  export * from './provider/create-directus-service.provider.ts';
2
2
  export * from './provider/create-fetch-service.provider.ts';
3
+ export * from './provider/create-fixture-service.provider.ts';
3
4
  export * from './service.factory.ts';
@@ -1,3 +1,4 @@
1
1
  export * from "./provider/create-directus-service.provider.js";
2
2
  export * from "./provider/create-fetch-service.provider.js";
3
+ export * from "./provider/create-fixture-service.provider.js";
3
4
  export * from "./service.factory.js";
@@ -0,0 +1,9 @@
1
+ import { ServiceAbstract, type AnyObject, type ConfigurableServiceClass, type ConfiguredApplication, type ServiceAbstractOptions } from '@tanglemedia/svelte-starter-core';
2
+ export declare class BaseFixtureService<T extends AnyObject> extends ServiceAbstract<T> {
3
+ }
4
+ type FixtureServiceProviderOpt<T extends AnyObject> = {
5
+ serviceClass?: (base: ConfigurableServiceClass<T, BaseFixtureService<T>>) => ConfigurableServiceClass<T, BaseFixtureService<T>>;
6
+ adapterKey?: string;
7
+ };
8
+ export declare function createFixtureServiceProvider({ configureService }: ConfiguredApplication): <T extends AnyObject>(collection: string, opt?: Partial<ServiceAbstractOptions> & FixtureServiceProviderOpt<T>) => BaseFixtureService<T>;
9
+ export {};
@@ -0,0 +1,18 @@
1
+ import { ServiceAbstract } from '@tanglemedia/svelte-starter-core';
2
+ export class BaseFixtureService extends ServiceAbstract {
3
+ }
4
+ export function createFixtureServiceProvider({ configureService }) {
5
+ const services = {};
6
+ return (collection, opt) => {
7
+ const k = JSON.stringify([collection, opt]);
8
+ if (services[k]) {
9
+ return services[k];
10
+ }
11
+ const Service = opt?.serviceClass ? opt.serviceClass(BaseFixtureService) : BaseFixtureService;
12
+ return (services[k] = configureService(Service, {
13
+ path: collection,
14
+ adapterKey: opt?.adapterKey ?? 'fixture',
15
+ ...(opt ?? {})
16
+ }));
17
+ };
18
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanglemedia/svelte-starter-toolbelt",
3
- "version": "2.0.0-next.2",
3
+ "version": "2.0.0-next.3",
4
4
  "files": [
5
5
  "src",
6
6
  "dist",
@@ -29,7 +29,7 @@
29
29
  },
30
30
  "peerDependencies": {
31
31
  "@directus/sdk": ">=17.0.0",
32
- "@tanglemedia/svelte-starter-core": ">=4.0.0-next.0",
32
+ "@tanglemedia/svelte-starter-core": ">=4.0.0-next.1",
33
33
  "@tanstack/svelte-query": ">=6",
34
34
  "svelte": "^5.0.0"
35
35
  },
@@ -64,8 +64,8 @@
64
64
  "vite": "^8.0.8",
65
65
  "msw": "^2.12.7",
66
66
  "vitest": "^4.1.4",
67
- "@tanglemedia/svelte-starter-types": "3.0.0-next.0",
68
- "@tanglemedia/svelte-starter-core": "4.0.0-next.0"
67
+ "@tanglemedia/svelte-starter-core": "4.0.0-next.1",
68
+ "@tanglemedia/svelte-starter-types": "3.0.0-next.0"
69
69
  },
70
70
  "keywords": [
71
71
  "svelte"
@@ -1,3 +1,4 @@
1
1
  export * from './provider/create-directus-service.provider.ts';
2
2
  export * from './provider/create-fetch-service.provider.ts';
3
+ export * from './provider/create-fixture-service.provider.ts';
3
4
  export * from './service.factory.ts';
@@ -0,0 +1,94 @@
1
+ import { describe, expect, test, vi } from 'vitest';
2
+ import type { ConfiguredApplication, ServiceAbstractOptions } from '@tanglemedia/svelte-starter-core';
3
+
4
+ import {
5
+ BaseFixtureService,
6
+ createFixtureServiceProvider
7
+ } from './create-fixture-service.provider';
8
+
9
+ describe('createFixtureServiceProvider', () => {
10
+ test('returns a factory function', () => {
11
+ const app = {
12
+ configureService: vi.fn()
13
+ } as unknown as ConfiguredApplication;
14
+
15
+ const createService = createFixtureServiceProvider(app);
16
+
17
+ expect(typeof createService).toBe('function');
18
+ });
19
+
20
+ test('caches service instances for the same collection and options', () => {
21
+ const instance = { service: 'fixture' };
22
+ const app = {
23
+ configureService: vi.fn(() => instance)
24
+ } as unknown as ConfiguredApplication;
25
+ const createService = createFixtureServiceProvider(app);
26
+
27
+ const first = createService('users');
28
+ const second = createService('users');
29
+
30
+ expect(first).toBe(second);
31
+ expect(app.configureService).toHaveBeenCalledOnce();
32
+ });
33
+
34
+ test('defaults adapterKey to fixture', () => {
35
+ const configureService = vi.fn();
36
+ const app = {
37
+ configureService
38
+ } as unknown as ConfiguredApplication;
39
+ const createService = createFixtureServiceProvider(app);
40
+
41
+ createService('users');
42
+
43
+ expect(configureService).toHaveBeenCalledWith(
44
+ BaseFixtureService,
45
+ expect.objectContaining({
46
+ path: 'users',
47
+ adapterKey: 'fixture'
48
+ })
49
+ );
50
+ });
51
+
52
+ test('passes through a custom adapterKey when provided', () => {
53
+ const configureService = vi.fn();
54
+ const app = {
55
+ configureService
56
+ } as unknown as ConfiguredApplication;
57
+ const createService = createFixtureServiceProvider(app);
58
+
59
+ createService('users', {
60
+ adapterKey: 'tenant-fixture'
61
+ });
62
+
63
+ expect(configureService).toHaveBeenCalledWith(
64
+ BaseFixtureService,
65
+ expect.objectContaining({
66
+ adapterKey: 'tenant-fixture'
67
+ })
68
+ );
69
+ });
70
+
71
+ test('uses a custom serviceClass when provided', () => {
72
+ const configureService = vi.fn();
73
+ const app = {
74
+ configureService
75
+ } as unknown as ConfiguredApplication;
76
+ const createService = createFixtureServiceProvider(app);
77
+
78
+ class CustomFixtureService<T extends Record<string, unknown>> extends BaseFixtureService<T> {}
79
+
80
+ createService('users', {
81
+ serviceClass: () => CustomFixtureService,
82
+ throwError: false
83
+ } as Partial<ServiceAbstractOptions>);
84
+
85
+ expect(configureService).toHaveBeenCalledWith(
86
+ CustomFixtureService,
87
+ expect.objectContaining({
88
+ path: 'users',
89
+ adapterKey: 'fixture',
90
+ throwError: false
91
+ })
92
+ );
93
+ });
94
+ });
@@ -0,0 +1,37 @@
1
+ import {
2
+ ServiceAbstract,
3
+ type AnyObject,
4
+ type ConfigurableServiceClass,
5
+ type ConfiguredApplication,
6
+ type ServiceAbstractOptions
7
+ } from '@tanglemedia/svelte-starter-core';
8
+
9
+ export class BaseFixtureService<T extends AnyObject> extends ServiceAbstract<T> {}
10
+
11
+ type FixtureServiceProviderOpt<T extends AnyObject> = {
12
+ serviceClass?: (base: ConfigurableServiceClass<T, BaseFixtureService<T>>) => ConfigurableServiceClass<T, BaseFixtureService<T>>;
13
+ adapterKey?: string;
14
+ };
15
+
16
+ export function createFixtureServiceProvider({ configureService }: ConfiguredApplication) {
17
+ const services: Record<string, unknown> = {};
18
+
19
+ return <T extends AnyObject>(
20
+ collection: string,
21
+ opt?: Partial<ServiceAbstractOptions> & FixtureServiceProviderOpt<T>
22
+ ): BaseFixtureService<T> => {
23
+ const k = JSON.stringify([collection, opt]);
24
+
25
+ if (services[k]) {
26
+ return services[k] as BaseFixtureService<T>;
27
+ }
28
+
29
+ const Service = opt?.serviceClass ? opt.serviceClass(BaseFixtureService) : BaseFixtureService<T>;
30
+
31
+ return (services[k] = configureService<T, BaseFixtureService<T>>(Service, {
32
+ path: collection,
33
+ adapterKey: opt?.adapterKey ?? 'fixture',
34
+ ...(opt ?? {})
35
+ })) as BaseFixtureService<T>;
36
+ };
37
+ }