mirror of
https://github.com/nestriness/nestri.git
synced 2025-12-12 08:45:38 +02:00
remove old config
This commit is contained in:
25
README.md
25
README.md
@@ -1,7 +1,32 @@
|
||||
<p align="center">
|
||||
<<<<<<< HEAD
|
||||
<a href="https://nestri.io">
|
||||
<picture>
|
||||
<source srcset="packages/www/public/" />
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
=======
|
||||
<a href="https://nestri.io">
|
||||
<picture>
|
||||
<source srcset="packages/web/public/logo.white.svg" media="(prefers-color-scheme: dark)">
|
||||
<source srcset="packages/web/public/logo.black.svg" media="(prefers-color-scheme: light)">
|
||||
<img src="packages/web/public/logo.black.svg" alt="Nestri logo">
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
<p align="center">Deploy and stream games/apps in the cloud. Use our GPUs or bring your own.</p>
|
||||
<p align="center">
|
||||
<a href="https://discord.com/invite/Y6etn3qKZ3"><img alt="Discord" src="https://img.shields.io/discord/1080111004698021909?style=flat-square&label=discord" /></a>
|
||||
<a href="https://github.com/nestrilabs/nestri/blob/main/LICENSE"><img alt="Nestri License" src="https://img.shields.io/github/license/nestriness/nestri?style=flat-square" /></a>
|
||||
<a href="https://github.com/nestrilabs/nestri/actions/workflows/runner.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/nestrilabs/nestri/runner.yml?style=flat-square&branch=main" /></a>
|
||||
<!-- <a href="https://nestri.io" style="text-decoration: none;">
|
||||
<img src="https://img.shields.io/badge/Start%20Playing%20Now-For%20$1/hour-brightgreen?style=flat-square" alt="Umami Demo" />
|
||||
</a> -->
|
||||
</p>
|
||||
|
||||
<!-- TODO: Add a link to the demo app when it's ready -->
|
||||
<!-- TODO: Add a link to install for self-hosters -->
|
||||
<!-- TODO: Add a CTA for hosted option -->
|
||||
<!-- TODO: Add feature imagery like Lobechat -->
|
||||
>>>>>>> main
|
||||
|
||||
120
infra-old/api.ts
120
infra-old/api.ts
@@ -1,120 +0,0 @@
|
||||
import { bus } from "./bus";
|
||||
import { vpc } from "./vpc";
|
||||
import { auth } from "./auth";
|
||||
import { domain } from "./dns";
|
||||
import { secret } from "./secret";
|
||||
import { postgres } from "./postgres";
|
||||
|
||||
const urls = new sst.Linkable("Urls", {
|
||||
properties: {
|
||||
api: `https://api.${domain}`,
|
||||
auth: `https://auth.${domain}`,
|
||||
site: $dev ? "http://localhost:3000" : `https://console.${domain}`,
|
||||
}
|
||||
})
|
||||
|
||||
const apiFn = new sst.aws.Function("ApiFn", {
|
||||
vpc,
|
||||
handler: "packages/functions/src/api/index.handler",
|
||||
streaming: !$dev,
|
||||
link: [
|
||||
bus,
|
||||
urls,
|
||||
auth,
|
||||
postgres,
|
||||
secret.SteamApiKey,
|
||||
secret.PolarSecret,
|
||||
secret.PolarWebhookSecret,
|
||||
secret.NestriFamilyMonthly,
|
||||
secret.NestriFamilyYearly,
|
||||
secret.NestriFreeMonthly,
|
||||
secret.NestriProMonthly,
|
||||
secret.NestriProYearly,
|
||||
],
|
||||
url: true,
|
||||
});
|
||||
|
||||
const provider = new aws.Provider("UsEast1", { region: "us-east-1" });
|
||||
|
||||
const webAcl = new aws.wafv2.WebAcl(
|
||||
"ApiWaf",
|
||||
{
|
||||
scope: "CLOUDFRONT",
|
||||
defaultAction: {
|
||||
allow: {},
|
||||
},
|
||||
visibilityConfig: {
|
||||
cloudwatchMetricsEnabled: true,
|
||||
metricName: "api-rate-limit-metric",
|
||||
sampledRequestsEnabled: true,
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
name: "rate-limit-rule",
|
||||
priority: 1,
|
||||
action: {
|
||||
block: {
|
||||
customResponse: {
|
||||
responseCode: 429,
|
||||
customResponseBodyKey: "rate-limit-response",
|
||||
},
|
||||
},
|
||||
},
|
||||
statement: {
|
||||
rateBasedStatement: {
|
||||
limit: 2 * 60, // 2 rps per authorization header
|
||||
evaluationWindowSec: 60,
|
||||
aggregateKeyType: "CUSTOM_KEYS",
|
||||
customKeys: [
|
||||
{
|
||||
header: {
|
||||
name: "Authorization",
|
||||
textTransformations: [{ priority: 0, type: "NONE" }],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
visibilityConfig: {
|
||||
cloudwatchMetricsEnabled: true,
|
||||
metricName: "rate-limit-rule-metric",
|
||||
sampledRequestsEnabled: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
customResponseBodies: [
|
||||
{
|
||||
key: "rate-limit-response",
|
||||
content: JSON.stringify({
|
||||
type: "rate_limit",
|
||||
code: "too_many_requests",
|
||||
message: "Rate limit exceeded. Please try again later.",
|
||||
}),
|
||||
contentType: "APPLICATION_JSON",
|
||||
},
|
||||
],
|
||||
},
|
||||
{ provider },
|
||||
);
|
||||
|
||||
export const api = new sst.aws.Router("Api", {
|
||||
routes: {
|
||||
"/*": apiFn.url,
|
||||
},
|
||||
domain: {
|
||||
name: "api." + domain,
|
||||
dns: sst.cloudflare.dns(),
|
||||
},
|
||||
transform: {
|
||||
cdn(args) {
|
||||
if (!args.transform) {
|
||||
args.transform = {
|
||||
distribution: {},
|
||||
};
|
||||
}
|
||||
args.transform!.distribution = {
|
||||
webAclId: webAcl.arn,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,32 +0,0 @@
|
||||
import { bus } from "./bus";
|
||||
import { vpc } from "./vpc";
|
||||
import { domain } from "./dns";
|
||||
import { secret } from "./secret";
|
||||
import { postgres } from "./postgres";
|
||||
|
||||
export const auth = new sst.aws.Auth("Auth", {
|
||||
authorizer: {
|
||||
vpc,
|
||||
link: [
|
||||
bus,
|
||||
postgres,
|
||||
secret.PolarSecret,
|
||||
secret.GithubClientID,
|
||||
secret.DiscordClientID,
|
||||
secret.GithubClientSecret,
|
||||
secret.DiscordClientSecret,
|
||||
],
|
||||
permissions: [
|
||||
{
|
||||
actions: ["ses:SendEmail"],
|
||||
resources: ["*"],
|
||||
},
|
||||
],
|
||||
handler: "packages/functions/src/auth/index.handler",
|
||||
},
|
||||
domain: {
|
||||
name: "auth." + domain,
|
||||
dns: sst.cloudflare.dns(),
|
||||
},
|
||||
forceUpgrade: "v2",
|
||||
});
|
||||
@@ -1,70 +0,0 @@
|
||||
import { vpc } from "./vpc";
|
||||
import { secret } from "./secret";
|
||||
import { storage } from "./storage";
|
||||
import { postgres } from "./postgres";
|
||||
|
||||
export const dlq = new sst.aws.Queue("Dlq");
|
||||
|
||||
export const retryQueue = new sst.aws.Queue("RetryQueue");
|
||||
|
||||
export const bus = new sst.aws.Bus("Bus");
|
||||
|
||||
export const eventSub = bus.subscribe("Event", {
|
||||
vpc,
|
||||
handler: "packages/functions/src/events/index.handler",
|
||||
link: [
|
||||
// email,
|
||||
bus,
|
||||
storage,
|
||||
postgres,
|
||||
retryQueue,
|
||||
secret.PolarSecret,
|
||||
secret.SteamApiKey
|
||||
],
|
||||
environment: {
|
||||
RETRIES: "2",
|
||||
},
|
||||
memory: "3002 MB",// For faster processing of large(r) images
|
||||
timeout: "10 minutes",
|
||||
});
|
||||
|
||||
new aws.lambda.FunctionEventInvokeConfig("EventConfig", {
|
||||
functionName: $resolve([eventSub.nodes.function.name]).apply(
|
||||
([name]) => name,
|
||||
),
|
||||
maximumRetryAttempts: 1,
|
||||
destinationConfig: {
|
||||
onFailure: {
|
||||
destination: retryQueue.arn,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
retryQueue.subscribe({
|
||||
vpc,
|
||||
handler: "packages/functions/src/queues/retry.handler",
|
||||
timeout: "30 seconds",
|
||||
environment: {
|
||||
RETRIER_QUEUE_URL: retryQueue.url,
|
||||
},
|
||||
link: [
|
||||
dlq,
|
||||
retryQueue,
|
||||
eventSub.nodes.function,
|
||||
],
|
||||
permissions: [
|
||||
{
|
||||
actions: ["lambda:GetFunction", "lambda:InvokeFunction"],
|
||||
resources: [
|
||||
$interpolate`arn:aws:lambda:${aws.getRegionOutput().name}:${aws.getCallerIdentityOutput().accountId}:function:*`,
|
||||
],
|
||||
},
|
||||
],
|
||||
transform: {
|
||||
function: {
|
||||
deadLetterConfig: {
|
||||
targetArn: dlq.arn,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,6 +0,0 @@
|
||||
import { vpc } from "./vpc";
|
||||
|
||||
export const cluster = new sst.aws.Cluster("Cluster", {
|
||||
vpc,
|
||||
forceUpgrade: "v2"
|
||||
});
|
||||
@@ -1,5 +0,0 @@
|
||||
export const domain =
|
||||
{
|
||||
production: "nestri.io",
|
||||
dev: "dev.nestri.io",
|
||||
}[$app.stage] || $app.stage + ".dev.nestri.io";
|
||||
@@ -1,6 +0,0 @@
|
||||
import { domain } from "./dns";
|
||||
|
||||
export const email = new sst.aws.Email("Email",{
|
||||
sender: domain,
|
||||
dns: sst.cloudflare.dns(),
|
||||
})
|
||||
@@ -1,67 +0,0 @@
|
||||
import { vpc } from "./vpc";
|
||||
import { isPermanentStage } from "./stage";
|
||||
|
||||
export const postgres = !isPermanentStage
|
||||
? sst.aws.Aurora.get("Database", "nestri-dev-databasecluster-vmeeabek")
|
||||
: new sst.aws.Aurora("Database", {
|
||||
vpc,
|
||||
engine: "postgres",
|
||||
scaling: {
|
||||
min: "0 ACU",
|
||||
max: "1 ACU",
|
||||
},
|
||||
transform: {
|
||||
clusterParameterGroup: {
|
||||
parameters: [
|
||||
{
|
||||
name: "rds.logical_replication",
|
||||
value: "1",
|
||||
applyMethod: "pending-reboot",
|
||||
},
|
||||
{
|
||||
name: "max_slot_wal_keep_size",
|
||||
value: "10240",
|
||||
applyMethod: "pending-reboot",
|
||||
},
|
||||
{
|
||||
name: "rds.force_ssl",
|
||||
value: "0",
|
||||
applyMethod: "pending-reboot",
|
||||
},
|
||||
{
|
||||
name: "max_connections",
|
||||
value: "1000",
|
||||
applyMethod: "pending-reboot",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
new sst.x.DevCommand("Studio", {
|
||||
link: [postgres],
|
||||
dev: {
|
||||
command: "bun db:dev studio",
|
||||
directory: "packages/core",
|
||||
autostart: true,
|
||||
},
|
||||
});
|
||||
|
||||
// const migrator = new sst.aws.Function("DatabaseMigrator", {
|
||||
// handler: "packages/functions/src/migrator.handler",
|
||||
// link: [postgres],
|
||||
// copyFiles: [
|
||||
// {
|
||||
// from: "packages/core/migrations",
|
||||
// to: "./migrations",
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// if (!$dev) {
|
||||
// new aws.lambda.Invocation("DatabaseMigratorInvocation", {
|
||||
// input: Date.now().toString(),
|
||||
// functionName: migrator.name,
|
||||
// });
|
||||
// }
|
||||
@@ -1,9 +0,0 @@
|
||||
// import { auth } from "./auth";
|
||||
import { postgres } from "./postgres";
|
||||
|
||||
export const device = new sst.aws.Realtime("Realtime", {
|
||||
authorizer: {
|
||||
link: [ postgres],
|
||||
handler: "packages/functions/src/realtime/authorizer.handler"
|
||||
}
|
||||
})
|
||||
@@ -1,18 +0,0 @@
|
||||
export const secret = {
|
||||
PolarSecret: new sst.Secret("PolarSecret", process.env.POLAR_API_KEY),
|
||||
SteamApiKey: new sst.Secret("SteamApiKey"),
|
||||
GithubClientID: new sst.Secret("GithubClientID"),
|
||||
DiscordClientID: new sst.Secret("DiscordClientID"),
|
||||
PolarWebhookSecret: new sst.Secret("PolarWebhookSecret"),
|
||||
GithubClientSecret: new sst.Secret("GithubClientSecret"),
|
||||
DiscordClientSecret: new sst.Secret("DiscordClientSecret"),
|
||||
|
||||
// Pricing
|
||||
NestriFreeMonthly: new sst.Secret("NestriFreeMonthly"),
|
||||
NestriProMonthly: new sst.Secret("NestriProMonthly"),
|
||||
NestriProYearly: new sst.Secret("NestriProYearly"),
|
||||
NestriFamilyMonthly: new sst.Secret("NestriFamilyMonthly"),
|
||||
NestriFamilyYearly: new sst.Secret("NestriFamilyYearly"),
|
||||
};
|
||||
|
||||
export const allSecrets = Object.values(secret);
|
||||
@@ -1,2 +0,0 @@
|
||||
export const isPermanentStage =
|
||||
$app.stage === "production" || $app.stage === "dev";
|
||||
@@ -1 +0,0 @@
|
||||
export const storage = new sst.aws.Bucket("Storage");
|
||||
@@ -1,11 +0,0 @@
|
||||
import { isPermanentStage } from "./stage";
|
||||
|
||||
export const vpc = isPermanentStage
|
||||
? new sst.aws.Vpc("VPC", {
|
||||
az: 2,
|
||||
// For lambdas to work in this VPC
|
||||
nat: "ec2",
|
||||
// For SST tunnel to work
|
||||
bastion: true,
|
||||
})
|
||||
: sst.aws.Vpc.get("VPC", "vpc-0beb1cdc21a725748");
|
||||
@@ -1,23 +0,0 @@
|
||||
// This is the website part where people play and connect
|
||||
import { api } from "./api";
|
||||
import { auth } from "./auth";
|
||||
import { zero } from "./zero";
|
||||
import { domain } from "./dns";
|
||||
|
||||
new sst.aws.StaticSite("Web", {
|
||||
path: "packages/www",
|
||||
build: {
|
||||
output: "./dist",
|
||||
command: "bun run build",
|
||||
},
|
||||
domain: {
|
||||
dns: sst.cloudflare.dns(),
|
||||
name: "console." + domain
|
||||
},
|
||||
environment: {
|
||||
VITE_API_URL: api.url,
|
||||
VITE_STAGE: $app.stage,
|
||||
VITE_AUTH_URL: auth.url,
|
||||
VITE_ZERO_URL: zero.url,
|
||||
},
|
||||
})
|
||||
@@ -1,186 +0,0 @@
|
||||
import { auth } from "./auth";
|
||||
import { domain } from "./dns";
|
||||
import { readFileSync } from "fs";
|
||||
import { cluster } from "./cluster";
|
||||
import { storage } from "./storage";
|
||||
import { postgres } from "./postgres";
|
||||
|
||||
const connectionString = $interpolate`postgresql://${postgres.username}:${postgres.password}@${postgres.host}:${postgres.port}/${postgres.database}`;
|
||||
|
||||
const tag = $dev
|
||||
? `latest`
|
||||
: JSON.parse(
|
||||
readFileSync("./node_modules/@rocicorp/zero/package.json").toString(),
|
||||
).version.replace("+", "-");
|
||||
|
||||
const zeroEnv = {
|
||||
FORCE: "1",
|
||||
NO_COLOR: "1",
|
||||
ZERO_LOG_LEVEL: "info",
|
||||
ZERO_LITESTREAM_LOG_LEVEL: "info",
|
||||
ZERO_UPSTREAM_DB: connectionString,
|
||||
ZERO_IMAGE_URL: `rocicorp/zero:${tag}`,
|
||||
ZERO_CVR_DB: connectionString,
|
||||
ZERO_CHANGE_DB: connectionString,
|
||||
ZERO_REPLICA_FILE: "/tmp/nestri.db",
|
||||
ZERO_LITESTREAM_RESTORE_PARALLELISM: "64",
|
||||
ZERO_APP_ID: $app.stage,
|
||||
ZERO_AUTH_JWKS_URL: $interpolate`${auth.url}/.well-known/jwks.json`,
|
||||
ZERO_INITIAL_SYNC_ROW_BATCH_SIZE: "30000",
|
||||
NODE_OPTIONS: "--max-old-space-size=8192",
|
||||
...($dev
|
||||
? {
|
||||
}
|
||||
: {
|
||||
ZERO_LITESTREAM_BACKUP_URL: $interpolate`s3://${storage.name}/zero/0`,
|
||||
}),
|
||||
};
|
||||
|
||||
// Replication Manager Service
|
||||
const replicationManager = !$dev
|
||||
? new sst.aws.Service(`ZeroReplication`, {
|
||||
cluster,
|
||||
wait: true,
|
||||
cpu: "0.5 vCPU",
|
||||
memory: "1 GB",
|
||||
capacity: "spot",
|
||||
architecture: "arm64",
|
||||
image: zeroEnv.ZERO_IMAGE_URL,
|
||||
link: [storage, postgres],
|
||||
health: {
|
||||
command: ["CMD-SHELL", "curl -f http://localhost:4849/ || exit 1"],
|
||||
interval: "5 seconds",
|
||||
retries: 3,
|
||||
startPeriod: "300 seconds",
|
||||
},
|
||||
environment: {
|
||||
...zeroEnv,
|
||||
ZERO_CHANGE_MAX_CONNS: "3",
|
||||
ZERO_NUM_SYNC_WORKERS: "0",
|
||||
},
|
||||
logging: {
|
||||
retention: "1 month",
|
||||
},
|
||||
loadBalancer: {
|
||||
public: false,
|
||||
ports: [
|
||||
{
|
||||
listen: "80/http",
|
||||
forward: "4849/http",
|
||||
},
|
||||
],
|
||||
},
|
||||
transform: {
|
||||
loadBalancer: {
|
||||
idleTimeout: 3600,
|
||||
},
|
||||
service: {
|
||||
healthCheckGracePeriodSeconds: 900,
|
||||
},
|
||||
},
|
||||
}) : undefined;
|
||||
|
||||
// Permissions deployment
|
||||
// const permissions = new sst.aws.Function(
|
||||
// "ZeroPermissions",
|
||||
// {
|
||||
// vpc,
|
||||
// link: [postgres],
|
||||
// handler: "packages/functions/src/zero.handler",
|
||||
// // environment: { ["ZERO_UPSTREAM_DB"]: connectionString },
|
||||
// copyFiles: [{
|
||||
// from: "packages/zero/permissions.sql",
|
||||
// to: "./.permissions.sql"
|
||||
// }],
|
||||
// }
|
||||
// );
|
||||
|
||||
// if (replicationManager) {
|
||||
// new aws.lambda.Invocation(
|
||||
// "ZeroPermissionsInvocation",
|
||||
// {
|
||||
// input: Date.now().toString(),
|
||||
// functionName: permissions.name,
|
||||
// },
|
||||
// { dependsOn: replicationManager }
|
||||
// );
|
||||
// // new command.local.Command(
|
||||
// // "ZeroPermission",
|
||||
// // {
|
||||
// // dir: process.cwd() + "/packages/zero",
|
||||
// // environment: {
|
||||
// // ZERO_UPSTREAM_DB: connectionString,
|
||||
// // },
|
||||
// // create: "bun run zero-deploy-permissions",
|
||||
// // triggers: [Date.now()],
|
||||
// // },
|
||||
// // {
|
||||
// // dependsOn: [replicationManager],
|
||||
// // },
|
||||
// // );
|
||||
// }
|
||||
|
||||
export const zero = new sst.aws.Service("Zero", {
|
||||
cluster,
|
||||
image: zeroEnv.ZERO_IMAGE_URL,
|
||||
link: [storage, postgres],
|
||||
architecture: "arm64",
|
||||
cpu: "0.5 vCPU",
|
||||
memory: "1 GB",
|
||||
capacity: "spot",
|
||||
environment: {
|
||||
...zeroEnv,
|
||||
...($dev
|
||||
? {
|
||||
ZERO_NUM_SYNC_WORKERS: "1",
|
||||
}
|
||||
: {
|
||||
ZERO_CHANGE_STREAMER_URI: replicationManager.url.apply((val) =>
|
||||
val.replace("http://", "ws://"),
|
||||
),
|
||||
ZERO_UPSTREAM_MAX_CONNS: "15",
|
||||
ZERO_CVR_MAX_CONNS: "160",
|
||||
}),
|
||||
},
|
||||
health: {
|
||||
retries: 3,
|
||||
command: ["CMD-SHELL", "curl -f http://localhost:4848/ || exit 1"],
|
||||
interval: "5 seconds",
|
||||
startPeriod: "300 seconds",
|
||||
},
|
||||
loadBalancer: {
|
||||
domain: {
|
||||
name: "zero." + domain,
|
||||
dns: sst.cloudflare.dns()
|
||||
},
|
||||
rules: [
|
||||
{ listen: "443/https", forward: "4848/http" },
|
||||
{ listen: "80/http", forward: "4848/http" },
|
||||
],
|
||||
},
|
||||
scaling: {
|
||||
min: 1,
|
||||
max: 4,
|
||||
},
|
||||
logging: {
|
||||
retention: "1 month",
|
||||
},
|
||||
transform: {
|
||||
service: {
|
||||
healthCheckGracePeriodSeconds: 900,
|
||||
},
|
||||
// taskDefinition: {
|
||||
// ephemeralStorage: {
|
||||
// sizeInGib: 200,
|
||||
// },
|
||||
// },
|
||||
loadBalancer: {
|
||||
idleTimeout: 3600,
|
||||
},
|
||||
},
|
||||
dev: {
|
||||
command: "bun dev",
|
||||
directory: "packages/zero",
|
||||
url: "http://localhost:4848",
|
||||
},
|
||||
});
|
||||
1
packages/web/.astro/content-assets.mjs
Normal file
1
packages/web/.astro/content-assets.mjs
Normal file
@@ -0,0 +1 @@
|
||||
export default new Map();
|
||||
1
packages/web/.astro/content-modules.mjs
Normal file
1
packages/web/.astro/content-modules.mjs
Normal file
@@ -0,0 +1 @@
|
||||
export default new Map();
|
||||
1
packages/web/.astro/data-store.json
Normal file
1
packages/web/.astro/data-store.json
Normal file
@@ -0,0 +1 @@
|
||||
[["Map",1,2],"meta::meta",["Map",3,4,5,6],"astro-version","5.11.2","astro-config-digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{},\"compressHTML\":true,\"base\":\"/\",\"trailingSlash\":\"ignore\",\"output\":\"static\",\"scopedStyleStrategy\":\"attribute\",\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astro\",\"serverEntry\":\"entry.mjs\",\"redirects\":true,\"inlineStylesheets\":\"auto\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":4321,\"streaming\":true,\"allowedHosts\":[]},\"redirects\":{},\"image\":{\"endpoint\":{\"route\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"config\":{}},\"domains\":[],\"remotePatterns\":[],\"responsiveStyles\":false},\"devToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":{\"type\":\"shiki\",\"excludeLangs\":[\"math\"]},\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"theme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPlugins\":[],\"rehypePlugins\":[],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":true},\"security\":{\"checkOrigin\":true},\"env\":{\"schema\":{},\"validateSecrets\":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false,\"headingIdCompat\":false,\"preserveScriptOrder\":false,\"liveContentCollections\":false,\"csp\":false},\"legacy\":{\"collections\":false}}"]
|
||||
5
packages/web/.astro/settings.json
Normal file
5
packages/web/.astro/settings.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"_variables": {
|
||||
"lastUpdateCheck": 1752741260450
|
||||
}
|
||||
}
|
||||
1
packages/web/.astro/types.d.ts
vendored
Normal file
1
packages/web/.astro/types.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="astro/client" />
|
||||
65
packages/web/public/logo.black.svg
Normal file
65
packages/web/public/logo.black.svg
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="410"
|
||||
height="50"
|
||||
viewBox="0 0 108.47917 13.229167"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
inkscape:export-filename="logo-black.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
|
||||
sodipodi:docname="logo.black.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:zoom="1.9477379"
|
||||
inkscape:cx="243.35923"
|
||||
inkscape:cy="61.353224"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1046"
|
||||
inkscape:window-x="-11"
|
||||
inkscape:window-y="-11"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" /><defs
|
||||
id="defs1"><linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="paint1"
|
||||
x1="317.5"
|
||||
x2="314.00699"
|
||||
y1="-51.5"
|
||||
y2="126"
|
||||
gradientTransform="matrix(0.06483182,0,0,0.06483182,7.793483,1.7716596)"><stop
|
||||
stop-color="white"
|
||||
id="stop1" /><stop
|
||||
offset="1"
|
||||
stop-opacity="0"
|
||||
id="stop2" /></linearGradient></defs><g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"><path
|
||||
fill="url(#paint1)"
|
||||
pathLength="1"
|
||||
stroke="url(#paint1)"
|
||||
d="m 66.688022,7.9135153 h -8.573986 q -3.000755,0 -3.000755,-2.572126 V 3.1978936 a 3.1280616,3.1280616 0 0 1 0.175245,-1.0930831 q 0.549966,-1.4792191 2.82551,-1.4792191 h 12.432349 v 2.5809064 h -11.58352 q -0.333456,0 -0.40229,0.2702417 a 0.64443619,0.64443619 0 0 0 -0.01774,0.1583869 v 1.2776343 q 0,0.4286286 0.420026,0.4286286 h 8.58259 q 3.000928,0 3.000928,2.572126 v 2.1434957 a 3.1280616,3.1280616 0 0 1 -0.175243,1.09326 q -0.549967,1.479042 -2.825685,1.479042 h -12.43217 v -2.580731 h 11.574741 a 0.61721885,0.61721885 0 0 0 0.169801,-0.02125 q 0.259003,-0.07428 0.259003,-0.4075567 v -1.277454 a 0.61721885,0.61721885 0 0 0 -0.02125,-0.169627 q -0.07428,-0.259178 -0.407558,-0.259178 z M 53.398413,10.065616 v 2.563697 H 40.966062 q -3.000929,0 -3.000929,-2.572302 V 3.1978936 a 3.1280616,3.1280616 0 0 1 0.175419,-1.0930831 q 0.549966,-1.4792191 2.82551,-1.4792191 h 9.43142 q 3.000931,0 3.000931,2.5723022 v 3.0009297 a 3.1303444,3.1303444 0 0 1 -0.176122,1.0955408 q -0.513266,1.3780752 -2.52331,1.4774622 a 6.4805345,6.4805345 0 0 1 -0.301499,0.0077 h -9.002615 l 0.0085,0.857433 q 0,0.4286287 0.4202,0.4372327 z M 24.246719,3.1978936 v 9.4314194 h -3.42956 V 0.6255914 h 12.432352 q 3.000929,0 3.000929,2.5723022 V 12.629313 H 32.820705 V 3.6265222 q 0,-0.4286286 -0.420024,-0.4286286 z m 75.451365,9.4314194 -3.34387,-3.8583647 h -5.23012 V 12.629313 H 87.694359 V 0.6255914 H 100.1267 a 4.3200052,4.3200052 0 0 1 1.18755,0.1489057 q 1.33173,0.3813933 1.68537,1.7406798 a 4.4211483,4.4211483 0 0 1 0.12801,1.1113453 v 2.5723011 a 3.1988267,3.1988267 0 0 1 -0.15154,1.0263568 q -0.33942,1.0033542 -1.43794,1.3564762 a 4.0817218,4.0817218 0 0 1 -0.91417,0.172259 l 3.36108,3.8753977 z M 72.261256,0.5999546 85.979669,0.617163 v 2.5807306 h -5.13583 v 9.4314194 h -3.438161 l -0.0086,-9.4314194 -5.13582,0.00858 z m 32.581244,0.025641 h 3.42956 V 12.629316 H 104.8425 Z M 91.124094,3.2065009 v 2.9923255 h 8.15377 q 0.33365,0 0.4023,-0.2704175 a 0.64443619,0.64443619 0 0 0 0.0179,-0.1583869 V 3.6351296 q 0,-0.4286286 -0.42021,-0.4286286 z m -49.729227,2.9837213 8.145181,0.017211 q 0.343115,-0.00688 0.411597,-0.2772657 a 0.61704326,0.61704326 0 0 0 0.01721,-0.1515397 V 3.6265286 q 0,-0.3334559 -0.270419,-0.4022896 A 0.64443619,0.64443619 0 0 0 49.54005,3.206499 l -7.716551,-0.00858 q -0.42863,0 -0.42863,0.4202002 z"
|
||||
id="path1"
|
||||
style="font-size:12px;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.0438989mm;stroke-linecap:round;stroke-opacity:1" /><path
|
||||
d="M 1.50309,1.4982293 H 15.924554 V 2.2921471 H 1.50309 Z m 0,4.7193972 H 15.924554 V 7.0115422 H 1.50309 Z m 0,4.7193935 h 14.421464 v 0.793917 H 1.50309 Z"
|
||||
id="path1-8"
|
||||
style="font-size:12px;fill:#ff4f01;fill-opacity:1;fill-rule:evenodd;stroke:#ff4f01;stroke-width:2.75789;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:export-filename="logo.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" /></g></svg>
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
65
packages/web/public/logo.white.svg
Normal file
65
packages/web/public/logo.white.svg
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="410"
|
||||
height="50"
|
||||
viewBox="0 0 108.47917 13.229167"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
inkscape:export-filename="logo-black.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
|
||||
sodipodi:docname="logo.white.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:zoom="1.9477379"
|
||||
inkscape:cx="243.35923"
|
||||
inkscape:cy="61.353224"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1046"
|
||||
inkscape:window-x="-11"
|
||||
inkscape:window-y="-11"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" /><defs
|
||||
id="defs1"><linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="paint1"
|
||||
x1="317.5"
|
||||
x2="314.00699"
|
||||
y1="-51.5"
|
||||
y2="126"
|
||||
gradientTransform="matrix(0.06483182,0,0,0.06483182,7.793483,1.7716596)"><stop
|
||||
stop-color="white"
|
||||
id="stop1" /><stop
|
||||
offset="1"
|
||||
stop-opacity="0"
|
||||
id="stop2" /></linearGradient></defs><g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"><path
|
||||
fill="url(#paint1)"
|
||||
pathLength="1"
|
||||
stroke="url(#paint1)"
|
||||
d="m 66.688022,7.9135153 h -8.573986 q -3.000755,0 -3.000755,-2.572126 V 3.1978936 a 3.1280616,3.1280616 0 0 1 0.175245,-1.0930831 q 0.549966,-1.4792191 2.82551,-1.4792191 h 12.432349 v 2.5809064 h -11.58352 q -0.333456,0 -0.40229,0.2702417 a 0.64443619,0.64443619 0 0 0 -0.01774,0.1583869 v 1.2776343 q 0,0.4286286 0.420026,0.4286286 h 8.58259 q 3.000928,0 3.000928,2.572126 v 2.1434957 a 3.1280616,3.1280616 0 0 1 -0.175243,1.09326 q -0.549967,1.479042 -2.825685,1.479042 h -12.43217 v -2.580731 h 11.574741 a 0.61721885,0.61721885 0 0 0 0.169801,-0.02125 q 0.259003,-0.07428 0.259003,-0.4075567 v -1.277454 a 0.61721885,0.61721885 0 0 0 -0.02125,-0.169627 q -0.07428,-0.259178 -0.407558,-0.259178 z M 53.398413,10.065616 v 2.563697 H 40.966062 q -3.000929,0 -3.000929,-2.572302 V 3.1978936 a 3.1280616,3.1280616 0 0 1 0.175419,-1.0930831 q 0.549966,-1.4792191 2.82551,-1.4792191 h 9.43142 q 3.000931,0 3.000931,2.5723022 v 3.0009297 a 3.1303444,3.1303444 0 0 1 -0.176122,1.0955408 q -0.513266,1.3780752 -2.52331,1.4774622 a 6.4805345,6.4805345 0 0 1 -0.301499,0.0077 h -9.002615 l 0.0085,0.857433 q 0,0.4286287 0.4202,0.4372327 z M 24.246719,3.1978936 v 9.4314194 h -3.42956 V 0.6255914 h 12.432352 q 3.000929,0 3.000929,2.5723022 V 12.629313 H 32.820705 V 3.6265222 q 0,-0.4286286 -0.420024,-0.4286286 z m 75.451365,9.4314194 -3.34387,-3.8583647 h -5.23012 V 12.629313 H 87.694359 V 0.6255914 H 100.1267 a 4.3200052,4.3200052 0 0 1 1.18755,0.1489057 q 1.33173,0.3813933 1.68537,1.7406798 a 4.4211483,4.4211483 0 0 1 0.12801,1.1113453 v 2.5723011 a 3.1988267,3.1988267 0 0 1 -0.15154,1.0263568 q -0.33942,1.0033542 -1.43794,1.3564762 a 4.0817218,4.0817218 0 0 1 -0.91417,0.172259 l 3.36108,3.8753977 z M 72.261256,0.5999546 85.979669,0.617163 v 2.5807306 h -5.13583 v 9.4314194 h -3.438161 l -0.0086,-9.4314194 -5.13582,0.00858 z m 32.581244,0.025641 h 3.42956 V 12.629316 H 104.8425 Z M 91.124094,3.2065009 v 2.9923255 h 8.15377 q 0.33365,0 0.4023,-0.2704175 a 0.64443619,0.64443619 0 0 0 0.0179,-0.1583869 V 3.6351296 q 0,-0.4286286 -0.42021,-0.4286286 z m -49.729227,2.9837213 8.145181,0.017211 q 0.343115,-0.00688 0.411597,-0.2772657 a 0.61704326,0.61704326 0 0 0 0.01721,-0.1515397 V 3.6265286 q 0,-0.3334559 -0.270419,-0.4022896 A 0.64443619,0.64443619 0 0 0 49.54005,3.206499 l -7.716551,-0.00858 q -0.42863,0 -0.42863,0.4202002 z"
|
||||
id="path1"
|
||||
style="font-size:12px;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.0438989mm;stroke-linecap:round;stroke-opacity:1" /><path
|
||||
d="M 1.50309,1.4982293 H 15.924554 V 2.2921471 H 1.50309 Z m 0,4.7193972 H 15.924554 V 7.0115422 H 1.50309 Z m 0,4.7193935 h 14.421464 v 0.793917 H 1.50309 Z"
|
||||
id="path1-8"
|
||||
style="font-size:12px;fill:#ff4f01;fill-opacity:1;fill-rule:evenodd;stroke:#ff4f01;stroke-width:2.75789;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:export-filename="logo.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" /></g></svg>
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
Reference in New Issue
Block a user