Compare commits

...

1 Commits

Author SHA1 Message Date
Matt Aitken f85907ec68 WIP from @Chigala, needs work on packaging 2023-10-06 17:17:18 +01:00
17 changed files with 483 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock
+30
View File
@@ -0,0 +1,30 @@
module.exports = {
root: true,
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:svelte/recommended',
'prettier'
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
extraFileExtensions: ['.svelte']
},
env: {
browser: true,
es2017: true,
node: true
},
overrides: [
{
files: ['*.svelte'],
parser: 'svelte-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser'
}
}
]
};
+11
View File
@@ -0,0 +1,11 @@
.DS_Store
node_modules
/build
/dist
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
+13
View File
@@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock
+9
View File
@@ -0,0 +1,9 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"pluginSearchDirs": ["."],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}
+58
View File
@@ -0,0 +1,58 @@
# create-svelte
Everything you need to build a Svelte library, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
Read more about creating a library [in the docs](https://kit.svelte.dev/docs/packaging).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npm create svelte@latest
# create a new project in my-app
npm create svelte@latest my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
Everything inside `src/lib` is part of your library, everything inside `src/routes` can be used as a showcase or preview app.
## Building
To build your library:
```bash
npm run package
```
To create a production version of your showcase app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
## Publishing
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/)).
To publish your library to [npm](https://www.npmjs.com):
```bash
npm publish
```
+64
View File
@@ -0,0 +1,64 @@
{
"name": "@trigger.dev/svelte",
"version": "2.1.9",
"description": "Trigger.dev Svelte SDK",
"license": "MIT",
"scripts": {
"dev": "vite dev",
"build": "svelte-package --input ./src --output ./build",
"preview": "vite preview",
"package": "svelte-kit sync && svelte-package && publint",
"prepublishOnly": "npm run package",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"test": "vitest",
"lint": "prettier --plugin-search-dir . --check . && eslint .",
"format": "prettier --plugin-search-dir . --write ."
},
"type": "module",
"types": "build/index.d.ts",
"module": "build/index.js",
"exports": {
".": {
"types": "./build/index.d.ts",
"import": "./build/index.js",
"svelte": "./build/index.js",
"default": "./build/index.js"
},
"./package.json": "./package.json"
},
"files": [
"dist",
"!dist/**/*.test.*",
"!dist/**/*.spec.*"
],
"peerDependencies": {
"svelte": "^4.0.0"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.20.4",
"@sveltejs/package": "^2.0.0",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-svelte": "^2.30.0",
"prettier": "^2.8.0",
"prettier-plugin-svelte": "^2.10.1",
"publint": "^0.1.9",
"svelte": "^4.0.5",
"svelte-check": "^3.4.3",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^4.4.2",
"vitest": "^0.34.0"
},
"dependencies": {
"@tanstack/svelte-query": "^4.33.0",
"@trigger.dev/core": "workspace:*",
"@trigger.dev/sdk": "workspace:*",
"esm-env": "^1.0.0",
"zod": "3.22.3"
}
}
@@ -0,0 +1,55 @@
<script lang="ts">
import { BROWSER } from 'esm-env';
import { QueryClient, QueryClientProvider } from '@tanstack/svelte-query';
import { setTriggerContext } from './providerContext.js';
export let publicApiKey: string;
export let apiUrl: string | undefined = undefined;
setTriggerContext({
publicApiKey,
apiUrl
});
const publicApiKeyStartsWith = 'pk_';
const privateApiKeyStartsWith = 'tr_';
// SvelteKit defaults to rendering routes with SSR.
// Because of this, you need to disable the query on the server. Otherwise, your query will continue executing on the server asynchronously,
// even after the HTML has been sent to the client.
//https://tanstack.com/query/latest/docs/svelte/ssr
const queryClient = new QueryClient({
defaultOptions: {
queries: {
enabled: BROWSER
}
}
});
if (!publicApiKey) {
throw new Error('TriggerProvider requires `publicApiKey` to be set with a value.');
}
$: {
verifyApiKey(publicApiKey);
}
function verifyApiKey(apiKey: string) {
if (apiKey.startsWith(privateApiKeyStartsWith)) {
throw new Error(
`You are using a private API key, you should not do this because the value is visible to the client.`
);
}
if (!apiKey.startsWith(publicApiKeyStartsWith)) {
console.error(
`TriggerProvider publicApiKey wasn't in the correct format. Should be ${publicApiKeyStartsWith}...`
);
}
}
</script>
<div>
<QueryClientProvider client={queryClient}>
<slot />
</QueryClientProvider>
</div>
+12
View File
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>
+63
View File
@@ -0,0 +1,63 @@
import { createQuery, type CreateQueryResult } from '@tanstack/svelte-query';
import { GetEventSchema, type GetEvent } from '@trigger.dev/core';
import { getTriggerContext } from './providerContext.js';
import { zodfetch } from './fetch.js';
import { runResolvedStatuses } from './runs.js';
const defaultRefreshInterval = 1000;
export type UseEventDetailsResult = CreateQueryResult<GetEvent>;
export function useEventDetails(eventId: string | undefined): UseEventDetailsResult {
const { apiUrl, publicApiKey } = getTriggerContext();
return createQuery({
queryKey: [`triggerdotdev-event-${eventId}`],
queryFn: async () => {
return await zodfetch(GetEventSchema, `${apiUrl}/api/v1/events/${eventId}`, {
method: 'GET',
headers: {
Authorization: `Bearer ${publicApiKey}`
}
});
},
refetchInterval: (data) => {
if (
data &&
data.runs.length > 0 &&
data.runs.every((r) => runResolvedStatuses.includes(r.status))
) {
return false;
}
return defaultRefreshInterval;
},
enabled: !!eventId
});
}
//we cannot call useRunDetails inside the subscription, because it would be called outside component initialization, we will have to do it inside the svelte component itself
//I'm still looking for better ways of doing this.
// export function useEventRunDetails(
// eventId: string | undefined,
// options?: RunDetailOptions
// ): RunDetailsResult | undefined {
// const event = useEventDetails(eventId);
// let result: RunDetailsResult | undefined;
// const subscribedEvent = event.subscribe((event) => {
// if (event.data) {
// console.log('event: ', event.data?.id);
// const runs = useRunDetails(event.data?.runs[0].id, options);
// runs.subscribe((runs) => {
// console.log('runs: ', runs);
// result = runs;
// });
// }
// });
// onDestroy(() => {
// subscribedEvent();
// });
// return result;
// }
+32
View File
@@ -0,0 +1,32 @@
import type { z } from 'zod';
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint
export async function zodfetch<TResponseBody extends any>(
schema: z.Schema<TResponseBody>,
url: string,
requestInit?: RequestInit
): Promise<TResponseBody> {
const response = await fetch(url, requestInit);
if ((!requestInit || requestInit.method === 'GET') && response.status === 404) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return;
}
//todo improve error handling
if (response.status >= 400 && response.status < 500) {
const body = await response.json();
throw new Error(body.error);
}
if (response.status !== 200) {
throw new Error(`Failed to fetch ${url}, got status code ${response.status}`);
}
const jsonBody = await response.json();
return schema.parse(jsonBody);
}
+3
View File
@@ -0,0 +1,3 @@
export * from './events.js'
export * from './runs.js'
export { default as TriggerProvider } from './TriggerProvider.svelte';
+17
View File
@@ -0,0 +1,17 @@
import { getContext, setContext } from 'svelte';
type TriggerContext = {
publicApiKey: string;
apiUrl?: string;
};
const triggerContextKey = "$$_TriggerContext"
export function setTriggerContext(context: TriggerContext) {
setContext(triggerContextKey, context);
}
export function getTriggerContext(): TriggerContext {
return getContext<TriggerContext>(triggerContextKey);
}
+54
View File
@@ -0,0 +1,54 @@
import { createQuery, type CreateQueryResult } from '@tanstack/svelte-query';
import {
GetRunSchema,
urlWithSearchParams,
type GetRun,
type GetRunOptions
} from '@trigger.dev/core';
import { getTriggerContext } from './providerContext.js';
import { zodfetch } from './fetch.js';
export const runResolvedStatuses = ['SUCCESS', 'FAILURE', 'CANCELED', 'TIMED_OUT', 'ABORTED'];
const defaultRefreshInterval = 1000;
export type RunDetailOptions = GetRunOptions & {
/** How often you want to refresh, the default is 1000. Min is 500 */
refreshIntervalMs?: number;
};
export type UseRunDetailsResult = CreateQueryResult<GetRun>;
export function useRunDetails(
runId: string | undefined,
options?: RunDetailOptions
): UseRunDetailsResult {
const { apiUrl, publicApiKey } = getTriggerContext();
const { refreshIntervalMs: refreshInterval, ...otherOptions } = options || {};
const url = urlWithSearchParams(`${apiUrl}/api/v1/runs/${runId}`, otherOptions);
return createQuery({
queryKey: [`triggerdotdev-run-${runId}`],
queryFn: async () => {
return await zodfetch(GetRunSchema, url, {
method: 'GET',
headers: {
Authorization: `Bearer ${publicApiKey}`
}
});
},
enabled: !!runId,
refetchInterval: (data) => {
if (data?.status && runResolvedStatuses.includes(data.status)) {
return false;
}
if (refreshInterval !== undefined) {
return Math.max(refreshInterval, 500);
}
return defaultRefreshInterval;
}
});
}
+18
View File
@@ -0,0 +1,18 @@
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/kit/vite';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: vitePreprocess(),
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter(),
}
};
export default config;
+22
View File
@@ -0,0 +1,22 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "Node",
"ignoreDeprecations": "5.0",
"paths": {
"@trigger.dev/core": ["../core/src/index"],
"@trigger.dev/core/*": ["../core/src/*"],
"@trigger.dev/sdk": ["../trigger-sdk/src/index"],
"@trigger.dev/sdk/*": ["../trigger-sdk/src/*"]
}
},
"exclude": ["node_modules"]
}
+9
View File
@@ -0,0 +1,9 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vitest/config';
export default defineConfig({
plugins: [sveltekit()],
test: {
include: ['src/**/*.{test,spec}.{js,ts}']
}
});