forked from mirror/crumbs-original
Compare commits
@@ -90,6 +90,13 @@ jobs:
|
|||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
- name: Make package public
|
||||||
|
run: |
|
||||||
|
gh api orgs/${{ github.repository_owner }}/packages/container/crumbs -X PATCH \
|
||||||
|
-f visibility=public
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Create GitHub Release
|
- name: Create GitHub Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -50,6 +50,13 @@ jobs:
|
|||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
- name: Make package public
|
||||||
|
run: |
|
||||||
|
gh api orgs/${{ github.repository_owner }}/packages/container/crumbs -X PATCH \
|
||||||
|
-f visibility=public
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Create GitHub Release
|
- name: Create GitHub Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
crumbs:
|
crumbs:
|
||||||
image: ghcr.io/bretzel-app/crumbs:0.21.2
|
image: ghcr.io/bretzel-app/crumbs:0.22.0
|
||||||
container_name: crumbs
|
container_name: crumbs
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
|
|||||||
+5
-2
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "crumbs",
|
"name": "crumbs",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.21.3",
|
"version": "0.22.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"author": "Bretzel (https://bretzel.app)",
|
"author": "Bretzel (https://bretzel.app)",
|
||||||
@@ -12,7 +12,8 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
"build": "vite build",
|
"build": "npx tsx scripts/generate-openapi.ts && vite build",
|
||||||
|
"openapi": "npx tsx scripts/generate-openapi.ts",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"prepare": "svelte-kit sync || echo ''",
|
"prepare": "svelte-kit sync || echo ''",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
@@ -84,7 +85,9 @@
|
|||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vite": "^7.3.1",
|
"vite": "^7.3.1",
|
||||||
"vite-plugin-istanbul": "^7.2.1",
|
"vite-plugin-istanbul": "^7.2.1",
|
||||||
|
"vite-plugin-pwa": "^1.2.0",
|
||||||
"vitest": "^3.2.4",
|
"vitest": "^3.2.4",
|
||||||
|
"workbox-window": "^7.4.0",
|
||||||
"yaml": "^2.8.2"
|
"yaml": "^2.8.2"
|
||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ export default defineConfig({
|
|||||||
use: {
|
use: {
|
||||||
baseURL: 'http://localhost:4173',
|
baseURL: 'http://localhost:4173',
|
||||||
trace: 'on-first-retry',
|
trace: 'on-first-retry',
|
||||||
screenshot: 'only-on-failure'
|
screenshot: 'only-on-failure',
|
||||||
|
serviceWorkers: 'block'
|
||||||
},
|
},
|
||||||
projects: [
|
projects: [
|
||||||
{
|
{
|
||||||
|
|||||||
Generated
+6
@@ -165,9 +165,15 @@ importers:
|
|||||||
vite-plugin-istanbul:
|
vite-plugin-istanbul:
|
||||||
specifier: ^7.2.1
|
specifier: ^7.2.1
|
||||||
version: 7.2.1(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))
|
version: 7.2.1(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))
|
||||||
|
vite-plugin-pwa:
|
||||||
|
specifier: ^1.2.0
|
||||||
|
version: 1.2.0(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(workbox-build@7.4.0)(workbox-window@7.4.0)
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.4
|
||||||
version: 3.2.4(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
|
version: 3.2.4(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
|
||||||
|
workbox-window:
|
||||||
|
specifier: ^7.4.0
|
||||||
|
version: 7.4.0
|
||||||
yaml:
|
yaml:
|
||||||
specifier: ^2.8.2
|
specifier: ^2.8.2
|
||||||
version: 2.8.2
|
version: 2.8.2
|
||||||
|
|||||||
@@ -0,0 +1,147 @@
|
|||||||
|
/**
|
||||||
|
* Auto-generates an OpenAPI spec from the SvelteKit route tree.
|
||||||
|
*
|
||||||
|
* Scans all +server.ts files under src/routes/api/ for exported HTTP methods and
|
||||||
|
* builds a minimal OpenAPI 3.1 spec at static/.well-known/openapi.json.
|
||||||
|
*
|
||||||
|
* Usage: npx tsx scripts/generate-openapi.ts
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { readFileSync, writeFileSync, mkdirSync, readdirSync, statSync } from 'fs';
|
||||||
|
import { resolve, relative, dirname, join } from 'path';
|
||||||
|
|
||||||
|
const ROOT = process.cwd();
|
||||||
|
const ROUTES_DIR = resolve(ROOT, 'src/routes/api');
|
||||||
|
const OUTPUT = resolve(ROOT, 'static/api/openapi.json');
|
||||||
|
|
||||||
|
const pkg = JSON.parse(readFileSync(resolve(ROOT, 'package.json'), 'utf-8'));
|
||||||
|
|
||||||
|
function walkDir(dir: string): string[] {
|
||||||
|
const results: string[] = [];
|
||||||
|
for (const entry of readdirSync(dir)) {
|
||||||
|
const full = join(dir, entry);
|
||||||
|
if (statSync(full).isDirectory()) {
|
||||||
|
results.push(...walkDir(full));
|
||||||
|
} else if (entry === '+server.ts') {
|
||||||
|
results.push(full);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'] as const;
|
||||||
|
const METHOD_RE = new RegExp(`export\\s+const\\s+(${HTTP_METHODS.join('|')})`, 'g');
|
||||||
|
|
||||||
|
function svelteKitPathToOpenAPI(filePath: string): string {
|
||||||
|
const rel = relative(ROUTES_DIR, dirname(filePath));
|
||||||
|
const segments = rel === '' ? [] : rel.split('/');
|
||||||
|
const apiPath =
|
||||||
|
'/api/' +
|
||||||
|
segments
|
||||||
|
.map((s) => {
|
||||||
|
const match = s.match(/^\[(.+)\]$/);
|
||||||
|
return match ? `{${match[1]}}` : s;
|
||||||
|
})
|
||||||
|
.join('/');
|
||||||
|
return apiPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractMethods(filePath: string): string[] {
|
||||||
|
const content = readFileSync(filePath, 'utf-8');
|
||||||
|
const methods: string[] = [];
|
||||||
|
let match;
|
||||||
|
while ((match = METHOD_RE.exec(content)) !== null) {
|
||||||
|
methods.push(match[1].toLowerCase());
|
||||||
|
}
|
||||||
|
METHOD_RE.lastIndex = 0;
|
||||||
|
return methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inferTag(path: string): string {
|
||||||
|
const first = path.replace('/api/', '').split('/')[0];
|
||||||
|
return first.charAt(0).toUpperCase() + first.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractPathParams(path: string) {
|
||||||
|
const params: { name: string; in: string; required: boolean; schema: { type: string } }[] = [];
|
||||||
|
const re = /\{(\w+)\}/g;
|
||||||
|
let match;
|
||||||
|
while ((match = re.exec(path)) !== null) {
|
||||||
|
params.push({ name: match[1], in: 'path', required: true, schema: { type: 'string' } });
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
const files = walkDir(ROUTES_DIR);
|
||||||
|
const paths: Record<string, Record<string, unknown>> = {};
|
||||||
|
|
||||||
|
for (const fullPath of files) {
|
||||||
|
const apiPath = svelteKitPathToOpenAPI(fullPath);
|
||||||
|
const methods = extractMethods(fullPath);
|
||||||
|
|
||||||
|
if (methods.length === 0) continue;
|
||||||
|
|
||||||
|
const pathParams = extractPathParams(apiPath);
|
||||||
|
const pathEntry: Record<string, unknown> = {};
|
||||||
|
|
||||||
|
if (pathParams.length > 0) {
|
||||||
|
pathEntry.parameters = pathParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const method of methods) {
|
||||||
|
const operation: Record<string, unknown> = {
|
||||||
|
tags: [inferTag(apiPath)],
|
||||||
|
responses: {
|
||||||
|
'200': { description: 'Success' }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (['post', 'put', 'patch'].includes(method)) {
|
||||||
|
operation.requestBody = {
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
schema: { type: 'object' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pathEntry[method] = operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
paths[apiPath] = pathEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortedPaths: Record<string, Record<string, unknown>> = {};
|
||||||
|
for (const key of Object.keys(paths).sort()) {
|
||||||
|
sortedPaths[key] = paths[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
const spec = {
|
||||||
|
openapi: '3.1.0',
|
||||||
|
info: {
|
||||||
|
title: `${pkg.name.charAt(0).toUpperCase() + pkg.name.slice(1)} API`,
|
||||||
|
description: `Auto-generated API spec for ${pkg.name}`,
|
||||||
|
version: pkg.version,
|
||||||
|
contact: {
|
||||||
|
name: 'Bretzel',
|
||||||
|
url: 'https://bretzel.app'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
servers: [{ url: '/', description: 'Current instance' }],
|
||||||
|
security: [{ sessionCookie: [] }],
|
||||||
|
paths: sortedPaths,
|
||||||
|
components: {
|
||||||
|
securitySchemes: {
|
||||||
|
sessionCookie: {
|
||||||
|
type: 'apiKey',
|
||||||
|
in: 'cookie',
|
||||||
|
name: 'session'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mkdirSync(dirname(OUTPUT), { recursive: true });
|
||||||
|
writeFileSync(OUTPUT, JSON.stringify(spec, null, 2) + '\n');
|
||||||
|
console.log(`Generated ${relative(ROOT, OUTPUT)} with ${Object.keys(paths).length} paths`);
|
||||||
Vendored
+3
@@ -1,3 +1,6 @@
|
|||||||
|
/// <reference types="vite-plugin-pwa/info" />
|
||||||
|
/// <reference types="vite-plugin-pwa/vanillajs" />
|
||||||
|
|
||||||
// See https://svelte.dev/docs/kit/types#app.d.ts
|
// See https://svelte.dev/docs/kit/types#app.d.ts
|
||||||
// for information about these interfaces
|
// for information about these interfaces
|
||||||
declare global {
|
declare global {
|
||||||
|
|||||||
@@ -35,8 +35,8 @@
|
|||||||
href="https://bretzel.app"
|
href="https://bretzel.app"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="text-[var(--primary)] underline hover:text-[var(--primary-hover)]">Bretzel</a
|
class="text-[var(--primary)] underline hover:text-[var(--primary-hover)]">bretzel.app</a
|
||||||
> family of apps.
|
> universe.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,30 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import '../app.css';
|
import '../app.css';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { pwaInfo } from 'virtual:pwa-info';
|
||||||
|
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
if (pwaInfo) {
|
||||||
|
const { registerSW } = await import('virtual:pwa-register');
|
||||||
|
registerSW({
|
||||||
|
immediate: true,
|
||||||
|
onRegistered(r: ServiceWorkerRegistration | undefined) {
|
||||||
|
console.log('SW Registered:', r);
|
||||||
|
},
|
||||||
|
onRegisterError(error: Error) {
|
||||||
|
console.log('SW registration error', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const webManifest = $derived(pwaInfo ? pwaInfo.webManifest.linkTag : '');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
{@html webManifest}
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
{@render children()}
|
{@render children()}
|
||||||
|
|||||||
@@ -0,0 +1,796 @@
|
|||||||
|
{
|
||||||
|
"openapi": "3.1.0",
|
||||||
|
"info": {
|
||||||
|
"title": "Crumbs API",
|
||||||
|
"description": "Auto-generated API spec for crumbs",
|
||||||
|
"version": "0.21.9",
|
||||||
|
"contact": {
|
||||||
|
"name": "Bretzel",
|
||||||
|
"url": "https://bretzel.app"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"url": "/",
|
||||||
|
"description": "Current instance"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"sessionCookie": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"/api/admin/users": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Admin"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"Admin"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/admin/users/{id}": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"patch": {
|
||||||
|
"tags": [
|
||||||
|
"Admin"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"tags": [
|
||||||
|
"Admin"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/auth/account": {
|
||||||
|
"delete": {
|
||||||
|
"tags": [
|
||||||
|
"Auth"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/auth/login": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"Auth"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/auth/logout": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"Auth"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/auth/oauth/{provider}": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "provider",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Auth"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/auth/oauth/{provider}/callback": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "provider",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Auth"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/auth/password": {
|
||||||
|
"put": {
|
||||||
|
"tags": [
|
||||||
|
"Auth"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/auth/profile": {
|
||||||
|
"put": {
|
||||||
|
"tags": [
|
||||||
|
"Auth"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/auth/sessions": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Auth"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"tags": [
|
||||||
|
"Auth"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/auth/setup": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"Auth"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/mcp": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"Mcp"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Mcp"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"tags": [
|
||||||
|
"Mcp"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/notes": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Notes"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"Notes"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/notes/reorder": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"Notes"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/notes/{id}": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Notes"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patch": {
|
||||||
|
"tags": [
|
||||||
|
"Notes"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"tags": [
|
||||||
|
"Notes"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/notes/{id}/attachments": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Notes"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"Notes"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patch": {
|
||||||
|
"tags": [
|
||||||
|
"Notes"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"tags": [
|
||||||
|
"Notes"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/notes/{id}/collaborators": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Notes"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"Notes"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"tags": [
|
||||||
|
"Notes"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/notes/{id}/versions": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Notes"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/notes/{id}/versions/{versionId}": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "versionId",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Notes"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/notes/{id}/versions/{versionId}/restore": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "versionId",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"Notes"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/preferences": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Preferences"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"tags": [
|
||||||
|
"Preferences"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/search": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Search"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/settings/api-keys": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Settings"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"Settings"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/settings/api-keys/{id}": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"delete": {
|
||||||
|
"tags": [
|
||||||
|
"Settings"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/sync": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"Sync"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Sync"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/tags": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Tags"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/users/search": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Users"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"securitySchemes": {
|
||||||
|
"sessionCookie": {
|
||||||
|
"type": "apiKey",
|
||||||
|
"in": "cookie",
|
||||||
|
"name": "session"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 54 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 299 KiB |
+4
-1
@@ -5,7 +5,10 @@ const config = {
|
|||||||
kit: {
|
kit: {
|
||||||
adapter: adapter({
|
adapter: adapter({
|
||||||
out: 'build'
|
out: 'build'
|
||||||
})
|
}),
|
||||||
|
serviceWorker: {
|
||||||
|
register: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+8
-4
@@ -23,6 +23,8 @@ export default defineConfig({
|
|||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
SvelteKitPWA({
|
SvelteKitPWA({
|
||||||
|
scope: '/',
|
||||||
|
buildBase: '/',
|
||||||
registerType: 'autoUpdate',
|
registerType: 'autoUpdate',
|
||||||
manifest: {
|
manifest: {
|
||||||
name: 'Crumbs by Bretzel',
|
name: 'Crumbs by Bretzel',
|
||||||
@@ -34,8 +36,7 @@ export default defineConfig({
|
|||||||
theme_color: '#C8860A',
|
theme_color: '#C8860A',
|
||||||
icons: [
|
icons: [
|
||||||
{ src: 'pwa-192x192.png', sizes: '192x192', type: 'image/png' },
|
{ src: 'pwa-192x192.png', sizes: '192x192', type: 'image/png' },
|
||||||
{ src: 'pwa-512x512.png', sizes: '512x512', type: 'image/png' },
|
{ src: 'pwa-512x512.png', sizes: '512x512', type: 'image/png' }
|
||||||
{ src: 'pwa-512x512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
workbox: {
|
workbox: {
|
||||||
@@ -52,7 +53,9 @@ export default defineConfig({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
urlPattern: /\/api\/notes\/.*\/attachments\?attachmentId=/,
|
urlPattern: ({ request, url }) =>
|
||||||
|
request.method === 'GET' &&
|
||||||
|
/\/api\/notes\/.*\/attachments\?attachmentId=/.test(url.href),
|
||||||
handler: 'CacheFirst',
|
handler: 'CacheFirst',
|
||||||
options: {
|
options: {
|
||||||
cacheName: 'attachment-cache',
|
cacheName: 'attachment-cache',
|
||||||
@@ -60,7 +63,8 @@ export default defineConfig({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
urlPattern: /^https?:\/\/.*\/api\//,
|
urlPattern: ({ request, url }) =>
|
||||||
|
request.method === 'GET' && /\/api\//.test(url.pathname),
|
||||||
handler: 'NetworkFirst',
|
handler: 'NetworkFirst',
|
||||||
options: {
|
options: {
|
||||||
cacheName: 'api-cache',
|
cacheName: 'api-cache',
|
||||||
|
|||||||
+1
-1
@@ -280,7 +280,7 @@
|
|||||||
<li><a href="https://github.com/bretzel-app/crumbs/blob/main/docs/DEPLOYMENT.md" target="_blank" rel="noopener">Docs</a></li>
|
<li><a href="https://github.com/bretzel-app/crumbs/blob/main/docs/DEPLOYMENT.md" target="_blank" rel="noopener">Docs</a></li>
|
||||||
<li><a href="https://github.com/bretzel-app/crumbs/blob/main/LICENSE" target="_blank" rel="noopener">License</a></li>
|
<li><a href="https://github.com/bretzel-app/crumbs/blob/main/LICENSE" target="_blank" rel="noopener">License</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<span class="footer-version">v0.21.3</span>
|
<span class="footer-version">v0.22.1</span>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user