npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@tanglemedia/svelte-starter-core

v0.1.4

Published

Styles and components for use in svelte websites

Downloads

164

Readme

Core

This package is experimental and is meant for internal use only.

Application

This is the entry point for initialing the application.

import { createApplication } from '@tanglemedia/svelte-starter-core';

const { application, configureService, getConfiguration, provideConfig, handle } =
  createApplication({
    /** options */
  });

Options

| option | required | note | | ---------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | config.loader | No | Function that returns a ConfigLoaderInterface. Uses the yml loader by default | | config.env | No | Function that returns the env payload. By default it uses svelte's $env/dynamic/public | | config.alias | No | True by default. Assumes you have defined an alias for "$config" otherwise it will assume your configs are loaded from /src/config/*/.yml | | service.provider.register | No | | | service.provider.serviceOptions | No | This will be applied to all services that was configured with configureService | | service.provider.serviceOptions.path | Yes | The path of the url for the api. Url is derived from the api.yml config baseUrl | | service.provider.serviceOptions.pathPrefix | No | Not supported | | service.provider.serviceOptions.transform | No | Transforms the response body | | service.provider.serviceOptions.transformQuery | No | Transforms the request query | | service.provider.serviceOptions.transformMeta | No | Transforms meta information | | service.provider.serviceOptions.throwError | No | Defaults to true. If it isn't a falsy value (null/0/false etc) then validateStatus will determine if the response is invalid | | service.provider.serviceOptions.validateStatus | No | Overwrite the method used to determine errors. (status: number) => boolean | | service.provider.serviceOptions.errorHandler | No | By default, the system will throw an exception. If you want to catch a specific error code such as a 401 to redirect to login, you can specify this here. For ALL errors, use 0 as the status code. | | application.plugin | No | An array of plugin providers |

Services

Services is a simple abstraction layer that makes some assumptions around common api requests and responses. Sevices rely on an underlying adapter which is responsible for transforming the request/response payloads and handling the actual requests to an api. Once you application has been configured, you can easily configure services like so. Note that boot exports the return values from createApplication.

import { ServiceAbstract } from '@tanglemedia/svelte-starter-core';
import type { User } from './schema/animal-color.interface';
import { configureService } from '../boot';

export class UserService extends ServiceAbstract<User> {}

const userService = configureService<User>(UserService, {
  path: 'users',
  transform: (payload) => {
    /** do something to your payload */
    return { ...payload };
  }
  // choose the adapter if it's a custom api
  // adapterKey: 'tenant'
});

// now you can query the api
userService.find({ filter: { email: '[email protected]' } });

Global Error handling

You can catch all service errors via the configs in createApplication. This is useful for catching a 401 status and redirecting to the log in screen.

import { createApplication } from '@tanglemedia/svelte-starter-core';
import { page } from '$app/stores';
import { goto } from '$app/navigation';

createApplication({
  /**
   * Handle global redirects
   */
  errorHandler: {
    // 0: () => console.log('Catch all errors')
    401: () => {
      let redirectUrl: string | null = null;

      const unsub = page.subscribe((page) => {
        redirectUrl = `/auth/login?_redirect=${page.url.pathname}`;
      });

      if (redirectUrl) {
        goto(redirectUrl);
      }

      unsub();
    }
  }
});

Authoring Api Adapters

Api adapters run the underlying logic for services. If your api uses an SDK you might need to create a custom adapter. Start by creating an api provider function.

import type {
  AdapterProviderRegister,
  ApiAdapterInterface,
  ApiAdapterProviderInterface
} from '@tanglemedia/svelte-starter-core';
import { MyCustomApiAdapter } from './my-adapter.ts';

type MyApiConfig = {};

class MyCustomApiProvider implements ApiAdapterProviderInterface<MyApiConfig> {
  async loadAdapter(key?: string, config?: MyApiConfig): Promise<ApiAdapterInterface<MyApiConfig>> {
    if (!config) {
      throw new Error('Missing adapter configuration');
    }

    const client = this.createDirectusClient<SchemaShape>(config);

    return new MyCustomApiAdapter(config, client);
  }
}

export const customAdapter = (): AdapterProviderRegister => ({
  name: 'my-custom-adapter',
  provider: new MyCustomApiProvider()
});

Next, define the actual api adapter. Make sure the class conforms with the ApiAdapterInterface interface.

import { ApiAdapterAbstract } from '@tanglemedia/svelte-starter-core';

export class MyCustomApiAdapter extends ApiAdapterAbstract<MyApiConfig> {
  /** Implement the necessary interface methods and abstracts */
}

Users can register your api adapter like so

import { createApplication } from '@tanglemedia/svelte-starter-core';
import { customAdapter } from 'my-custom-api';

createApplication({
  service: {
    provider: { register: [customAdapter()] }
  }
});

Authoring plugins

The main reason to author your own plugin is to add and enrich functionality of the application with the use of the configuration setup. To get started you'll need to define an function which provides the following


import MyComponent from './MyComponent.svelte'

export const myPlugin = () => ({
  name: 'my-plugin'
  root: 'parent-plugin',
  component: MyComponent,
  boot: () => {
    // after plugin is registered
  },
  handle: () => {
    return (event, resolve) => {
      // this hook is called server side
      return event(resolve)
    }
  }
})

Name - Required

An arbitrary name for your plugin. This and the "root" needs to be unique because a combination of both is used as a key for lookup.

Root - Optional

If you are writing an "adapter" for a specific plugin, you may specify the root plugin name. You plugin will now be scoped under this root plugin.

Component and ComponentFactory

Components requires an app property to be declared as a prop. It also requires a <slot />. If the slot isn't there, your application WILL not load properly

<script>
  import { type ConfiguredApplication } from '@tanglemedia/svelte-starter-core';

  export let app: ConfiguredApplication;
</script>

<slot />

Provide a component to be loaded with your application. There are two ways to specify how you want to load the component. You MUST specify one or the other and NOT both. The example above shows loading the component by providing it directly. You may also load the component via a factory which is an async function that returns the compoent.

export const myPlugin = () => ({
  name: 'my-plugin'
  root: 'parent-plugin',
  componentFactory: () => import('./MyComponent.svelte').then((m) => m.default)
})

Boot - optional

Called after the plugin is registerd

Handle - optional

This should return a function that conforms to svelte's hook function.