html-satori based

This commit is contained in:
Shivam Meena
2023-10-05 07:35:26 +05:30
parent f3fc389e91
commit 501efa9413
58 changed files with 1099 additions and 7864 deletions

View File

@@ -1,20 +1,30 @@
module.exports = {
root: true,
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:svelte/recommended',
'prettier'
],
parser: '@typescript-eslint/parser',
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
plugins: ['svelte3', '@typescript-eslint'],
ignorePatterns: ['*.cjs'],
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
settings: {
'svelte3/typescript': () => require('typescript')
},
plugins: ['@typescript-eslint'],
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020
ecmaVersion: 2020,
extraFileExtensions: ['.svelte']
},
env: {
browser: true,
es2017: true,
node: true
}
},
overrides: [
{
files: ['*.svelte'],
parser: 'svelte-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser'
}
}
]
};

View File

@@ -1,40 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@@ -1,19 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -1,27 +0,0 @@
on:
push:
branches: main
jobs:
publish:
runs-on: ubuntu-latest
env:
CI: true
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- uses: pnpm/action-setup@v2
name: Install pnpm
id: pnpm-install
with:
version: 8.6.1
- run: pnpm install
- run: pnpm test:build
- run: pnpm build
#- run: pnpm test
- uses: JS-DevTools/npm-publish@v2
with:
token: ${{ secrets.NPM_TOKEN }}
package: "package"

7
.gitignore vendored
View File

@@ -1,13 +1,12 @@
.DS_Store
node_modules
/build
/dist
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
.idea
package
.vercel
pnpm-lock.yaml
dist

1
.npmrc
View File

@@ -1 +1,2 @@
engine-strict=true
resolution-mode=highest

21
LICENSE
View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2022 Ether Corps
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

203
README.md
View File

@@ -1,189 +1,58 @@
# SvelteKit Open Graph Image Generation
# create-svelte
Dynamically generate Open Graph images from an HTML+CSS template or Svelte component using fast and efficient conversion from HTML > SVG > PNG. Based on [Satori](https://github.com/vercel/satori#documentation). No headless browser required.
Everything you need to build a Svelte library, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
## Installation
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
pnpm install -D @ethercorps/sveltekit-og
# 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
```
> Using with Cloudflare Pages or Workers then you have to provide `url` polyfill by just installing it as `devDependency`.
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
pnpm i -D url
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Usage
Everything inside `src/lib` is part of your library, everything inside `src/routes` can be used as a showcase or preview app.
Create a file at `/src/routes/og/+server.ts`. Alternatively, you can use JavaScript by removing the types from this example.
## Building
```typescript
// src/routes/og/+server.ts
import { ImageResponse } from '@ethercorps/sveltekit-og';
import { RequestHandler } from './$types';
To build your library:
const template = `
<div tw="bg-gray-50 flex w-full h-full items-center justify-center">
<div tw="flex flex-col md:flex-row w-full py-12 px-4 md:items-center justify-between p-8">
<h2 tw="flex flex-col text-3xl sm:text-4xl font-bold tracking-tight text-gray-900 text-left">
<span>Ready to dive in?</span>
<span tw="text-indigo-600">Start your free trial today.</span>
</h2>
<div tw="mt-8 flex md:mt-0">
<div tw="flex rounded-md shadow">
<a href="#" tw="flex items-center justify-center rounded-md border border-transparent bg-indigo-600 px-5 py-3 text-base font-medium text-white">Get started</a>
</div>
<div tw="ml-3 flex rounded-md shadow">
<a href="#" tw="flex items-center justify-center rounded-md border border-transparent bg-white px-5 py-3 text-base font-medium text-indigo-600">Learn more</a>
</div>
</div>
</div>
</div>
`;
const fontFile = await fetch('https://og-playground.vercel.app/inter-latin-ext-400-normal.woff');
const fontData: ArrayBuffer = await fontFile.arrayBuffer();
export const GET: RequestHandler = async () => {
return await ImageResponse(template, {
height: 630,
width: 1200,
fonts: [
{
name: 'Inter Latin',
data: fontData,
weight: 400
}
]
});
};
```bash
npm run package
```
Then run `npm dev` and visit `localhost:5173/og` to view your generated PNG. Remember that hot module reloading does not work with server routes, so if you change your HTML or CSS, hard refresh the route to see changes.
To create a production version of your showcase app:
## Example Output
![Rendered OG image](static/demo.png)
## Headers
When run in development, image headers contain `cache-control: no-cache, no-store`. In production, image headers contain `'cache-control': 'public, immutable, no-transform, max-age=31536000'`, which caches the image for 1 year. In both cases, the `'content-type': 'image/png'` is used.
## Styling
Notice that our example uses TailwindCSS classes (e.g. `tw="bg-gray-50"`). Alternatively, your HTML can contain style attributes using any of [the subset of CSS supported by Satori](https://github.com/vercel/satori#css).
Satori supports only a subset of HTML and CSS. For full details, see [Satoris documentation](https://github.com/vercel/satori#documentation). Notably, Satori only supports flex-based layouts.
## Fonts
Satori supports `ttf`, `otf`, and `woff` font formats; `woff2` is not supported. To maximize the font parsing speed, `ttf` or `otf` are recommended over `woff`.
By default, `@ethercorps/sveltekit-og` includes only 'Noto Sans' font. If you need to use other fonts, you can specify them as shown in the example. Notably, you can also import a font file that is stored locally within your project and are not required to use fetch.
## Examples
- `ImageResponse` · [_source_](/src/routes/new/+server.ts) · [_demo_](https://sveltekit-og-five.vercel.app/new)
- `componentToImageResponse` · [_source_](/src/routes/component-og/) · [_demo_](https://sveltekit-og-five.vercel.app/component-og)
## API Reference
The package exposes an `ImageResponse` and `componentToImageResponse` constructors, with the following options available:
```typescript
import {ImageResponse, componentToImageResponse} from '@ethercorps/sveltekit-og'
import {SvelteComponent} from "svelte";
// ...
ImageResponse(
element : string,
options : {
width ? : number = 1200
height ? : number = 630,
backgroundColor ? : string = "#fff"
fonts ? : {
name: string,
data: ArrayBuffer,
weight: number,
style: 'normal' | 'italic'
}[]
debug ? : boolean = false
graphemeImages ? : Record<string, string>;
loadAdditionalAsset ? : (languageCode: string, segment: string) => Promise<SatoriOptions["fonts"] | string | undefined>;
// Options that will be passed to the HTTP response
status ? : number = 200
statusText ? : string
headers ? : Record<string, string>
})
componentToImageResponse(
component : typeof SvelteComponent,
props : {}, // All export let example inside prop dictionary
options : {
width ? : number = 1200
height ? : number = 630
fonts ? : {
name: string,
data: ArrayBuffer,
weight: number,
style: 'normal' | 'italic'
}[]
debug ? : boolean = false
graphemeImages ? : Record<string, string>;
loadAdditionalAsset ? : (languageCode: string, segment: string) => Promise<SatoriOptions["fonts"] | string | undefined>;
// Options that will be passed to the HTTP response
status ? : number = 200
statusText ? : string
headers ? : Record<string, string>
})
```bash
npm run build
```
## Changelog
You can preview the production build with `npm run preview`.
### v1.2.3 Update (Breaking Changes)
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
> Now you have to install dependency by yourself which will make it easier to build for all plateforms.
## 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
```
npm i @resvg/resvg-js
```
```
npm i satori
```
> From now on their will be no issues related to build, and soon this library going to have its own documentation.
### v1.2.2 Update (Breaking Change)
- We don't provide access to satori from `@ethercorps/sveltekit-og`.
### v1.0.0 Update (Breaking Changes)
Finally, We have added html to react like element like object converter out of the box and with svelte compiler.
Now you can use `{ toReactElement }` with `"@ethercorps/sveltekit-og"` like:
- We have changed to function based instead of class based ImageResponse and componentToImageResponse.
- Removed `@resvg/resvg-wasm` with `@resvg/resvg-js` because of internal errors.
- Removed `satori-html` because now we have `toReactElement` out of the box with svelte compiler.
> If you find a problem related to undefined a please check [_vite.config.js_](/vite.config.ts) and add ` define: { _a: 'undefined' } in config.`
> If you find any issue and have suggestion for this project please open a ticket and if you want to contribute please create a new discussion.
## Acknowledgements
This project will not be possible without the following projects:
- [Satori & @vercel/og](https://github.com/vercel/satori)
- [Noto by Google Fonts](https://fonts.google.com/noto)
- [svg2png-wasm](https://github.com/ssssota/svg2png-wasm)
## Authors
- [@theetherGit](https://www.github.com/theetherGit)
- [@etherCorps](https://www.github.com/etherCorps)
## Contributors
- [@jasongitmail](https://github.com/jasongitmail)

View File

@@ -12,7 +12,7 @@
"format": "prettier --plugin-search-dir . --write ."
},
"devDependencies": {
"@ethercorps/sveltekit-og": "link:../../package",
"@ethercorps/sveltekit-og": "link:../../",
"@playwright/test": "^1.34.3",
"@sveltejs/adapter-cloudflare": "^2.3.0",
"@sveltejs/kit": "^1.20.2",

View File

@@ -1,4 +1,4 @@
lockfileVersion: '6.1'
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
@@ -6,8 +6,8 @@ settings:
devDependencies:
'@ethercorps/sveltekit-og':
specifier: link:../../package
version: link:../../package
specifier: link:../../
version: link:../..
'@playwright/test':
specifier: ^1.34.3
version: 1.34.3

View File

@@ -11,19 +11,19 @@
"format": "prettier --plugin-search-dir . --write ."
},
"devDependencies": {
"@ethercorps/sveltekit-og": "link:../../package",
"@playwright/test": "^1.34.3",
"@sveltejs/adapter-cloudflare-workers": "^1.1.2",
"@sveltejs/adapter-static": "^2.0.2",
"@sveltejs/kit": "^1.20.2",
"eslint": "^8.42.0",
"eslint-config-prettier": "^8.8.0",
"@ethercorps/sveltekit-og": "link:../..",
"@playwright/test": "^1.37.1",
"@sveltejs/adapter-cloudflare-workers": "^1.1.4",
"@sveltejs/adapter-static": "^2.0.3",
"@sveltejs/kit": "^1.24.0",
"eslint": "^8.48.0",
"eslint-config-prettier": "^8.10.0",
"eslint-plugin-svelte3": "^4.0.0",
"prettier": "^2.8.8",
"prettier-plugin-svelte": "^2.10.1",
"svelte": "^3.59.1",
"vite": "^4.3.9",
"url": "^0.11.0"
"svelte": "^3.59.2",
"url": "^0.11.1",
"vite": "^4.4.9"
},
"type": "module"
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,69 +1,56 @@
{
"name": "@ethercorps/sveltekit-og",
"version": "2.0.1",
"private": false,
"name": "sveltekit-og",
"version": "0.0.1",
"scripts": {
"dev": "vite dev --host",
"build:prod": "vite build",
"build": "svelte-kit sync && svelte-package",
"dev": "vite dev",
"build": "vite build && npm run package",
"preview": "vite preview",
"prepublishOnly": "echo 'Did you mean to publish `./package/`, instead of `./`?' && exit 1",
"test:build": "pnpm build && pnpm test:vercel:build && pnpm test:netlify:build && pnpm test:pages:build && pnpm test:workers:build && pnpm test:node:build",
"test:vercel:build": "cd examples/vercel-build && pnpm install && pnpm build",
"test:netlify:build": "cd examples/netlify-build && pnpm install && pnpm build",
"test:pages:build": "cd examples/cf-page-build && pnpm install && pnpm build",
"test:workers:build": "cd examples/cf-workers-build && pnpm install && pnpm build",
"test:node:build": "cd examples/node-build && pnpm install && pnpm build",
"test": "playwright test",
"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 ."
},
"devDependencies": {
"@builder.io/partytown": "^0.8.0",
"@playwright/test": "^1.37.1",
"@sveltejs/adapter-auto": "next",
"@sveltejs/adapter-vercel": "^2.4.3",
"@sveltejs/kit": "^1.24.0",
"@sveltejs/package": "2.2.2",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"autoprefixer": "^10.4.15",
"brace": "^0.11.1",
"eslint": "^8.48.0",
"eslint-config-prettier": "^8.10.0",
"eslint-plugin-svelte": "^2.33.0",
"postcss": "^8.4.29",
"prettier": "^2.8.8",
"prettier-plugin-svelte": "^2.10.1",
"prism-svelte": "^0.5.0",
"prismjs": "^1.29.0",
"svelte": "^4.2.0",
"svelte-check": "^3.5.1",
"svelte-preprocess": "^5.0.4",
"tailwindcss": "^3.3.3",
"tslib": "^2.6.2",
"typescript": "^5.2.2",
"vite": "^4.4.9"
"exports": {
".": {
"types": "./dist/index.d.ts",
"svelte": "./dist/index.js"
}
},
"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"
},
"svelte": "./dist/index.js",
"types": "./dist/index.d.ts",
"type": "module",
"dependencies": {
"satori": "^0.10.3",
"svg2png-wasm": "^1.4.0"
},
"keywords": [
"open graph image",
"open graph",
"og image",
"og:image",
"social",
"card",
"sveltekit og",
"sveltekit-og",
"@ethercorps/sveltekit-og"
],
"license": "MIT",
"repository": "https://github.com/etherCorps/sveltekit-og",
"homepage": "https://github.com/etherCorps/sveltekit-og#readme"
"@vercel/og": "^0.5.17",
"satori-html": "^0.3.2"
}
}

View File

@@ -1,10 +0,0 @@
import type { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
webServer: {
command: 'npm run build && npm run preview',
port: 4173
}
};
export default config;

1561
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +0,0 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
};

View File

@@ -1,14 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@font-face {
font-family: 'Ian Mono';
src: url('/iaw-mono-var.woff2') format('woff2');
}
@layer base {
html {
font-family: Ian Mono, monospace;
}
}

17
src/app.d.ts vendored
View File

@@ -1,11 +1,12 @@
/// <reference types="@sveltejs/kit" />
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
// and what to do when importing types
declare namespace App {
// interface Locals {}
// interface PageData {}
// interface Error {}
// interface Platform {}
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface Platform {}
}
}
export {};

View File

@@ -2,36 +2,11 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/logo.webp" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- HTML Meta Tags -->
<title>@ethercorps/sveltekit-og</title>
<meta name="description" content="Demo example for @ethercorps/sveltekit-og" />
<!-- Facebook Meta Tags -->
<meta property="og:url" content="https://sveltekit-og.ethercorps.io/" />
<meta property="og:type" content="website" />
<meta property="og:title" content="@ethercorps/sveltekit-og" />
<meta
property="og:description"
content="A typescript implementation of vercel/og for sveltekit. Dynamically generate Open Graph images from an HTML+CSS template or Svelte component using fast and efficient conversion from HTML > SVG > PNG. Based on Satori. No headless browser required."
/>
<meta property="og:image" content="https://sveltekit-og.ethercorps.io/og?w=1200&h=630" />
<!-- Twitter Meta Tags -->
<meta name="twitter:card" content="https://sveltekit-og.ethercorps.io/" />
<meta property="twitter:domain" content="sveltekit-og.ethercorps.io" />
<meta property="twitter:url" content="https://sveltekit-og.ethercorps.io/" />
<meta name="twitter:title" content="undefined" />
<meta
name="twitter:description"
content="A typescript implementation of vercel/og for sveltekit. Dynamically generate Open Graph images from an HTML+CSS template or Svelte component using fast and efficient conversion from HTML > SVG > PNG. Based on Satori. No headless browser required."
/>
<meta name="twitter:image" content="https://sveltekit-og.ethercorps.io/og?w=1200&h=675" />
%sveltekit.head%
</head>
<body>
<body data-sveltekit-preload-data="hover">
<div>%sveltekit.body%</div>
</body>
</html>

View File

@@ -1,72 +0,0 @@
<script>
let menuBar = false;
</script>
<!-- navbar goes here -->
<nav class="bg-gray-100">
<div class="max-w-full mx-auto px-4">
<div class="flex justify-between">
<div class="flex space-x-4">
<!-- logo -->
<div>
<a
href="#"
class="flex items-center py-5 px-2 text-gray-700 hover:text-gray-900 space-x-3"
>
<svg viewBox="0 0 75 65" fill="black" class="w-4 h-4 rotate-90">
<path d="M37.59.25l36.95 64H.64l36.95-64z" />
</svg>
<span class="font-bold">Sveltekit-OG</span>
</a>
</div>
</div>
<!-- secondary nav -->
<div class="hidden md:flex items-center space-x-1">
<a
href="https://github.com/etherCorps/sveltekit-og/#readme"
target="_blank"
rel="noreferrer"
class="py-5 px-3 underline">Docs</a
>
<a
href="https://github.com/etherCorps/sveltekit-og"
target="_blank"
rel="noreferrer"
class="py-5 px-3 underline">Github</a
>
</div>
<!-- mobile button goes here -->
<div class="md:hidden flex items-center">
<button
class="mobile-menu-button"
on:click={() => {
menuBar = !menuBar;
}}
>
<svg
class="w-6 h-6"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"
/>
</svg>
</button>
</div>
</div>
</div>
<!-- mobile menu -->
<div class="mobile-menu {menuBar ? '' : 'hidden'} md:hidden">
<a href="#" class="block py-2 px-4 text-sm hover:bg-gray-200">Docs</a>
<a href="#" class="block py-2 px-4 text-sm hover:bg-gray-200">Github</a>
</div>
</nav>

7
src/index.test.ts Normal file
View File

@@ -0,0 +1,7 @@
import { describe, it, expect } from 'vitest';
describe('sum test', () => {
it('adds 1 + 2 to equal 3', () => {
expect(1 + 2).toBe(3);
});
});

78
src/lib/api.ts Normal file
View File

@@ -0,0 +1,78 @@
import { html } from "satori-html";
import {ImageResponse as IR} from "@vercel/og"
import type {SvelteComponent} from "svelte";
export const ImageResponse = async (htmlTemplate: string, options?: ImageResponseOptions) => {
const reactVNode = html(`${htmlTemplate}`);
console.log(reactVNode)
return new IR(reactVNode, options)
};
export const componentToImageResponse = async (component: SvelteComponent, props: Record<string, any>, options?: ImageResponseOptions) => {
const ssrSvelte = component.render(props);
console.log(ssrSvelte);
return ImageResponse(`${ssrSvelte.html}<style>${ssrSvelte.css.code}</style>`, options)
};
declare const apis: {
twemoji: (code: any) => string;
openmoji: string;
blobmoji: string;
noto: string;
fluent: (code: any) => string;
fluentFlat: (code: any) => string;
};
declare type EmojiType = keyof typeof apis;
type Weight = 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;
type Style$1 = 'normal' | 'italic';
interface FontOptions {
data: Buffer | ArrayBuffer;
name: string;
weight?: Weight;
style?: Style$1;
lang?: string;
}
export declare type ImageResponseOptions = ImageOptions & ConstructorParameters<typeof Response>[1];
declare type ImageOptions = {
/**
* The width of the image.
*
* @type {number}
* @default 1200
*/
width?: number;
/**
* The height of the image.
*
* @type {number}
* @default 630
*/
height?: number;
/**
* Display debug information on the image.
*
* @type {boolean}
* @default false
*/
debug?: boolean;
/**
* A list of fonts to use.
*
* @type {{ data: ArrayBuffer; name: string; weight?: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900; style?: 'normal' | 'italic' }[]}
* @default Noto Sans Latin Regular.
*/
fonts?: FontOptions[];
/**
* Using a specific Emoji style. Defaults to `twemoji`.
*
* @link https://github.com/vercel/og#emoji
* @type {EmojiType}
* @default 'twemoji'
*/
emoji?: EmojiType;
};

View File

@@ -1,98 +1 @@
import satori, { type SatoriOptions } from 'satori';
import type { SvelteComponent } from 'svelte';
import toReactElement from './toReactElement.js';
import { svg2png, initialize, type ConvertOptions } from 'svg2png-wasm';
let initialized = false;
const fontFile = await fetch('https://sveltekit-og.ethercorps.io/noto-sans.ttf');
const fontData: ArrayBuffer = await fontFile.arrayBuffer();
const indexWasmRes = await fetch('https://unpkg.com/svg2png-wasm/svg2png_wasm_bg.wasm');
const svg2PngWasmBuffer = await indexWasmRes.arrayBuffer();
const initSvgToPng = async () => {
await initialize(svg2PngWasmBuffer).catch((e) => console.log(e));
initialized = true;
};
const ImageResponse = async (htmlTemplate: string, optionsByUser: ImageResponseOptions) => {
const options = Object.assign({ width: 1200, height: 630, debug: !1 }, optionsByUser);
const svg = await satori(toReactElement(htmlTemplate), {
width: options.width,
height: options.height,
debug: options.debug,
fonts: options.fonts || [
{
name: 'sans serif',
data: fontData,
style: 'normal',
weight: 700
}
]
});
if (!initialized) {
await initSvgToPng();
initialized = true;
}
const defaultConfig: ConvertOptions = {
width: options.width, // optional
height: options.height // optional
};
if (Object.hasOwn(options, 'backgroundColor')) {
defaultConfig.backgroundColor = options.backgroundColor;
}
const png = await svg2png(svg, defaultConfig);
return new Response(png, {
headers: {
'Content-Type': 'image/png',
'cache-control': 'public, immutable, no-transform, max-age=31536000',
...options.headers
},
status: options.status,
statusText: options.statusText
});
};
const componentToImageResponse = (
component: typeof SvelteComponent<any>,
props = {},
optionsByUser: ImageResponseOptions
) => {
const htmlTemplate = componentToMarkup(component, props);
return ImageResponse(htmlTemplate, optionsByUser);
};
const componentToMarkup = (component: typeof SvelteComponent<any>, props = {}) => {
const SvelteRenderedMarkup = (component as any).render(props);
let htmlTemplate = `${SvelteRenderedMarkup.html}`;
if (SvelteRenderedMarkup && SvelteRenderedMarkup.css && SvelteRenderedMarkup.css.code) {
htmlTemplate = `${SvelteRenderedMarkup.html}<style>${SvelteRenderedMarkup.css.code}</style>`;
}
return htmlTemplate;
};
type ImageResponseOptions = ConstructorParameters<typeof Response>[1] & ImageOptions;
type ImageOptions = {
width?: number;
height?: number;
debug?: boolean;
fonts?: SatoriOptions['fonts'];
backgroundColor?: string;
graphemeImages?: Record<string, string>;
loadAdditionalAsset?: (
languageCode: string,
segment: string
) => Promise<SatoriOptions['fonts'] | string | undefined>;
};
export type ImageResponseType = typeof ImageResponse;
export { componentToImageResponse, ImageResponse, toReactElement };
export {componentToImageResponse, ImageResponse, type ImageResponseOptions} from "./api.js"

View File

@@ -1,107 +0,0 @@
import { parse, walk } from 'svelte/compiler';
import type { Ast } from 'svelte/types/compiler/interfaces';
/* Start of code from satori-html for cssToObject converter*/
const camelize = (ident: string) => ident.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
const cssToObject = (str: string) => {
const obj: Record<string, string> = {};
let t = 0;
let pair = ['', ''];
const flags: Record<string, number> = {};
for (const c of str) {
if (!flags['('] && c === ':') {
t = 1;
} else if (c === ';') {
const [decl = '', value = ''] = pair;
obj[camelize(decl.trim())] = value.trim();
t = 0;
pair = ['', ''];
} else {
pair[t] += c;
switch (c) {
case '(': {
flags[c]++;
break;
}
case ')': {
flags['(']--;
break;
}
}
}
}
const [decl = '', value = ''] = pair;
if (decl.trim() && value.trim()) {
obj[camelize(decl.trim())] = value.trim();
}
return obj;
};
const nodeMap = new WeakMap();
interface VNode {
type: string;
props: {
style?: Record<string, any>;
children?: string | VNode | VNode[];
[prop: string]: any;
};
}
const root: VNode = {
type: 'div',
props: {
style: {
display: 'flex',
flexDirection: 'column',
width: '100%',
height: '100%'
},
children: []
}
};
/* End of satori-html */
export const toReactElement = (htmlString: string): VNode => {
const svelteAST: Ast = parse(htmlString);
walk(svelteAST, {
enter(node: any, parent: any, prop: any, index: any) {
let newNode: any = {};
if (node.type === 'Fragment') {
nodeMap.set(node, root);
} else if (node.type === 'Element') {
newNode.type = node.name;
const { ...props } = node.attributes;
if (node.attributes.length > 0) {
node.attributes.forEach((attribute: any) => {
if (attribute.name === 'style') {
props['style'] = cssToObject(attribute.value[0].data) as any;
} else props[attribute.name] = attribute.value[0].data as any;
});
delete props[0];
}
props.children = [] as unknown as string;
Object.assign(newNode, { props });
nodeMap.set(node, newNode);
if (parent) {
const newParent = nodeMap.get(parent);
newParent.props.children[index] = newNode;
}
} else if (node.type === 'Text') {
newNode = node.data.trim();
if (newNode) {
if (parent && parent.type !== 'Attribute') {
const newParent = nodeMap.get(parent);
if (parent.children.length === 1) {
newParent.props.children = newNode;
} else {
newParent.props.children[index] = newNode;
}
}
}
}
}
});
return root;
};
export default toReactElement;

View File

@@ -1,71 +0,0 @@
<script>
import '../app.css';
import Navbar from '../components/Navbar.svelte';
import { onMount } from 'svelte'
import { partytownSnippet } from '@builder.io/partytown/integration'
// Add the Partytown script to the DOM head
let scriptEl
onMount(
() => {
if (scriptEl) {
scriptEl.textContent = partytownSnippet()
}
}
)
</script>
<svelte:head>
<!-- Config options -->
<script>
// Forward the necessary functions to the web worker layer
partytown = {
forward: ['dataLayer.push'],
resolveUrl: (url) => {
const siteUrl = 'https://sveltekit-og.ethercorps.io/proxytown';
if (url.hostname === 'www.googletagmanager.com') {
const proxyUrl = new URL(`${siteUrl}/gtm`)
const gtmId = new URL(url).searchParams.get('id')
gtmId && proxyUrl.searchParams.append('id', gtmId)
return proxyUrl
} else if (url.hostname === 'www.google-analytics.com') {
const proxyUrl = new URL(`${siteUrl}/ga`)
return proxyUrl
}
return url
}
}
</script>
<!-- `partytownSnippet` is inserted here -->
<script bind:this={scriptEl}></script>
<script
type="text/partytown"
src="https://www.googletagmanager.com/gtag/js?id=G-RQGCXL5D07"></script>
<script type="text/partytown">
window.dataLayer = window.dataLayer || []
function gtag() {
dataLayer.push(arguments)
}
gtag('js', new Date())
gtag('config', 'G-RQGCXL5D07', {
page_path: window.location.pathname
})
</script>
</svelte:head>
<div class="max-h-screen">
<Navbar />
<slot />
</div>

View File

@@ -1,240 +0,0 @@
<script>
import {base} from "$app/paths";
import Prism from 'prismjs';
import 'prism-svelte';
import 'prismjs/themes/prism-tomorrow.css';
const source = `
/src/routes/new/+server.ts
import { ImageResponse } from '@ethercorps/sveltekit-og';
import type { RequestHandler } from '@sveltejs/kit';
const template = \`
<div tw="bg-gray-50 flex w-full h-full items-center justify-center">
<div tw="flex flex-col md:flex-row w-full py-12 px-4 md:items-center justify-between p-8">
<h2 tw="flex flex-col text-3xl sm:text-4xl font-bold tracking-tight text-gray-900 text-left">
<span>Ready to dive in?</span>
<span tw="text-indigo-600">Start your free trial today.</span>
</h2>
<div tw="mt-8 flex md:mt-0">
<div tw="flex rounded-md shadow">
<a href="#" tw="flex items-center justify-center rounded-md border border-transparent bg-indigo-600 px-5 py-3 text-base font-medium text-white">Get started</a>
</div>
<div tw="ml-3 flex rounded-md shadow">
<a href="#" tw="flex items-center justify-center rounded-md border border-transparent bg-white px-5 py-3 text-base font-medium text-indigo-600">Learn more</a>
</div>
</div>
</div>
</div>
\`;
const fontFile400 = await fetch(
'https://raw.githubusercontent.com/etherCorps/sveltekit-og/main/static/inter-latin-ext-400-normal.woff'
);
const fontFile700 = await fetch(
'https://raw.githubusercontent.com/etherCorps/sveltekit-og/main/static/inter-latin-ext-700-normal.woff'
);
const fontData400: ArrayBuffer = await fontFile400.arrayBuffer();
const fontData700: ArrayBuffer = await fontFile700.arrayBuffer();
export const GET: RequestHandler = async () => {
return await ImageResponse(template, {
height: 250,
width: 500,
fonts: [
{
name: 'Inter Latin',
data: fontData400,
weight: 400
},
{
name: 'Inter Latin',
data: fontData700,
weight: 700
}
]
});
};
`;
const apiReference = `
import {ImageResponse, componentToImageResponse} from '@ethercorps/sveltekit-og'
import {SvelteComponent} from "svelte";
// ...
ImageResponse(
element : string,
options : {
width ? : number = 1200
height ? : number = 630,
backgroundColor ? : string = "#fff"
fonts ? : {
name: string,
data: ArrayBuffer,
weight: number,
style: 'normal' | 'italic'
}[]
debug ? : boolean = false
graphemeImages ? : Record<string, string>;
loadAdditionalAsset ? : (languageCode: string, segment: string) => Promise<SatoriOptions["fonts"] | string | undefined>;
// Options that will be passed to the HTTP response
status ? : number = 200
statusText ? : string
headers ? : Record<string, string>
})
componentToImageResponse(
component : typeof SvelteComponent,
props : {}, // All export let example inside prop dictionary
options : {
width ? : number = 1200
height ? : number = 630
fonts ? : {
name: string,
data: ArrayBuffer,
weight: number,
style: 'normal' | 'italic'
}[]
debug ? : boolean = false
graphemeImages ? : Record<string, string>;
loadAdditionalAsset ? : (languageCode: string, segment: string) => Promise<SatoriOptions["fonts"] | string | undefined>;
// Options that will be passed to the HTTP response
status ? : number = 200
statusText ? : string
headers ? : Record<string, string>
})
`;
const highlightedQuickEg = Prism.highlight(source, Prism.languages.svelte, 'svelte');
const highlightedApiReference = Prism.highlight(apiReference, Prism.languages.svelte, 'svelte');
</script>
<div class="mx-10 mt-5 pb-10 space-y-5">
<section id="introduction" class="space-y-3">
<h1 class="font-bold text-2xl">Introduction</h1>
<p class="">
SvelteKit-OG is use to dynamically generate Open Graph images from an HTML+CSS template or
Svelte component using fast and efficient conversion from <br /> HTML > SVG > PNG. Based on Satori.
No headless browser required.
</p>
</section>
<section id="installation" class="space-y-4">
<h1 class="font-bold text-2xl">Installation</h1>
<p>
Use your favourite package manager and add <span class="bg-gray-100 px-2 py-1 rounded-full"
>@ethercorps/sveltekit-og</span
>
as your <span class="bg-gray-100 px-2 py-1 rounded-full">devDependency</span>.
</p>
<div id="pnpm-install-og">
Example:
<code class="border rounded-full bg-gray-100 px-3 py-1.5 text-gray-900">
pnpm i -D @ethercorps/sveltekit-og
</code>
</div>
<div class="border-x-4 border-gray-900 rounded-lg leading-9">
<p class="ml-2">
If you are using it on with <span class="bg-gray-100 px-2 py-1 rounded-full">
cloudflare pages
</span>
or <span class="bg-gray-100 px-2 py-1 rounded-full">cloudflare workers </span> then you have
to provide <span class="bg-gray-100 px-2 py-1 rounded-full">polyfills</span> for
<span class="bg-gray-100 px-2 py-1 rounded-full">url</span>. You can simply add it to your
<span class="bg-gray-100 px-2 py-1 rounded-full">devDependency</span>,
<br /> To install
<code class="border rounded-full bg-gray-100 px-3 py-1.5 text-gray-900">
pnpm i -D url
</code>
</p>
</div>
</section>
<section id="usage" class="space-y-3">
<h1 class="font-bold text-2xl">Usage</h1>
<p class="">
Create a file at <span class="bg-gray-100 px-2 py-1 rounded-full">
/src/routes/og/+server.ts
</span>. Alternatively, you can use JavaScript by removing the types from this example.
</p>
<div class="border-x-4 border-gray-900 rounded-lg w-fit px-2 leading-9">
<p class="ml-2">
Route can be anything but it should have only one file
<span class="bg-gray-100 px-2 py-1 rounded-full"> +server.ts </span>
</p>
</div>
<pre class="bg-gray-100 overflow-auto px-3 py-1.5 rounded-xl"><code class="" >{@html highlightedQuickEg}</code></pre>
<div class="border-x-4 border-gray-900 rounded-lg w-fit px-2 leading-9">
<p class="ml-2">
Then run <span class="bg-gray-100 px-2 py-1 rounded-full"> pnpm run dev </span> and visit <span class="bg-gray-100 px-2 py-1 rounded-full"> localhost:5173/og </span> to view your generated PNG. Remember that hot module reloading does not work with server routes, so if you change your HTML or CSS, hard refresh the route to see changes.
</p>
</div>
<h2 class="font-bold text-xl">
Image Output: <a target="_blank" class="hover:text-indigo-500 transition-all" rel="noreferrer" href="https://sveltekit-og.ethercorps.io/new"> Live Version</a>
<img loading="lazy" class="rounded-lg mt-5 shadow-lg shadow-indigo-200" src="https://sveltekit-og.ethercorps.io/new" alt="@ethercorps/sveltekit-og Demo OG Generated PNG" />
</h2>
</section>
<section id="headers" class="space-y-3">
<h1 class="font-bold text-2xl">Headers</h1>
<p class="">
Notice that our example uses TailwindCSS classes (e.g. <span class="bg-gray-100 px-2 py-1 rounded-full">tw="bg-gray-50"</span>). Alternatively, your HTML can contain style attributes using any of <a href="https://github.com/vercel/satori#css" target="_blank" rel="noreferrer" class="text-indigo-500">the subset of CSS supported by Satori</a>.
<br />
<br />
Satori supports only a subset of HTML and CSS. For full details, see <a href="https://github.com/vercel/satori#documentation" target="_blank" rel="noreferrer" class="text-indigo-500">Satoris documentation</a>. Notably, Satori only supports flex-based layouts.
</p>
</section>
<section id="fonts" class="space-y-3">
<h1 class="font-bold text-2xl">Fonts</h1>
<p class="">
Satori supports <span class="bg-gray-100 px-2 py-1 rounded-full">ttf</span>, <span class="bg-gray-100 px-2 py-1 rounded-full">otf</span>, and <span class="bg-gray-100 px-2 py-1 rounded-full">woff</span> font formats; <span class="bg-gray-100 px-2 py-1 rounded-full">woff2</span> is not supported. To maximize the font parsing speed, <span class="bg-gray-100 px-2 py-1 rounded-full">ttf</span> or <span class="bg-gray-100 px-2 py-1 rounded-full">otf</span> are recommended over <span class="bg-gray-100 px-2 py-1 rounded-full">woff</span>.
<br />
<br />
By default, <span class="bg-gray-100 px-2 py-1 rounded-full">@ethercorps/sveltekit-og</span> includes only 'Noto Sans' font. If you need to use other fonts, you can specify them as shown in the example. Notably, you can also import a font file that is stored locally within your project and are not required to use fetch.
</p>
</section>
<section id="examples" class="space-y-3">
<h1 class="font-bold text-2xl">Examples</h1>
<li><span class="bg-gray-100 px-2 py-1 rounded-full">ImageResponse</span> - <a href="https://github.com/etherCorps/sveltekit-og/blob/main/src/routes/new/+server.ts" target="_blank" rel="noreferrer" class="text-indigo-500">Source</a> - <a href="https://sveltekit-og-five.vercel.app/new" target="_blank" rel="noreferrer" class="text-indigo-500">Demo</a></li>
<li><span class="bg-gray-100 px-2 py-1 rounded-full">componentToImageResponse</span> - <a href="https://github.com/etherCorps/sveltekit-og/tree/main/src/routes/component-og" target="_blank" rel="noreferrer" class="text-indigo-500">Source</a> - <a href="https://sveltekit-og-five.vercel.app/component-og" target="_blank" rel="noreferrer" class="text-indigo-500">Demo</a></li>
</section>
<section id="api-reference" class="space-y-3">
<h1 class="font-bold text-2xl">Api Reference</h1>
<p>
The package exposes an <span class="bg-gray-100 px-2 py-1 rounded-full">ImageResponse</span> and <span class="bg-gray-100 px-2 py-1 rounded-full">componentToImageResponse</span> constructors, with the following options available.
</p>
<pre class="bg-gray-100 overflow-auto px-3 py-1.5 rounded-xl"><code class="" >{@html highlightedApiReference}</code></pre>
</section>
<div id="footer" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 place-content-evenly">
<section id="acknowledgements" class="space-y-3 bg-indigo-50 px-3 py-1.5 shadow-md w-full shadow-indigo-500 rounded-lg border border-indigo-500">
<h1 class="font-bold text-2xl">Acknowledgements</h1>
<p>This project will not be possible without the following projects:</p>
<li><a href="https://github.com/vercel/satori" target="_blank" rel="noreferrer" class="text-indigo-500">Satori & Vercel-OG</a></li>
<li><a href="https://fonts.google.com/noto" target="_blank" rel="noreferrer" class="text-indigo-500">Noto by Google Fonts</a></li>
<li><a href="https://github.com/ssssota/svg2png-wasm" target="_blank" rel="noreferrer" class="text-indigo-500">svg2png-wasm</a></li>
</section>
<section id="author" class="space-y-3 bg-indigo-50 px-3 py-1.5 shadow-md w-full shadow-indigo-500 rounded-lg border border-indigo-500">
<h1 class="font-bold text-2xl">Author</h1>
<p>I would like to thank myself:</p>
<li><a href="https://github.com/etherCorps" target="_blank" rel="noreferrer" class="text-indigo-500">@ethercorps</a></li>
<li><a href="https://github.com/theetherGit" target="_blank" rel="noreferrer" class="text-indigo-500">@theetherGit</a></li>
</section>
<section id="contributors" class="space-y-3 bg-indigo-50 px-3 py-1.5 shadow-md w-full shadow-indigo-500 rounded-lg border border-indigo-500">
<h1 class="font-bold text-2xl">Contributors</h1>
<p>Without your commits, support, ideas and works every library is incomplete. So, special thanks to:</p>
<li><a href="https://github.com/jasongitmail" target="_blank" rel="noreferrer" class="text-indigo-500">@jasongitmail</a></li>
</section>
</div>
</div>

View File

@@ -1 +0,0 @@
export let prerender = true

7
src/routes/+server.ts Normal file
View File

@@ -0,0 +1,7 @@
import type {RequestHandler} from "@sveltejs/kit";
import {ImageResponse} from "$lib";
export const GET: RequestHandler = async () => {
const html = '<div style="color: black; background: aqua; height: 100vh;">hello, world</div>';
return ImageResponse(html)
};

View File

@@ -1,26 +0,0 @@
import OG from './OG.svelte';
import { componentToImageResponse } from '$lib';
import type { RequestHandler } from '@sveltejs/kit';
const fontFile = await fetch(
'https://raw.githubusercontent.com/etherCorps/sveltekit-og/main/static/inter-latin-ext-700-normal.woff'
);
const fontData: ArrayBuffer = await fontFile.arrayBuffer();
export const GET: RequestHandler = async () => {
return await componentToImageResponse(
OG,
{ text: 'Ready to dive in?', spanText: 'Start your free trial today.' },
{
height: 250,
width: 500,
fonts: [
{
name: 'Inter Latin',
data: fontData,
weight: 700
}
]
}
);
};

View File

@@ -1,29 +0,0 @@
<script>
export let text;
export let spanText;
</script>
<div tw="bg-gray-50 flex w-full h-full items-center justify-center">
<div tw="flex flex-col md:flex-row w-full py-12 px-4 md:items-center justify-between p-8">
<h2 tw="flex flex-col text-3xl sm:text-4xl font-bold tracking-tight text-gray-900 text-left">
<span>{text}</span>
<span tw="text-indigo-600">{spanText}</span>
</h2>
<div tw="mt-8 flex md:mt-0">
<div tw="flex rounded-md shadow">
<a
href="#"
tw="flex items-center justify-center rounded-md border border-transparent bg-indigo-600 px-5 py-3 text-base font-medium text-white"
>Get started</a
>
</div>
<div tw="ml-3 flex rounded-md shadow">
<a
href="#"
tw="flex items-center justify-center rounded-md border border-transparent bg-white px-5 py-3 text-base font-medium text-indigo-600"
>Learn more</a
>
</div>
</div>
</div>
</div>

View File

@@ -1,50 +0,0 @@
`/src/routes/new/+server.ts`
import { ImageResponse } from '$lib';
import type { RequestHandler } from '@sveltejs/kit';
const template = `
<div tw="bg-gray-50 flex w-full h-full items-center justify-center">
<div tw="flex flex-col md:flex-row w-full py-12 px-4 md:items-center justify-between p-8">
<h2 tw="flex flex-col text-3xl sm:text-4xl font-bold tracking-tight text-gray-900 text-left">
<span>Ready to dive in?</span>
<span tw="text-indigo-600">Start your free trial today.</span>
</h2>
<div tw="mt-8 flex md:mt-0">
<div tw="flex rounded-md shadow">
<a href="#" tw="flex items-center justify-center rounded-md border border-transparent bg-indigo-600 px-5 py-3 text-base font-medium text-white">Get started</a>
</div>
<div tw="ml-3 flex rounded-md shadow">
<a href="#" tw="flex items-center justify-center rounded-md border border-transparent bg-white px-5 py-3 text-base font-medium text-indigo-600">Learn more</a>
</div>
</div>
</div>
</div>
`;
const fontFile400 = await fetch(
'https://raw.githubusercontent.com/etherCorps/sveltekit-og/main/static/inter-latin-ext-400-normal.woff'
);
const fontFile700 = await fetch(
'https://raw.githubusercontent.com/etherCorps/sveltekit-og/main/static/inter-latin-ext-700-normal.woff'
);
const fontData400: ArrayBuffer = await fontFile400.arrayBuffer();
const fontData700: ArrayBuffer = await fontFile700.arrayBuffer();
export const GET: RequestHandler = async () => {
return await ImageResponse(template, {
height: 250,
width: 500,
fonts: [
{
name: 'Inter Latin',
data: fontData400,
weight: 400
},
{
name: 'Inter Latin',
data: fontData700,
weight: 700
}
]
});
};

View File

@@ -1,19 +0,0 @@
import type {RequestHandler} from "@sveltejs/kit";
import {ImageResponse} from "$lib";
import {to_number} from "svelte/internal";
const htmlSrc = `
<div style="display: flex; height: 100%; width: 100%; align-items: center; justify-content: center; flex-direction: column; background-image: linear-gradient(to bottom, #dbf4ff, #fff1f1); font-size: 60px; letter-spacing: -2px; font-weight: 700; text-align: center;">
<div style="background-image: linear-gradient(90deg, rgb(0, 124, 240, 1), rgb(0, 223, 216)); background-clip: text; -webkit-background-clip: text; color: transparent;">Design</div>
<div style="background-image: linear-gradient(90deg, rgb(121, 40, 202, 1), rgb(255, 0, 128)); background-clip: text; -webkit-background-clip: text; color: transparent;">Develop</div>
<div style="background-image: linear-gradient(90deg, rgb(255, 77, 77, 1), rgb(249, 203, 40)); background-clip: text; -webkit-background-clip: text; color: transparent;">SvelteKit OG</div>
</div>
`;
export const GET: RequestHandler = async ({request, url}) => {
return ImageResponse(htmlSrc, {
width: to_number(url.searchParams.get('w')) || 600,
height: to_number(url.searchParams.get('h')) || 420,
})
};

10
src/routes/sc/+server.ts Normal file
View File

@@ -0,0 +1,10 @@
import type {RequestHandler} from "@sveltejs/kit";
import {componentToImageResponse} from "$lib";
import OG from "./OG.svelte";
export const GET: RequestHandler = async () => {
return await componentToImageResponse(
OG,
{ text: 'Ready to dive in?', spanText: 'Start your free trial today.' }
);
};

29
src/routes/sc/OG.svelte Normal file
View File

@@ -0,0 +1,29 @@
<script>
export let text;
export let spanText;
</script>
<div tw="bg-gray-50 flex w-full h-full items-center justify-center">
<div tw="flex flex-col md:flex-row w-full py-12 px-4 md:items-center justify-between p-8">
<h2 tw="flex flex-col text-3xl sm:text-4xl font-bold tracking-tight text-gray-900 text-left">
<span>{text}</span>
<span tw="text-indigo-600">{spanText}</span>
</h2>
<div tw="mt-8 flex md:mt-0">
<div tw="flex rounded-md shadow">
<a
href="#"
tw="flex items-center justify-center rounded-md border border-transparent bg-indigo-600 px-5 py-3 text-base font-medium text-white"
>Get started</a
>
</div>
<div tw="ml-3 flex rounded-md shadow">
<a
href="#"
tw="flex items-center justify-center rounded-md border border-transparent bg-white px-5 py-3 text-base font-medium text-indigo-600"
>Learn more</a
>
</div>
</div>
</div>
</div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

View File

@@ -1,572 +0,0 @@
/* Partytown 0.8.0 - MIT builder.io */
(window => {
const isPromise = v => "object" == typeof v && v && v.then;
const noop = () => {};
const len = obj => obj.length;
const getConstructorName = obj => {
var _a, _b, _c;
try {
const constructorName = null === (_a = null == obj ? void 0 : obj.constructor) || void 0 === _a ? void 0 : _a.name;
if (constructorName) {
return constructorName;
}
} catch (e) {}
try {
const zoneJsConstructorName = null === (_c = null === (_b = null == obj ? void 0 : obj.__zone_symbol__originalInstance) || void 0 === _b ? void 0 : _b.constructor) || void 0 === _c ? void 0 : _c.name;
if (zoneJsConstructorName) {
return zoneJsConstructorName;
}
} catch (e) {}
return "";
};
const startsWith = (str, val) => str.startsWith(val);
const isValidMemberName = memberName => !(startsWith(memberName, "webkit") || startsWith(memberName, "toJSON") || startsWith(memberName, "constructor") || startsWith(memberName, "toString") || startsWith(memberName, "_"));
const getNodeName = node => 11 === node.nodeType && node.host ? "#s" : node.nodeName;
const randomId = () => Math.round(Math.random() * Number.MAX_SAFE_INTEGER).toString(36);
const defineConstructorName = (Cstr, value) => ((obj, memberName, descriptor) => Object.defineProperty(obj, memberName, {
...descriptor,
configurable: true
}))(Cstr, "name", {
value: value
});
const htmlConstructorTags = {
Anchor: "a",
DList: "dl",
Image: "img",
OList: "ol",
Paragraph: "p",
Quote: "q",
TableCaption: "caption",
TableCell: "td",
TableCol: "colgroup",
TableRow: "tr",
TableSection: "tbody",
UList: "ul"
};
const svgConstructorTags = {
Graphics: "g",
SVG: "svg"
};
const InstanceIdKey = Symbol();
const CreatedKey = Symbol();
const instances = new Map;
const mainRefs = new Map;
const winCtxs = {};
const windowIds = new WeakMap;
const getAndSetInstanceId = (instance, instanceId) => {
if (instance) {
if (instanceId = windowIds.get(instance)) {
return instanceId;
}
(instanceId = instance[InstanceIdKey]) || setInstanceId(instance, instanceId = randomId());
return instanceId;
}
};
const getInstance = (winId, instanceId, win, doc, docId) => {
if ((win = winCtxs[winId]) && win.$window$) {
if (winId === instanceId) {
return win.$window$;
}
doc = win.$window$.document;
docId = instanceId.split(".").pop();
if ("d" === docId) {
return doc;
}
if ("e" === docId) {
return doc.documentElement;
}
if ("h" === docId) {
return doc.head;
}
if ("b" === docId) {
return doc.body;
}
}
return instances.get(instanceId);
};
const setInstanceId = (instance, instanceId, now) => {
if (instance) {
instances.set(instanceId, instance);
instance[InstanceIdKey] = instanceId;
instance[CreatedKey] = now = Date.now();
if (now > lastCleanup + 5e3) {
instances.forEach(((storedInstance, instanceId) => {
storedInstance[CreatedKey] < lastCleanup && storedInstance.nodeType && !storedInstance.isConnected && instances.delete(instanceId);
}));
lastCleanup = now;
}
}
};
let lastCleanup = 0;
const mainWindow = window.parent;
const docImpl = document.implementation.createHTMLDocument();
const config = mainWindow.partytown || {};
const libPath = (config.lib || "/~partytown/") + "debug/";
const logMain = msg => {
console.debug.apply(console, [ "%cMain 🌎", "background: #717171; color: white; padding: 2px 3px; border-radius: 2px; font-size: 0.8em;", msg ]);
};
const winIds = [];
const normalizedWinId = winId => {
winIds.includes(winId) || winIds.push(winId);
return winIds.indexOf(winId) + 1;
};
const defineCustomElement = (winId, worker, ceData) => {
const Cstr = defineConstructorName(class extends winCtxs[winId].$window$.HTMLElement {}, ceData[0]);
const ceCallbackMethods = "connectedCallback,disconnectedCallback,attributeChangedCallback,adoptedCallback".split(",");
ceCallbackMethods.map((callbackMethodName => Cstr.prototype[callbackMethodName] = function(...args) {
worker.postMessage([ 15, winId, getAndSetInstanceId(this), callbackMethodName, args ]);
}));
Cstr.observedAttributes = ceData[1];
return Cstr;
};
const serializeForWorker = ($winId$, value, added, type, cstrName, prevInstanceId) => void 0 !== value && (type = typeof value) ? "string" === type || "number" === type || "boolean" === type || null == value ? [ 0, value ] : "function" === type ? [ 6 ] : (added = added || new Set) && Array.isArray(value) ? added.has(value) ? [ 1, [] ] : added.add(value) && [ 1, value.map((v => serializeForWorker($winId$, v, added))) ] : "object" === type ? serializedValueIsError(value) ? [ 14, {
name: value.name,
message: value.message,
stack: value.stack
} ] : "" === (cstrName = getConstructorName(value)) ? [ 2, {} ] : "Window" === cstrName ? [ 3, [ $winId$, $winId$ ] ] : "HTMLCollection" === cstrName || "NodeList" === cstrName ? [ 7, Array.from(value).map((v => serializeForWorker($winId$, v, added)[1])) ] : cstrName.endsWith("Event") ? [ 5, serializeObjectForWorker($winId$, value, added) ] : "CSSRuleList" === cstrName ? [ 12, Array.from(value).map(serializeCssRuleForWorker) ] : startsWith(cstrName, "CSS") && cstrName.endsWith("Rule") ? [ 11, serializeCssRuleForWorker(value) ] : "CSSStyleDeclaration" === cstrName ? [ 13, serializeObjectForWorker($winId$, value, added) ] : "Attr" === cstrName ? [ 10, [ value.name, value.value ] ] : value.nodeType ? [ 3, [ $winId$, getAndSetInstanceId(value), getNodeName(value), prevInstanceId ] ] : [ 2, serializeObjectForWorker($winId$, value, added, true, true) ] : void 0 : value;
const serializeObjectForWorker = (winId, obj, added, includeFunctions, includeEmptyStrings, serializedObj, propName, propValue) => {
serializedObj = {};
if (!added.has(obj)) {
added.add(obj);
for (propName in obj) {
if (isValidMemberName(propName)) {
propValue = "path" === propName && getConstructorName(obj).endsWith("Event") ? obj.composedPath() : obj[propName];
(includeFunctions || "function" != typeof propValue) && (includeEmptyStrings || "" !== propValue) && (serializedObj[propName] = serializeForWorker(winId, propValue, added));
}
}
}
return serializedObj;
};
const serializeCssRuleForWorker = cssRule => {
let obj = {};
let key;
for (key in cssRule) {
validCssRuleProps.includes(key) && (obj[key] = String(cssRule[key]));
}
return obj;
};
const serializedValueIsError = value => value instanceof window.top.Error;
const deserializeFromWorker = (worker, serializedTransfer, serializedType, serializedValue) => {
if (serializedTransfer) {
serializedType = serializedTransfer[0];
serializedValue = serializedTransfer[1];
return 0 === serializedType ? serializedValue : 4 === serializedType ? deserializeRefFromWorker(worker, serializedValue) : 1 === serializedType ? serializedValue.map((v => deserializeFromWorker(worker, v))) : 3 === serializedType ? getInstance(serializedValue[0], serializedValue[1]) : 5 === serializedType ? constructEvent(deserializeObjectFromWorker(worker, serializedValue)) : 2 === serializedType ? deserializeObjectFromWorker(worker, serializedValue) : 8 === serializedType ? serializedValue : 9 === serializedType ? new window[serializedTransfer[2]](serializedValue) : void 0;
}
};
const deserializeRefFromWorker = (worker, {$winId$: $winId$, $instanceId$: $instanceId$, $refId$: $refId$}, ref) => {
ref = mainRefs.get($refId$);
if (!ref) {
ref = function(...args) {
worker.postMessage([ 9, {
$winId$: $winId$,
$instanceId$: $instanceId$,
$refId$: $refId$,
$thisArg$: serializeForWorker($winId$, this),
$args$: serializeForWorker($winId$, args)
} ]);
};
mainRefs.set($refId$, ref);
}
return ref;
};
const constructEvent = eventProps => new ("detail" in eventProps ? CustomEvent : Event)(eventProps.type, eventProps);
const deserializeObjectFromWorker = (worker, serializedValue, obj, key) => {
obj = {};
for (key in serializedValue) {
obj[key] = deserializeFromWorker(worker, serializedValue[key]);
}
return obj;
};
const validCssRuleProps = "cssText,selectorText,href,media,namespaceURI,prefix,name,conditionText".split(",");
const mainAccessHandler = async (worker, accessReq) => {
let accessRsp = {
$msgId$: accessReq.$msgId$
};
let totalTasks = len(accessReq.$tasks$);
let i = 0;
let task;
let winId;
let applyPath;
let instance;
let rtnValue;
let isLast;
for (;i < totalTasks; i++) {
try {
isLast = i === totalTasks - 1;
task = accessReq.$tasks$[i];
winId = task.$winId$;
applyPath = task.$applyPath$;
!winCtxs[winId] && winId.startsWith("f_") && await new Promise((resolve => {
let check = 0;
let callback = () => {
winCtxs[winId] || check++ > 1e3 ? resolve() : requestAnimationFrame(callback);
};
callback();
}));
if (1 === applyPath[0] && applyPath[1] in winCtxs[winId].$window$) {
setInstanceId(new winCtxs[winId].$window$[applyPath[1]](...deserializeFromWorker(worker, applyPath[2])), task.$instanceId$);
} else {
instance = getInstance(winId, task.$instanceId$);
if (instance) {
rtnValue = applyToInstance(worker, winId, instance, applyPath, isLast, task.$groupedGetters$);
task.$assignInstanceId$ && ("string" == typeof task.$assignInstanceId$ ? setInstanceId(rtnValue, task.$assignInstanceId$) : winCtxs[task.$assignInstanceId$.$winId$] = {
$winId$: task.$assignInstanceId$.$winId$,
$window$: {
document: rtnValue
}
});
if (isPromise(rtnValue)) {
rtnValue = await rtnValue;
isLast && (accessRsp.$isPromise$ = true);
}
isLast && (accessRsp.$rtnValue$ = serializeForWorker(winId, rtnValue, void 0, void 0, void 0, task.$instanceId$));
} else {
accessRsp.$error$ = `Error finding instance "${task.$instanceId$}" on window ${normalizedWinId(winId)}`;
console.error(accessRsp.$error$, task);
}
}
} catch (e) {
isLast ? accessRsp.$error$ = String(e.stack || e) : console.error(e);
}
}
return accessRsp;
};
const applyToInstance = (worker, winId, instance, applyPath, isLast, groupedGetters) => {
let i = 0;
let l = len(applyPath);
let next;
let current;
let previous;
let args;
let groupedRtnValues;
for (;i < l; i++) {
current = applyPath[i];
next = applyPath[i + 1];
previous = applyPath[i - 1];
try {
if (!Array.isArray(next)) {
if ("string" == typeof current || "number" == typeof current) {
if (i + 1 === l && groupedGetters) {
groupedRtnValues = {};
groupedGetters.map((propName => groupedRtnValues[propName] = instance[propName]));
return groupedRtnValues;
}
instance = instance[current];
} else {
if (0 === next) {
instance[previous] = deserializeFromWorker(worker, current);
return;
}
if ("function" == typeof instance[previous]) {
args = deserializeFromWorker(worker, current);
"define" === previous && "CustomElementRegistry" === getConstructorName(instance) && (args[1] = defineCustomElement(winId, worker, args[1]));
"insertRule" === previous && args[1] > len(instance.cssRules) && (args[1] = len(instance.cssRules));
instance = instance[previous].apply(instance, args);
if ("play" === previous) {
return Promise.resolve();
}
}
}
}
} catch (err) {
if (isLast) {
throw err;
}
console.debug("Non-blocking setter error:", err);
}
}
return instance;
};
const readNextScript = (worker, winCtx) => {
let $winId$ = winCtx.$winId$;
let win = winCtx.$window$;
let doc = win.document;
let scriptSelector = 'script[type="text/partytown"]:not([data-ptid]):not([data-pterror])';
let scriptElm;
let $instanceId$;
let scriptData;
if (doc && doc.body) {
scriptElm = doc.querySelector('script[type="text/partytown"]:not([data-ptid]):not([data-pterror]):not([async]):not([defer])');
scriptElm || (scriptElm = doc.querySelector(scriptSelector));
if (scriptElm) {
scriptElm.dataset.ptid = $instanceId$ = getAndSetInstanceId(scriptElm, $winId$);
scriptData = {
$winId$: $winId$,
$instanceId$: $instanceId$
};
if (scriptElm.src) {
scriptData.$url$ = scriptElm.src;
scriptData.$orgUrl$ = scriptElm.dataset.ptsrc || scriptElm.src;
} else {
scriptData.$content$ = scriptElm.innerHTML;
}
worker.postMessage([ 7, scriptData ]);
} else {
if (!winCtx.$isInitialized$) {
winCtx.$isInitialized$ = 1;
((worker, $winId$, win) => {
let queuedForwardCalls = win._ptf;
let forwards = (win.partytown || {}).forward || [];
let i;
let mainForwardFn;
let forwardCall = ($forward$, args) => worker.postMessage([ 10, {
$winId$: $winId$,
$forward$: $forward$,
$args$: serializeForWorker($winId$, Array.from(args))
} ]);
win._ptf = void 0;
forwards.map((forwardProps => {
mainForwardFn = win;
forwardProps.split(".").map(((_, i, arr) => {
mainForwardFn = mainForwardFn[arr[i]] = i + 1 < len(arr) ? mainForwardFn[arr[i]] || ("push" === arr[i + 1] ? [] : {}) : (...args) => forwardCall(arr, args);
}));
}));
if (queuedForwardCalls) {
for (i = 0; i < len(queuedForwardCalls); i += 2) {
forwardCall(queuedForwardCalls[i], queuedForwardCalls[i + 1]);
}
}
})(worker, $winId$, win);
doc.dispatchEvent(new CustomEvent("pt0"));
{
const winType = win === win.top ? "top" : "iframe";
logMain(`Executed ${winType} window ${normalizedWinId($winId$)} environment scripts in ${(performance.now() - winCtx.$startTime$).toFixed(1)}ms`);
}
}
worker.postMessage([ 8, $winId$ ]);
}
} else {
requestAnimationFrame((() => readNextScript(worker, winCtx)));
}
};
const registerWindow = (worker, $winId$, $window$) => {
if (!windowIds.has($window$)) {
windowIds.set($window$, $winId$);
const doc = $window$.document;
const history = $window$.history;
const $parentWinId$ = windowIds.get($window$.parent);
let initialised = false;
const onInitialisedQueue = [];
const onInitialised = callback => {
initialised ? callback() : onInitialisedQueue.push(callback);
};
const sendInitEnvData = () => {
worker.postMessage([ 5, {
$winId$: $winId$,
$parentWinId$: $parentWinId$,
$url$: doc.baseURI,
$visibilityState$: doc.visibilityState
} ]);
setTimeout((() => {
initialised = true;
onInitialisedQueue.forEach((callback => {
callback();
}));
}));
};
const pushState = history.pushState.bind(history);
const replaceState = history.replaceState.bind(history);
const onLocationChange = (type, state, newUrl, oldUrl) => () => {
setTimeout((() => {
worker.postMessage([ 13, {
$winId$: $winId$,
type: type,
state: state,
url: doc.baseURI,
newUrl: newUrl,
oldUrl: oldUrl
} ]);
}));
};
history.pushState = (state, _, newUrl) => {
pushState(state, _, newUrl);
onInitialised(onLocationChange(0, state, null == newUrl ? void 0 : newUrl.toString()));
};
history.replaceState = (state, _, newUrl) => {
replaceState(state, _, newUrl);
onInitialised(onLocationChange(1, state, null == newUrl ? void 0 : newUrl.toString()));
};
$window$.addEventListener("popstate", (event => {
onInitialised(onLocationChange(2, event.state));
}));
$window$.addEventListener("hashchange", (event => {
onInitialised(onLocationChange(3, {}, event.newURL, event.oldURL));
}));
$window$.addEventListener("ptupdate", (() => {
readNextScript(worker, winCtxs[$winId$]);
}));
doc.addEventListener("visibilitychange", (() => worker.postMessage([ 14, $winId$, doc.visibilityState ])));
winCtxs[$winId$] = {
$winId$: $winId$,
$window$: $window$
};
winCtxs[$winId$].$startTime$ = performance.now();
{
const winType = $winId$ === $parentWinId$ ? "top" : "iframe";
logMain(`Registered ${winType} window ${normalizedWinId($winId$)}`);
}
"complete" === doc.readyState ? sendInitEnvData() : $window$.addEventListener("load", sendInitEnvData);
}
};
const onMessageFromWebWorker = (worker, msg, winCtx) => {
if (4 === msg[0]) {
registerWindow(worker, randomId(), mainWindow);
} else {
winCtx = winCtxs[msg[1]];
winCtx && (7 === msg[0] ? requestAnimationFrame((() => readNextScript(worker, winCtx))) : 6 === msg[0] && ((worker, winCtx, instanceId, errorMsg, scriptElm) => {
scriptElm = winCtx.$window$.document.querySelector(`[data-ptid="${instanceId}"]`);
if (scriptElm) {
errorMsg ? scriptElm.dataset.pterror = errorMsg : scriptElm.type += "-x";
delete scriptElm.dataset.ptid;
}
readNextScript(worker, winCtx);
})(worker, winCtx, msg[2], msg[3]));
}
};
const readMainInterfaces = () => {
const elms = Object.getOwnPropertyNames(mainWindow).map((interfaceName => ((doc, interfaceName, r, tag) => {
r = interfaceName.match(/^(HTML|SVG)(.+)Element$/);
if (r) {
tag = r[2];
return "S" == interfaceName[0] ? doc.createElementNS("http://www.w3.org/2000/svg", svgConstructorTags[tag] || tag.slice(0, 2).toLowerCase() + tag.slice(2)) : doc.createElement(htmlConstructorTags[tag] || tag);
}
})(docImpl, interfaceName))).filter((elm => elm)).map((elm => [ elm ]));
return readImplementations(elms, []);
};
const cstrs = new Set([ "Object" ]);
const readImplementations = (impls, interfaces) => {
const cstrImpls = impls.filter((implData => implData[0])).map((implData => {
const impl = implData[0];
const interfaceType = implData[1];
const cstrName = getConstructorName(impl);
const CstrPrototype = mainWindow[cstrName].prototype;
return [ cstrName, CstrPrototype, impl, interfaceType ];
}));
cstrImpls.map((([cstrName, CstrPrototype, impl, intefaceType]) => readOwnImplementation(cstrs, interfaces, cstrName, CstrPrototype, impl, intefaceType)));
return interfaces;
};
const readImplementation = (cstrName, impl, memberName) => {
let interfaceMembers = [];
let interfaceInfo = [ cstrName, "Object", interfaceMembers ];
for (memberName in impl) {
readImplementationMember(interfaceMembers, impl, memberName);
}
return interfaceInfo;
};
const readOwnImplementation = (cstrs, interfaces, cstrName, CstrPrototype, impl, interfaceType) => {
if (!cstrs.has(cstrName)) {
cstrs.add(cstrName);
const SuperCstr = Object.getPrototypeOf(CstrPrototype);
const superCstrName = getConstructorName(SuperCstr);
const interfaceMembers = [];
const propDescriptors = Object.getOwnPropertyDescriptors(CstrPrototype);
readOwnImplementation(cstrs, interfaces, superCstrName, SuperCstr, impl, interfaceType);
for (const memberName in propDescriptors) {
readImplementationMember(interfaceMembers, impl, memberName);
}
interfaces.push([ cstrName, superCstrName, interfaceMembers, interfaceType, getNodeName(impl) ]);
}
};
const readImplementationMember = (interfaceMembers, implementation, memberName, value, memberType, cstrName) => {
try {
if (isValidMemberName(memberName) && isNaN(memberName[0]) && "all" !== memberName) {
value = implementation[memberName];
memberType = typeof value;
if ("function" === memberType) {
(String(value).includes("[native") || Object.getPrototypeOf(implementation)[memberName]) && interfaceMembers.push([ memberName, 5 ]);
} else if ("object" === memberType && null != value) {
cstrName = getConstructorName(value);
"Object" !== cstrName && self[cstrName] && interfaceMembers.push([ memberName, value.nodeType || cstrName ]);
} else {
"symbol" !== memberType && (memberName.toUpperCase() === memberName ? interfaceMembers.push([ memberName, 6, value ]) : interfaceMembers.push([ memberName, 6 ]));
}
}
} catch (e) {
console.warn(e);
}
};
const readStorage = storageName => {
let items = [];
let i = 0;
let l = len(mainWindow[storageName]);
let key;
for (;i < l; i++) {
key = mainWindow[storageName].key(i);
items.push([ key, mainWindow[storageName].getItem(key) ]);
}
return items;
};
const getGlobalConstructor = (mainWindow, cstrName) => void 0 !== mainWindow[cstrName] ? new mainWindow[cstrName](noop) : 0;
const addGlobalConstructorUsingPrototype = ($interfaces$, mainWindow, cstrName) => {
void 0 !== mainWindow[cstrName] && $interfaces$.push([ cstrName, "Object", Object.keys(mainWindow[cstrName].prototype).map((propName => [ propName, 6 ])), 12 ]);
};
let worker;
(async receiveMessage => {
const sharedDataBuffer = new SharedArrayBuffer(1073741824);
const sharedData = new Int32Array(sharedDataBuffer);
return (worker, msg) => {
const msgType = msg[0];
const accessReq = msg[1];
if (0 === msgType) {
const initData = (() => {
const elm = docImpl.createElement("i");
const textNode = docImpl.createTextNode("");
const comment = docImpl.createComment("");
const frag = docImpl.createDocumentFragment();
const shadowRoot = docImpl.createElement("p").attachShadow({
mode: "open"
});
const intersectionObserver = getGlobalConstructor(mainWindow, "IntersectionObserver");
const mutationObserver = getGlobalConstructor(mainWindow, "MutationObserver");
const resizeObserver = getGlobalConstructor(mainWindow, "ResizeObserver");
const perf = mainWindow.performance;
const screen = mainWindow.screen;
const impls = [ [ mainWindow.history ], [ perf ], [ perf.navigation ], [ perf.timing ], [ screen ], [ screen.orientation ], [ mainWindow.visualViewport ], [ intersectionObserver, 12 ], [ mutationObserver, 12 ], [ resizeObserver, 12 ], [ textNode ], [ comment ], [ frag ], [ shadowRoot ], [ elm ], [ elm.attributes ], [ elm.classList ], [ elm.dataset ], [ elm.style ], [ docImpl ], [ docImpl.doctype ] ];
const initialInterfaces = [ readImplementation("Window", mainWindow), readImplementation("Node", textNode) ];
const $config$ = JSON.stringify(config, ((k, v) => {
if ("function" == typeof v) {
v = String(v);
v.startsWith(k + "(") && (v = "function " + v);
}
return v;
}));
const initWebWorkerData = {
$config$: $config$,
$interfaces$: readImplementations(impls, initialInterfaces),
$libPath$: new URL(libPath, mainWindow.location) + "",
$origin$: origin,
$localStorage$: readStorage("localStorage"),
$sessionStorage$: readStorage("sessionStorage")
};
addGlobalConstructorUsingPrototype(initWebWorkerData.$interfaces$, mainWindow, "IntersectionObserverEntry");
return initWebWorkerData;
})();
initData.$sharedDataBuffer$ = sharedDataBuffer;
worker.postMessage([ 1, initData ]);
} else {
2 === msg[0] ? worker.postMessage([ 3, readMainInterfaces() ]) : 11 === msgType ? receiveMessage(accessReq, (accessRsp => {
const stringifiedData = JSON.stringify(accessRsp);
const stringifiedDataLength = stringifiedData.length;
for (let i = 0; i < stringifiedDataLength; i++) {
sharedData[i + 1] = stringifiedData.charCodeAt(i);
}
sharedData[0] = stringifiedDataLength;
Atomics.notify(sharedData, 0);
})) : onMessageFromWebWorker(worker, msg);
}
};
})(((accessReq, responseCallback) => mainAccessHandler(worker, accessReq).then(responseCallback))).then((onMessageHandler => {
if (onMessageHandler) {
worker = new Worker(libPath + "partytown-ww-atomics.js?v=0.8.0", {
name: "Partytown 🎉"
});
worker.onmessage = ev => {
const msg = ev.data;
12 === msg[0] ? mainAccessHandler(worker, msg[1]) : onMessageHandler(worker, msg);
};
logMain("Created Partytown web worker (0.8.0)");
worker.onerror = ev => console.error("Web Worker Error", ev);
mainWindow.addEventListener("pt1", (ev => registerWindow(worker, getAndSetInstanceId(ev.detail.frameElement), ev.detail)));
}
}));
})(window);

View File

@@ -1,374 +0,0 @@
/* Partytown 0.8.0 - MIT builder.io */
(self => {
const [getter, setter, callMethod, constructGlobal, definePrototypePropertyDescriptor, randomId, WinIdKey, InstanceIdKey, ApplyPathKey] = self.$bridgeToMedia$;
delete self.$bridgeToMedia$;
const ContextKey = Symbol();
const MediaSourceKey = Symbol();
const ReadyStateKey = Symbol();
const SourceBuffersKey = Symbol();
const SourceBufferTasksKey = Symbol();
const TimeRangesKey = Symbol();
const EMPTY_ARRAY = [];
const defineCstr = (win, cstrName, Cstr) => win[cstrName] = defineCstrName(cstrName, Cstr);
const defineCstrName = (cstrName, Cstr) => Object.defineProperty(Cstr, "name", {
value: cstrName
});
const initCanvas = (WorkerBase, win) => {
const HTMLCanvasDescriptorMap = {
getContext: {
value(contextType, contextAttributes) {
this[ContextKey] || (this[ContextKey] = (contextType.includes("webgl") ? createContextWebGL : createContext2D)(this, contextType, contextAttributes));
return this[ContextKey];
}
}
};
const WorkerCanvasGradient = defineCstr(win, "CanvasGradient", class extends WorkerBase {
addColorStop(...args) {
callMethod(this, [ "addColorStop" ], args, 2);
}
});
const WorkerCanvasPattern = defineCstr(win, "CanvasPattern", class extends WorkerBase {
setTransform(...args) {
callMethod(this, [ "setTransform" ], args, 2);
}
});
const createContext2D = (canvasInstance, contextType, contextAttributes) => {
const winId = canvasInstance[WinIdKey];
const ctxInstanceId = randomId();
const ctxInstance = {
[WinIdKey]: winId,
[InstanceIdKey]: ctxInstanceId,
[ApplyPathKey]: []
};
const ctx = callMethod(canvasInstance, [ "getContext" ], [ contextType, contextAttributes ], 1, ctxInstanceId);
const ctx2dGetterMethods = "getContextAttributes,getImageData,getLineDash,getTransform,isPointInPath,isPointInStroke,measureText".split(",");
const CanvasRenderingContext2D = {
get: (target, propName) => "string" == typeof propName && propName in ctx ? "function" == typeof ctx[propName] ? (...args) => {
if (propName.startsWith("create")) {
const instanceId = randomId();
callMethod(ctxInstance, [ propName ], args, 2, instanceId);
if ("createImageData" === propName || "createPattern" === propName) {
(api => {
console.warn(`${api} not implemented`);
})(`${propName}()`);
return {
setTransform: () => {}
};
}
return new WorkerCanvasGradient(winId, instanceId);
}
const methodCallType = ctx2dGetterMethods.includes(propName) ? 1 : 2;
return callMethod(ctxInstance, [ propName ], args, methodCallType);
} : ctx[propName] : target[propName],
set(target, propName, value) {
if ("string" == typeof propName && propName in ctx) {
ctx[propName] !== value && "function" != typeof value && setter(ctxInstance, [ propName ], value);
ctx[propName] = value;
} else {
target[propName] = value;
}
return true;
}
};
return new Proxy(ctx, CanvasRenderingContext2D);
};
const createContextWebGL = (canvasInstance, contextType, contextAttributes) => {
const winId = canvasInstance[WinIdKey];
const ctxInstanceId = randomId();
const ctxInstance = {
[WinIdKey]: winId,
[InstanceIdKey]: ctxInstanceId,
[ApplyPathKey]: []
};
const ctx = callMethod(canvasInstance, [ "getContext" ], [ contextType, contextAttributes ], 1, ctxInstanceId);
const WebGLRenderingContextHandler = {
get: (target, propName) => "string" == typeof propName ? "function" != typeof ctx[propName] ? ctx[propName] : (...args) => callMethod(ctxInstance, [ propName ], args, getWebGlMethodCallType(propName)) : target[propName],
set(target, propName, value) {
if ("string" == typeof propName && propName in ctx) {
ctx[propName] !== value && "function" != typeof value && setter(ctxInstance, [ propName ], value);
ctx[propName] = value;
} else {
target[propName] = value;
}
return true;
}
};
return new Proxy(ctx, WebGLRenderingContextHandler);
};
const ctxWebGLGetterMethods = "checkFramebufferStatus,makeXRCompatible".split(",");
const getWebGlMethodCallType = methodName => methodName.startsWith("create") || methodName.startsWith("get") || methodName.startsWith("is") || ctxWebGLGetterMethods.includes(methodName) ? 1 : 2;
defineCstr(win, "CanvasGradient", WorkerCanvasGradient);
defineCstr(win, "CanvasPattern", WorkerCanvasPattern);
definePrototypePropertyDescriptor(win.HTMLCanvasElement, HTMLCanvasDescriptorMap);
};
const initMedia = (WorkerBase, WorkerEventTargetProxy, env, win) => {
var _a, _b;
win.Audio = defineCstrName("HTMLAudioElement", class {
constructor(src) {
const audio = env.$createNode$("audio", randomId());
audio.src = src;
return audio;
}
});
const WorkerAudioTrack = class extends WorkerBase {
get enabled() {
return getter(this, [ "enabled" ]);
}
set enabled(value) {
setter(this, [ "enabled" ], value);
}
get id() {
return getter(this, [ "id" ]);
}
get kind() {
return getter(this, [ "kind" ]);
}
get label() {
return getter(this, [ "label" ]);
}
get language() {
return getter(this, [ "language" ]);
}
get sourceBuffer() {
return new WorkerSourceBuffer(this);
}
};
const WorkerAudioTrackList = class {
constructor(mediaElm) {
const winId = mediaElm[WinIdKey];
const instanceId = mediaElm[InstanceIdKey];
const instance = {
addEventListener(...args) {
callMethod(mediaElm, [ "audioTracks", "addEventListener" ], args, 3);
},
getTrackById: (...args) => callMethod(mediaElm, [ "audioTracks", "getTrackById" ], args),
get length() {
return getter(mediaElm, [ "audioTracks", "length" ]);
},
removeEventListener(...args) {
callMethod(mediaElm, [ "audioTracks", "removeEventListener" ], args, 3);
}
};
return new Proxy(instance, {
get: (target, propName) => "number" == typeof propName ? new WorkerAudioTrack(winId, instanceId, [ "audioTracks", propName ]) : target[propName]
});
}
};
const WorkerSourceBufferList = defineCstr(win, "SourceBufferList", class extends Array {
constructor(mediaSource) {
super();
this[MediaSourceKey] = mediaSource;
}
addEventListener(...args) {
callMethod(this[MediaSourceKey], [ "sourceBuffers", "addEventListener" ], args, 3);
}
removeEventListener(...args) {
callMethod(this[MediaSourceKey], [ "sourceBuffers", "removeEventListener" ], args, 3);
}
});
const WorkerSourceBuffer = defineCstr(win, "SourceBuffer", (_b = class extends WorkerEventTargetProxy {
constructor(mediaSource) {
super(mediaSource[WinIdKey], mediaSource[InstanceIdKey], [ "sourceBuffers" ]);
this[_a] = [];
this[MediaSourceKey] = mediaSource;
}
abort() {
const sbIndex = getSourceBufferIndex(this);
callMethod(this, [ sbIndex, "appendWindowStart" ], EMPTY_ARRAY, 1);
}
addEventListener(...args) {
const sbIndex = getSourceBufferIndex(this);
callMethod(this, [ sbIndex, "addEventListener" ], args, 3);
}
appendBuffer(buf) {
this[SourceBufferTasksKey].push([ "appendBuffer", [ buf ], buf ]);
drainSourceBufferQueue(this);
}
get appendWindowStart() {
const sbIndex = getSourceBufferIndex(this);
return getter(this, [ sbIndex, "appendWindowStart" ]);
}
set appendWindowStart(value) {
const sbIndex = getSourceBufferIndex(this);
setter(this, [ sbIndex, "appendWindowStart" ], value);
}
get appendWindowEnd() {
const sbIndex = getSourceBufferIndex(this);
return getter(this, [ sbIndex, "appendWindowEnd" ]);
}
set appendWindowEnd(value) {
const sbIndex = getSourceBufferIndex(this);
setter(this, [ sbIndex, "appendWindowEnd" ], value);
}
get buffered() {
const mediaSource = this[MediaSourceKey];
const sbIndex = getSourceBufferIndex(this);
const timeRanges = new WorkerTimeRanges(mediaSource[WinIdKey], mediaSource[InstanceIdKey], [ "sourceBuffers", sbIndex, "buffered" ]);
return timeRanges;
}
changeType(mimeType) {
const sbIndex = getSourceBufferIndex(this);
callMethod(this, [ sbIndex, "changeType" ], [ mimeType ], 2);
}
get mode() {
const sbIndex = getSourceBufferIndex(this);
return getter(this, [ sbIndex, "mode" ]);
}
set mode(value) {
const sbIndex = getSourceBufferIndex(this);
setter(this, [ sbIndex, "mode" ], value);
}
remove(start, end) {
this[SourceBufferTasksKey].push([ "remove", [ start, end ] ]);
drainSourceBufferQueue(this);
}
removeEventListener(...args) {
const sbIndex = getSourceBufferIndex(this);
callMethod(this, [ sbIndex, "removeEventListener" ], args, 3);
}
get timestampOffset() {
const sbIndex = getSourceBufferIndex(this);
return getter(this, [ sbIndex, "timestampOffset" ]);
}
set timestampOffset(value) {
const sbIndex = getSourceBufferIndex(this);
setter(this, [ sbIndex, "timestampOffset" ], value);
}
get updating() {
const sbIndex = getSourceBufferIndex(this);
return getter(this, [ sbIndex, "updating" ]);
}
}, _a = SourceBufferTasksKey, _b));
const WorkerTimeRanges = defineCstr(win, "TimeRanges", class extends WorkerBase {
start(...args) {
return callMethod(this, [ "start" ], args);
}
end(...args) {
return callMethod(this, [ "end" ], args);
}
get length() {
return getter(this, [ "length" ]);
}
});
const getSourceBufferIndex = sourceBuffer => {
if (sourceBuffer) {
const mediaSource = sourceBuffer[MediaSourceKey];
const sourceBufferList = mediaSource[SourceBuffersKey];
return sourceBufferList.indexOf(sourceBuffer);
}
return -1;
};
const drainSourceBufferQueue = sourceBuffer => {
if (sourceBuffer[SourceBufferTasksKey].length) {
if (!sourceBuffer.updating) {
const task = sourceBuffer[SourceBufferTasksKey].shift();
if (task) {
const sbIndex = getSourceBufferIndex(sourceBuffer);
callMethod(sourceBuffer, [ sbIndex, task[0] ], task[1], 3, void 0, task[2]);
}
}
setTimeout((() => drainSourceBufferQueue(sourceBuffer)), 50);
}
};
const HTMLMediaDescriptorMap = {
buffered: {
get() {
if (!this[TimeRangesKey]) {
this[TimeRangesKey] = new WorkerTimeRanges(this[WinIdKey], this[InstanceIdKey], [ "buffered" ]);
setTimeout((() => {
this[TimeRangesKey] = void 0;
}), 5e3);
}
return this[TimeRangesKey];
}
},
readyState: {
get() {
if (4 === this[ReadyStateKey]) {
return 4;
}
if ("number" != typeof this[ReadyStateKey]) {
this[ReadyStateKey] = getter(this, [ "readyState" ]);
setTimeout((() => {
this[ReadyStateKey] = void 0;
}), 1e3);
}
return this[ReadyStateKey];
}
}
};
defineCstr(win, "MediaSource", class extends WorkerEventTargetProxy {
constructor() {
super(env.$winId$);
this[SourceBuffersKey] = new WorkerSourceBufferList(this);
constructGlobal(this, "MediaSource", EMPTY_ARRAY);
}
get activeSourceBuffers() {
return [];
}
addSourceBuffer(mimeType) {
const sourceBuffer = new WorkerSourceBuffer(this);
this[SourceBuffersKey].push(sourceBuffer);
callMethod(this, [ "addSourceBuffer" ], [ mimeType ]);
return sourceBuffer;
}
clearLiveSeekableRange() {
callMethod(this, [ "clearLiveSeekableRange" ], EMPTY_ARRAY, 2);
}
get duration() {
return getter(this, [ "duration" ]);
}
set duration(value) {
setter(this, [ "duration" ], value);
}
endOfStream(endOfStreamError) {
callMethod(this, [ "endOfStream" ], [ endOfStreamError ], 3);
}
get readyState() {
return getter(this, [ "readyState" ]);
}
removeSourceBuffer(sourceBuffer) {
const index = getSourceBufferIndex(sourceBuffer);
if (index > -1) {
this[SourceBuffersKey].splice(index, 1);
callMethod(this, [ "removeSourceBuffer" ], [ index ], 1);
}
}
setLiveSeekableRange(start, end) {
callMethod(this, [ "setLiveSeekableRange" ], [ start, end ], 2);
}
get sourceBuffers() {
return this[SourceBuffersKey];
}
static isTypeSupported(mimeType) {
if (!isStaticTypeSupported.has(mimeType)) {
const isSupported = callMethod(win, [ "MediaSource", "isTypeSupported" ], [ mimeType ]);
isStaticTypeSupported.set(mimeType, isSupported);
}
return isStaticTypeSupported.get(mimeType);
}
});
const winURL = win.URL = defineCstrName("URL", class extends URL {});
const hasAudioTracks = "audioTracks" in win.HTMLMediaElement.prototype;
if (hasAudioTracks) {
defineCstr(win, "AudioTrackList", WorkerAudioTrackList);
defineCstr(win, "AudioTrack", WorkerAudioTrack);
HTMLMediaDescriptorMap.audioTracks = {
get() {
return new WorkerAudioTrackList(this);
}
};
}
definePrototypePropertyDescriptor(win.HTMLMediaElement, HTMLMediaDescriptorMap);
winURL.createObjectURL = obj => callMethod(win, [ "URL", "createObjectURL" ], [ obj ]);
winURL.revokeObjectURL = obj => callMethod(win, [ "URL", "revokeObjectURL" ], [ obj ]);
};
const isStaticTypeSupported = new Map;
self.$bridgeFromMedia$ = (WorkerBase, WorkerEventTargetProxy, env, win, windowMediaConstructors) => {
windowMediaConstructors.map((mediaCstrName => {
delete win[mediaCstrName];
}));
initCanvas(WorkerBase, win);
initMedia(WorkerBase, WorkerEventTargetProxy, env, win);
};
})(self);

View File

@@ -1,559 +0,0 @@
/* Partytown 0.8.0 - MIT builder.io */
(window => {
const isPromise = v => "object" == typeof v && v && v.then;
const noop = () => {};
const len = obj => obj.length;
const getConstructorName = obj => {
var _a, _b, _c;
try {
const constructorName = null === (_a = null == obj ? void 0 : obj.constructor) || void 0 === _a ? void 0 : _a.name;
if (constructorName) {
return constructorName;
}
} catch (e) {}
try {
const zoneJsConstructorName = null === (_c = null === (_b = null == obj ? void 0 : obj.__zone_symbol__originalInstance) || void 0 === _b ? void 0 : _b.constructor) || void 0 === _c ? void 0 : _c.name;
if (zoneJsConstructorName) {
return zoneJsConstructorName;
}
} catch (e) {}
return "";
};
const startsWith = (str, val) => str.startsWith(val);
const isValidMemberName = memberName => !(startsWith(memberName, "webkit") || startsWith(memberName, "toJSON") || startsWith(memberName, "constructor") || startsWith(memberName, "toString") || startsWith(memberName, "_"));
const getNodeName = node => 11 === node.nodeType && node.host ? "#s" : node.nodeName;
const randomId = () => Math.round(Math.random() * Number.MAX_SAFE_INTEGER).toString(36);
const defineConstructorName = (Cstr, value) => ((obj, memberName, descriptor) => Object.defineProperty(obj, memberName, {
...descriptor,
configurable: true
}))(Cstr, "name", {
value: value
});
const htmlConstructorTags = {
Anchor: "a",
DList: "dl",
Image: "img",
OList: "ol",
Paragraph: "p",
Quote: "q",
TableCaption: "caption",
TableCell: "td",
TableCol: "colgroup",
TableRow: "tr",
TableSection: "tbody",
UList: "ul"
};
const svgConstructorTags = {
Graphics: "g",
SVG: "svg"
};
const InstanceIdKey = Symbol();
const CreatedKey = Symbol();
const instances = new Map;
const mainRefs = new Map;
const winCtxs = {};
const windowIds = new WeakMap;
const getAndSetInstanceId = (instance, instanceId) => {
if (instance) {
if (instanceId = windowIds.get(instance)) {
return instanceId;
}
(instanceId = instance[InstanceIdKey]) || setInstanceId(instance, instanceId = randomId());
return instanceId;
}
};
const getInstance = (winId, instanceId, win, doc, docId) => {
if ((win = winCtxs[winId]) && win.$window$) {
if (winId === instanceId) {
return win.$window$;
}
doc = win.$window$.document;
docId = instanceId.split(".").pop();
if ("d" === docId) {
return doc;
}
if ("e" === docId) {
return doc.documentElement;
}
if ("h" === docId) {
return doc.head;
}
if ("b" === docId) {
return doc.body;
}
}
return instances.get(instanceId);
};
const setInstanceId = (instance, instanceId, now) => {
if (instance) {
instances.set(instanceId, instance);
instance[InstanceIdKey] = instanceId;
instance[CreatedKey] = now = Date.now();
if (now > lastCleanup + 5e3) {
instances.forEach(((storedInstance, instanceId) => {
storedInstance[CreatedKey] < lastCleanup && storedInstance.nodeType && !storedInstance.isConnected && instances.delete(instanceId);
}));
lastCleanup = now;
}
}
};
let lastCleanup = 0;
const mainWindow = window.parent;
const docImpl = document.implementation.createHTMLDocument();
const config = mainWindow.partytown || {};
const libPath = (config.lib || "/~partytown/") + "debug/";
const logMain = msg => {
console.debug.apply(console, [ "%cMain 🌎", "background: #717171; color: white; padding: 2px 3px; border-radius: 2px; font-size: 0.8em;", msg ]);
};
const winIds = [];
const normalizedWinId = winId => {
winIds.includes(winId) || winIds.push(winId);
return winIds.indexOf(winId) + 1;
};
const defineCustomElement = (winId, worker, ceData) => {
const Cstr = defineConstructorName(class extends winCtxs[winId].$window$.HTMLElement {}, ceData[0]);
const ceCallbackMethods = "connectedCallback,disconnectedCallback,attributeChangedCallback,adoptedCallback".split(",");
ceCallbackMethods.map((callbackMethodName => Cstr.prototype[callbackMethodName] = function(...args) {
worker.postMessage([ 15, winId, getAndSetInstanceId(this), callbackMethodName, args ]);
}));
Cstr.observedAttributes = ceData[1];
return Cstr;
};
const serializeForWorker = ($winId$, value, added, type, cstrName, prevInstanceId) => void 0 !== value && (type = typeof value) ? "string" === type || "number" === type || "boolean" === type || null == value ? [ 0, value ] : "function" === type ? [ 6 ] : (added = added || new Set) && Array.isArray(value) ? added.has(value) ? [ 1, [] ] : added.add(value) && [ 1, value.map((v => serializeForWorker($winId$, v, added))) ] : "object" === type ? serializedValueIsError(value) ? [ 14, {
name: value.name,
message: value.message,
stack: value.stack
} ] : "" === (cstrName = getConstructorName(value)) ? [ 2, {} ] : "Window" === cstrName ? [ 3, [ $winId$, $winId$ ] ] : "HTMLCollection" === cstrName || "NodeList" === cstrName ? [ 7, Array.from(value).map((v => serializeForWorker($winId$, v, added)[1])) ] : cstrName.endsWith("Event") ? [ 5, serializeObjectForWorker($winId$, value, added) ] : "CSSRuleList" === cstrName ? [ 12, Array.from(value).map(serializeCssRuleForWorker) ] : startsWith(cstrName, "CSS") && cstrName.endsWith("Rule") ? [ 11, serializeCssRuleForWorker(value) ] : "CSSStyleDeclaration" === cstrName ? [ 13, serializeObjectForWorker($winId$, value, added) ] : "Attr" === cstrName ? [ 10, [ value.name, value.value ] ] : value.nodeType ? [ 3, [ $winId$, getAndSetInstanceId(value), getNodeName(value), prevInstanceId ] ] : [ 2, serializeObjectForWorker($winId$, value, added, true, true) ] : void 0 : value;
const serializeObjectForWorker = (winId, obj, added, includeFunctions, includeEmptyStrings, serializedObj, propName, propValue) => {
serializedObj = {};
if (!added.has(obj)) {
added.add(obj);
for (propName in obj) {
if (isValidMemberName(propName)) {
propValue = "path" === propName && getConstructorName(obj).endsWith("Event") ? obj.composedPath() : obj[propName];
(includeFunctions || "function" != typeof propValue) && (includeEmptyStrings || "" !== propValue) && (serializedObj[propName] = serializeForWorker(winId, propValue, added));
}
}
}
return serializedObj;
};
const serializeCssRuleForWorker = cssRule => {
let obj = {};
let key;
for (key in cssRule) {
validCssRuleProps.includes(key) && (obj[key] = String(cssRule[key]));
}
return obj;
};
const serializedValueIsError = value => value instanceof window.top.Error;
const deserializeFromWorker = (worker, serializedTransfer, serializedType, serializedValue) => {
if (serializedTransfer) {
serializedType = serializedTransfer[0];
serializedValue = serializedTransfer[1];
return 0 === serializedType ? serializedValue : 4 === serializedType ? deserializeRefFromWorker(worker, serializedValue) : 1 === serializedType ? serializedValue.map((v => deserializeFromWorker(worker, v))) : 3 === serializedType ? getInstance(serializedValue[0], serializedValue[1]) : 5 === serializedType ? constructEvent(deserializeObjectFromWorker(worker, serializedValue)) : 2 === serializedType ? deserializeObjectFromWorker(worker, serializedValue) : 8 === serializedType ? serializedValue : 9 === serializedType ? new window[serializedTransfer[2]](serializedValue) : void 0;
}
};
const deserializeRefFromWorker = (worker, {$winId$: $winId$, $instanceId$: $instanceId$, $refId$: $refId$}, ref) => {
ref = mainRefs.get($refId$);
if (!ref) {
ref = function(...args) {
worker.postMessage([ 9, {
$winId$: $winId$,
$instanceId$: $instanceId$,
$refId$: $refId$,
$thisArg$: serializeForWorker($winId$, this),
$args$: serializeForWorker($winId$, args)
} ]);
};
mainRefs.set($refId$, ref);
}
return ref;
};
const constructEvent = eventProps => new ("detail" in eventProps ? CustomEvent : Event)(eventProps.type, eventProps);
const deserializeObjectFromWorker = (worker, serializedValue, obj, key) => {
obj = {};
for (key in serializedValue) {
obj[key] = deserializeFromWorker(worker, serializedValue[key]);
}
return obj;
};
const validCssRuleProps = "cssText,selectorText,href,media,namespaceURI,prefix,name,conditionText".split(",");
const mainAccessHandler = async (worker, accessReq) => {
let accessRsp = {
$msgId$: accessReq.$msgId$
};
let totalTasks = len(accessReq.$tasks$);
let i = 0;
let task;
let winId;
let applyPath;
let instance;
let rtnValue;
let isLast;
for (;i < totalTasks; i++) {
try {
isLast = i === totalTasks - 1;
task = accessReq.$tasks$[i];
winId = task.$winId$;
applyPath = task.$applyPath$;
!winCtxs[winId] && winId.startsWith("f_") && await new Promise((resolve => {
let check = 0;
let callback = () => {
winCtxs[winId] || check++ > 1e3 ? resolve() : requestAnimationFrame(callback);
};
callback();
}));
if (1 === applyPath[0] && applyPath[1] in winCtxs[winId].$window$) {
setInstanceId(new winCtxs[winId].$window$[applyPath[1]](...deserializeFromWorker(worker, applyPath[2])), task.$instanceId$);
} else {
instance = getInstance(winId, task.$instanceId$);
if (instance) {
rtnValue = applyToInstance(worker, winId, instance, applyPath, isLast, task.$groupedGetters$);
task.$assignInstanceId$ && ("string" == typeof task.$assignInstanceId$ ? setInstanceId(rtnValue, task.$assignInstanceId$) : winCtxs[task.$assignInstanceId$.$winId$] = {
$winId$: task.$assignInstanceId$.$winId$,
$window$: {
document: rtnValue
}
});
if (isPromise(rtnValue)) {
rtnValue = await rtnValue;
isLast && (accessRsp.$isPromise$ = true);
}
isLast && (accessRsp.$rtnValue$ = serializeForWorker(winId, rtnValue, void 0, void 0, void 0, task.$instanceId$));
} else {
accessRsp.$error$ = `Error finding instance "${task.$instanceId$}" on window ${normalizedWinId(winId)}`;
console.error(accessRsp.$error$, task);
}
}
} catch (e) {
isLast ? accessRsp.$error$ = String(e.stack || e) : console.error(e);
}
}
return accessRsp;
};
const applyToInstance = (worker, winId, instance, applyPath, isLast, groupedGetters) => {
let i = 0;
let l = len(applyPath);
let next;
let current;
let previous;
let args;
let groupedRtnValues;
for (;i < l; i++) {
current = applyPath[i];
next = applyPath[i + 1];
previous = applyPath[i - 1];
try {
if (!Array.isArray(next)) {
if ("string" == typeof current || "number" == typeof current) {
if (i + 1 === l && groupedGetters) {
groupedRtnValues = {};
groupedGetters.map((propName => groupedRtnValues[propName] = instance[propName]));
return groupedRtnValues;
}
instance = instance[current];
} else {
if (0 === next) {
instance[previous] = deserializeFromWorker(worker, current);
return;
}
if ("function" == typeof instance[previous]) {
args = deserializeFromWorker(worker, current);
"define" === previous && "CustomElementRegistry" === getConstructorName(instance) && (args[1] = defineCustomElement(winId, worker, args[1]));
"insertRule" === previous && args[1] > len(instance.cssRules) && (args[1] = len(instance.cssRules));
instance = instance[previous].apply(instance, args);
if ("play" === previous) {
return Promise.resolve();
}
}
}
}
} catch (err) {
if (isLast) {
throw err;
}
console.debug("Non-blocking setter error:", err);
}
}
return instance;
};
const readNextScript = (worker, winCtx) => {
let $winId$ = winCtx.$winId$;
let win = winCtx.$window$;
let doc = win.document;
let scriptSelector = 'script[type="text/partytown"]:not([data-ptid]):not([data-pterror])';
let scriptElm;
let $instanceId$;
let scriptData;
if (doc && doc.body) {
scriptElm = doc.querySelector('script[type="text/partytown"]:not([data-ptid]):not([data-pterror]):not([async]):not([defer])');
scriptElm || (scriptElm = doc.querySelector(scriptSelector));
if (scriptElm) {
scriptElm.dataset.ptid = $instanceId$ = getAndSetInstanceId(scriptElm, $winId$);
scriptData = {
$winId$: $winId$,
$instanceId$: $instanceId$
};
if (scriptElm.src) {
scriptData.$url$ = scriptElm.src;
scriptData.$orgUrl$ = scriptElm.dataset.ptsrc || scriptElm.src;
} else {
scriptData.$content$ = scriptElm.innerHTML;
}
worker.postMessage([ 7, scriptData ]);
} else {
if (!winCtx.$isInitialized$) {
winCtx.$isInitialized$ = 1;
((worker, $winId$, win) => {
let queuedForwardCalls = win._ptf;
let forwards = (win.partytown || {}).forward || [];
let i;
let mainForwardFn;
let forwardCall = ($forward$, args) => worker.postMessage([ 10, {
$winId$: $winId$,
$forward$: $forward$,
$args$: serializeForWorker($winId$, Array.from(args))
} ]);
win._ptf = void 0;
forwards.map((forwardProps => {
mainForwardFn = win;
forwardProps.split(".").map(((_, i, arr) => {
mainForwardFn = mainForwardFn[arr[i]] = i + 1 < len(arr) ? mainForwardFn[arr[i]] || ("push" === arr[i + 1] ? [] : {}) : (...args) => forwardCall(arr, args);
}));
}));
if (queuedForwardCalls) {
for (i = 0; i < len(queuedForwardCalls); i += 2) {
forwardCall(queuedForwardCalls[i], queuedForwardCalls[i + 1]);
}
}
})(worker, $winId$, win);
doc.dispatchEvent(new CustomEvent("pt0"));
{
const winType = win === win.top ? "top" : "iframe";
logMain(`Executed ${winType} window ${normalizedWinId($winId$)} environment scripts in ${(performance.now() - winCtx.$startTime$).toFixed(1)}ms`);
}
}
worker.postMessage([ 8, $winId$ ]);
}
} else {
requestAnimationFrame((() => readNextScript(worker, winCtx)));
}
};
const registerWindow = (worker, $winId$, $window$) => {
if (!windowIds.has($window$)) {
windowIds.set($window$, $winId$);
const doc = $window$.document;
const history = $window$.history;
const $parentWinId$ = windowIds.get($window$.parent);
let initialised = false;
const onInitialisedQueue = [];
const onInitialised = callback => {
initialised ? callback() : onInitialisedQueue.push(callback);
};
const sendInitEnvData = () => {
worker.postMessage([ 5, {
$winId$: $winId$,
$parentWinId$: $parentWinId$,
$url$: doc.baseURI,
$visibilityState$: doc.visibilityState
} ]);
setTimeout((() => {
initialised = true;
onInitialisedQueue.forEach((callback => {
callback();
}));
}));
};
const pushState = history.pushState.bind(history);
const replaceState = history.replaceState.bind(history);
const onLocationChange = (type, state, newUrl, oldUrl) => () => {
setTimeout((() => {
worker.postMessage([ 13, {
$winId$: $winId$,
type: type,
state: state,
url: doc.baseURI,
newUrl: newUrl,
oldUrl: oldUrl
} ]);
}));
};
history.pushState = (state, _, newUrl) => {
pushState(state, _, newUrl);
onInitialised(onLocationChange(0, state, null == newUrl ? void 0 : newUrl.toString()));
};
history.replaceState = (state, _, newUrl) => {
replaceState(state, _, newUrl);
onInitialised(onLocationChange(1, state, null == newUrl ? void 0 : newUrl.toString()));
};
$window$.addEventListener("popstate", (event => {
onInitialised(onLocationChange(2, event.state));
}));
$window$.addEventListener("hashchange", (event => {
onInitialised(onLocationChange(3, {}, event.newURL, event.oldURL));
}));
$window$.addEventListener("ptupdate", (() => {
readNextScript(worker, winCtxs[$winId$]);
}));
doc.addEventListener("visibilitychange", (() => worker.postMessage([ 14, $winId$, doc.visibilityState ])));
winCtxs[$winId$] = {
$winId$: $winId$,
$window$: $window$
};
winCtxs[$winId$].$startTime$ = performance.now();
{
const winType = $winId$ === $parentWinId$ ? "top" : "iframe";
logMain(`Registered ${winType} window ${normalizedWinId($winId$)}`);
}
"complete" === doc.readyState ? sendInitEnvData() : $window$.addEventListener("load", sendInitEnvData);
}
};
const onMessageFromWebWorker = (worker, msg, winCtx) => {
if (4 === msg[0]) {
registerWindow(worker, randomId(), mainWindow);
} else {
winCtx = winCtxs[msg[1]];
winCtx && (7 === msg[0] ? requestAnimationFrame((() => readNextScript(worker, winCtx))) : 6 === msg[0] && ((worker, winCtx, instanceId, errorMsg, scriptElm) => {
scriptElm = winCtx.$window$.document.querySelector(`[data-ptid="${instanceId}"]`);
if (scriptElm) {
errorMsg ? scriptElm.dataset.pterror = errorMsg : scriptElm.type += "-x";
delete scriptElm.dataset.ptid;
}
readNextScript(worker, winCtx);
})(worker, winCtx, msg[2], msg[3]));
}
};
const readMainPlatform = () => {
const elm = docImpl.createElement("i");
const textNode = docImpl.createTextNode("");
const comment = docImpl.createComment("");
const frag = docImpl.createDocumentFragment();
const shadowRoot = docImpl.createElement("p").attachShadow({
mode: "open"
});
const intersectionObserver = getGlobalConstructor(mainWindow, "IntersectionObserver");
const mutationObserver = getGlobalConstructor(mainWindow, "MutationObserver");
const resizeObserver = getGlobalConstructor(mainWindow, "ResizeObserver");
const perf = mainWindow.performance;
const screen = mainWindow.screen;
const impls = [ [ mainWindow.history ], [ perf ], [ perf.navigation ], [ perf.timing ], [ screen ], [ screen.orientation ], [ mainWindow.visualViewport ], [ intersectionObserver, 12 ], [ mutationObserver, 12 ], [ resizeObserver, 12 ], [ textNode ], [ comment ], [ frag ], [ shadowRoot ], [ elm ], [ elm.attributes ], [ elm.classList ], [ elm.dataset ], [ elm.style ], [ docImpl ], [ docImpl.doctype ] ];
const initialInterfaces = [ readImplementation("Window", mainWindow), readImplementation("Node", textNode) ];
const $config$ = JSON.stringify(config, ((k, v) => {
if ("function" == typeof v) {
v = String(v);
v.startsWith(k + "(") && (v = "function " + v);
}
return v;
}));
const initWebWorkerData = {
$config$: $config$,
$interfaces$: readImplementations(impls, initialInterfaces),
$libPath$: new URL(libPath, mainWindow.location) + "",
$origin$: origin,
$localStorage$: readStorage("localStorage"),
$sessionStorage$: readStorage("sessionStorage")
};
addGlobalConstructorUsingPrototype(initWebWorkerData.$interfaces$, mainWindow, "IntersectionObserverEntry");
return initWebWorkerData;
};
const readMainInterfaces = () => {
const elms = Object.getOwnPropertyNames(mainWindow).map((interfaceName => ((doc, interfaceName, r, tag) => {
r = interfaceName.match(/^(HTML|SVG)(.+)Element$/);
if (r) {
tag = r[2];
return "S" == interfaceName[0] ? doc.createElementNS("http://www.w3.org/2000/svg", svgConstructorTags[tag] || tag.slice(0, 2).toLowerCase() + tag.slice(2)) : doc.createElement(htmlConstructorTags[tag] || tag);
}
})(docImpl, interfaceName))).filter((elm => elm)).map((elm => [ elm ]));
return readImplementations(elms, []);
};
const cstrs = new Set([ "Object" ]);
const readImplementations = (impls, interfaces) => {
const cstrImpls = impls.filter((implData => implData[0])).map((implData => {
const impl = implData[0];
const interfaceType = implData[1];
const cstrName = getConstructorName(impl);
const CstrPrototype = mainWindow[cstrName].prototype;
return [ cstrName, CstrPrototype, impl, interfaceType ];
}));
cstrImpls.map((([cstrName, CstrPrototype, impl, intefaceType]) => readOwnImplementation(cstrs, interfaces, cstrName, CstrPrototype, impl, intefaceType)));
return interfaces;
};
const readImplementation = (cstrName, impl, memberName) => {
let interfaceMembers = [];
let interfaceInfo = [ cstrName, "Object", interfaceMembers ];
for (memberName in impl) {
readImplementationMember(interfaceMembers, impl, memberName);
}
return interfaceInfo;
};
const readOwnImplementation = (cstrs, interfaces, cstrName, CstrPrototype, impl, interfaceType) => {
if (!cstrs.has(cstrName)) {
cstrs.add(cstrName);
const SuperCstr = Object.getPrototypeOf(CstrPrototype);
const superCstrName = getConstructorName(SuperCstr);
const interfaceMembers = [];
const propDescriptors = Object.getOwnPropertyDescriptors(CstrPrototype);
readOwnImplementation(cstrs, interfaces, superCstrName, SuperCstr, impl, interfaceType);
for (const memberName in propDescriptors) {
readImplementationMember(interfaceMembers, impl, memberName);
}
interfaces.push([ cstrName, superCstrName, interfaceMembers, interfaceType, getNodeName(impl) ]);
}
};
const readImplementationMember = (interfaceMembers, implementation, memberName, value, memberType, cstrName) => {
try {
if (isValidMemberName(memberName) && isNaN(memberName[0]) && "all" !== memberName) {
value = implementation[memberName];
memberType = typeof value;
if ("function" === memberType) {
(String(value).includes("[native") || Object.getPrototypeOf(implementation)[memberName]) && interfaceMembers.push([ memberName, 5 ]);
} else if ("object" === memberType && null != value) {
cstrName = getConstructorName(value);
"Object" !== cstrName && self[cstrName] && interfaceMembers.push([ memberName, value.nodeType || cstrName ]);
} else {
"symbol" !== memberType && (memberName.toUpperCase() === memberName ? interfaceMembers.push([ memberName, 6, value ]) : interfaceMembers.push([ memberName, 6 ]));
}
}
} catch (e) {
console.warn(e);
}
};
const readStorage = storageName => {
let items = [];
let i = 0;
let l = len(mainWindow[storageName]);
let key;
for (;i < l; i++) {
key = mainWindow[storageName].key(i);
items.push([ key, mainWindow[storageName].getItem(key) ]);
}
return items;
};
const getGlobalConstructor = (mainWindow, cstrName) => void 0 !== mainWindow[cstrName] ? new mainWindow[cstrName](noop) : 0;
const addGlobalConstructorUsingPrototype = ($interfaces$, mainWindow, cstrName) => {
void 0 !== mainWindow[cstrName] && $interfaces$.push([ cstrName, "Object", Object.keys(mainWindow[cstrName].prototype).map((propName => [ propName, 6 ])), 12 ]);
};
let worker;
(receiveMessage => {
const swContainer = window.navigator.serviceWorker;
return swContainer.getRegistration().then((swRegistration => {
swContainer.addEventListener("message", (ev => receiveMessage(ev.data, (accessRsp => swRegistration.active && swRegistration.active.postMessage(accessRsp)))));
return (worker, msg) => {
0 === msg[0] ? worker.postMessage([ 1, readMainPlatform() ]) : 2 === msg[0] ? worker.postMessage([ 3, readMainInterfaces() ]) : onMessageFromWebWorker(worker, msg);
};
}));
})(((accessReq, responseCallback) => mainAccessHandler(worker, accessReq).then(responseCallback))).then((onMessageHandler => {
if (onMessageHandler) {
worker = new Worker(libPath + "partytown-ww-sw.js?v=0.8.0", {
name: "Partytown 🎉"
});
worker.onmessage = ev => {
const msg = ev.data;
12 === msg[0] ? mainAccessHandler(worker, msg[1]) : onMessageHandler(worker, msg);
};
logMain("Created Partytown web worker (0.8.0)");
worker.onerror = ev => console.error("Web Worker Error", ev);
mainWindow.addEventListener("pt1", (ev => registerWindow(worker, getAndSetInstanceId(ev.detail.frameElement), ev.detail)));
}
}));
})(window);

View File

@@ -1,59 +0,0 @@
/* Partytown 0.8.0 - MIT builder.io */
const resolves = new Map;
const swMessageError = (accessReq, $error$) => ({
$msgId$: accessReq.$msgId$,
$error$: $error$
});
const httpRequestFromWebWorker = req => new Promise((async resolve => {
const accessReq = await req.clone().json();
const responseData = await (accessReq => new Promise((async resolve => {
const clients = await self.clients.matchAll();
const client = [ ...clients ].sort(((a, b) => a.url > b.url ? -1 : a.url < b.url ? 1 : 0))[0];
if (client) {
const timeout = 12e4;
const msgResolve = [ resolve, setTimeout((() => {
resolves.delete(accessReq.$msgId$);
resolve(swMessageError(accessReq, "Timeout"));
}), timeout) ];
resolves.set(accessReq.$msgId$, msgResolve);
client.postMessage(accessReq);
} else {
resolve(swMessageError(accessReq, "NoParty"));
}
})))(accessReq);
resolve(response(JSON.stringify(responseData), "application/json"));
}));
const response = (body, contentType) => new Response(body, {
headers: {
"content-type": contentType || "text/html",
"Cache-Control": "no-store"
}
});
self.oninstall = () => self.skipWaiting();
self.onactivate = () => self.clients.claim();
self.onmessage = ev => {
const accessRsp = ev.data;
const r = resolves.get(accessRsp.$msgId$);
if (r) {
resolves.delete(accessRsp.$msgId$);
clearTimeout(r[1]);
r[0](accessRsp);
}
};
self.onfetch = ev => {
const req = ev.request;
const url = new URL(req.url);
const pathname = url.pathname;
if (pathname.endsWith("sw.html")) {
ev.respondWith(response('<!DOCTYPE html><html><head><meta charset="utf-8"><script src="./partytown-sandbox-sw.js?v=0.8.0"><\/script></head></html>'));
} else {
pathname.endsWith("proxytown") && ev.respondWith(httpRequestFromWebWorker(req));
}
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,75 +0,0 @@
/* Partytown 0.8.0 - MIT builder.io */
!function(win, doc, nav, top, useAtomics, config, libPath, timeout, scripts, sandbox, mainForwardFn, isReady) {
function ready() {
if (!isReady) {
isReady = 1;
libPath = (config.lib || "/~partytown/") + (false !== config.debug ? "debug/" : "");
if ("/" == libPath[0]) {
scripts = doc.querySelectorAll('script[type="text/partytown"]');
if (top != win) {
top.dispatchEvent(new CustomEvent("pt1", {
detail: win
}));
} else {
timeout = setTimeout(fallback, 1e4);
doc.addEventListener("pt0", clearFallback);
useAtomics ? loadSandbox(1) : nav.serviceWorker ? nav.serviceWorker.register(libPath + (config.swPath || "partytown-sw.js"), {
scope: libPath
}).then((function(swRegistration) {
if (swRegistration.active) {
loadSandbox();
} else if (swRegistration.installing) {
swRegistration.installing.addEventListener("statechange", (function(ev) {
"activated" == ev.target.state && loadSandbox();
}));
} else {
console.warn(swRegistration);
}
}), console.error) : fallback();
}
} else {
console.warn('Partytown config.lib url must start with "/"');
}
}
}
function loadSandbox(isAtomics) {
sandbox = doc.createElement(isAtomics ? "script" : "iframe");
if (!isAtomics) {
sandbox.setAttribute("style", "display:block;width:0;height:0;border:0;visibility:hidden");
sandbox.setAttribute("aria-hidden", !0);
}
sandbox.src = libPath + "partytown-" + (isAtomics ? "atomics.js?v=0.8.0" : "sandbox-sw.html?" + Date.now());
doc.querySelector(config.sandboxParent || "body").appendChild(sandbox);
}
function fallback(i, script) {
console.warn("Partytown script fallback");
clearFallback();
top == win && (config.forward || []).map((function(forwardProps) {
delete win[forwardProps.split(".")[0]];
}));
for (i = 0; i < scripts.length; i++) {
script = doc.createElement("script");
script.innerHTML = scripts[i].innerHTML;
doc.head.appendChild(script);
}
sandbox && sandbox.parentNode.removeChild(sandbox);
}
function clearFallback() {
clearTimeout(timeout);
}
config = win.partytown || {};
top == win && (config.forward || []).map((function(forwardProps) {
mainForwardFn = win;
forwardProps.split(".").map((function(_, i, forwardPropsArr) {
mainForwardFn = mainForwardFn[forwardPropsArr[i]] = i + 1 < forwardPropsArr.length ? "push" == forwardPropsArr[i + 1] ? [] : mainForwardFn[forwardPropsArr[i]] || {} : function() {
(win._ptf = win._ptf || []).push(forwardPropsArr, arguments);
};
}));
}));
if ("complete" == doc.readyState) {
ready();
} else {
win.addEventListener("DOMContentLoaded", ready);
win.addEventListener("load", ready);
}
}(window, document, navigator, top, window.crossOriginIsolated);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +0,0 @@
/* Partytown 0.8.0 - MIT builder.io */
!function(t,e,n,i,r,o,a,d,s,c,l,p){function u(){p||(p=1,"/"==(a=(o.lib||"/~partytown/")+(o.debug?"debug/":""))[0]&&(s=e.querySelectorAll('script[type="text/partytown"]'),i!=t?i.dispatchEvent(new CustomEvent("pt1",{detail:t})):(d=setTimeout(f,1e4),e.addEventListener("pt0",w),r?h(1):n.serviceWorker?n.serviceWorker.register(a+(o.swPath||"partytown-sw.js"),{scope:a}).then((function(t){t.active?h():t.installing&&t.installing.addEventListener("statechange",(function(t){"activated"==t.target.state&&h()}))}),console.error):f())))}function h(t){c=e.createElement(t?"script":"iframe"),t||(c.setAttribute("style","display:block;width:0;height:0;border:0;visibility:hidden"),c.setAttribute("aria-hidden",!0)),c.src=a+"partytown-"+(t?"atomics.js?v=0.8.0":"sandbox-sw.html?"+Date.now()),e.querySelector(o.sandboxParent||"body").appendChild(c)}function f(n,r){for(w(),i==t&&(o.forward||[]).map((function(e){delete t[e.split(".")[0]]})),n=0;n<s.length;n++)(r=e.createElement("script")).innerHTML=s[n].innerHTML,e.head.appendChild(r);c&&c.parentNode.removeChild(c)}function w(){clearTimeout(d)}o=t.partytown||{},i==t&&(o.forward||[]).map((function(e){l=t,e.split(".").map((function(e,n,i){l=l[i[n]]=n+1<i.length?"push"==i[n+1]?[]:l[i[n]]||{}:function(){(t._ptf=t._ptf||[]).push(i,arguments)}}))})),"complete"==e.readyState?u():(t.addEventListener("DOMContentLoaded",u),t.addEventListener("load",u))}(window,document,navigator,top,window.crossOriginIsolated);

View File

@@ -1,17 +1,16 @@
import adapter from '@sveltejs/adapter-vercel';
import preprocess from 'svelte-preprocess';
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/kit/vite';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://github.com/sveltejs/svelte-preprocess
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: [
preprocess({
postcss: true,
preserve: ['partytown']
})
],
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()
}
};

View File

@@ -1,8 +0,0 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./src/**/*.{html,js,svelte,ts}'],
theme: {
extend: {}
},
plugins: []
};

View File

@@ -8,10 +8,7 @@
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true
"strict": true,
"moduleResolution": "NodeNext"
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
}

View File

@@ -1,12 +0,0 @@
{
"rewrites": [
{
"source": "/proxytown/gtm",
"destination": "https://www.googletagmanager.com/gtag/js"
},
{
"source": "/proxytown/ga",
"destination": "https://www.google-analytics.com/analytics.js"
}
]
}

View File

@@ -1,26 +1,9 @@
import { join } from 'path'
import { sveltekit } from '@sveltejs/kit/vite';
import type { UserConfig } from 'vite';
import { partytownVite } from '@builder.io/partytown/utils'
import { defineConfig } from 'vitest/config';
const config: UserConfig = {
plugins: [sveltekit(),
partytownVite({
// `dest` specifies where files are copied to in production
dest: join(process.cwd(), 'static', '~partytown')
})
],
define: {
_a: 'undefined'
},
build: {
rollupOptions: {
external: ['@resvg/resvg-js']
}
},
optimizeDeps: {
exclude: ['@resvg/resvg-js']
export default defineConfig({
plugins: [sveltekit()],
test: {
include: ['src/**/*.{test,spec}.{js,ts}']
}
};
export default config;
});